CluPilotCloud/app/Support/Readiness/BillingChecks.php

85 lines
3.4 KiB
PHP

<?php
namespace App\Support\Readiness;
use App\Models\InvoiceSeries;
use App\Models\PlanPrice;
use App\Services\Secrets\SecretVault;
use App\Support\CompanyProfile;
use App\Support\OperatingMode;
use App\Support\StripeWebhookSecret;
/**
* Was gesetzt sein muss, damit überhaupt ein Auftrag entstehen und ein Beleg
* herauskommen kann.
*/
final class BillingChecks
{
public const GROUP = 'billing';
/** @return array<int, Check> */
public static function all(): array
{
$mode = OperatingMode::current();
return [
new Check(
key: 'billing.stripe_secret',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.billing.stripe_secret', ['mode' => __('readiness.mode.'.$mode->value)]),
breaks: __('readiness.billing.stripe_secret_breaks'),
tab: 'services',
// get() löst den aktiven Modus selbst auf UND ist für Stripe
// strikt — ein Live-Schlüssel zählt im Testbetrieb nicht als
// Nachweis, sonst widerspräche diese Seite der Kassensperre.
satisfied: filled(app(SecretVault::class)->get('stripe.secret')),
),
new Check(
key: 'billing.webhook_secret',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.billing.webhook_secret'),
breaks: __('readiness.billing.webhook_secret_breaks'),
tab: 'env',
// Die Auswahl nach Modus liegt schon in StripeWebhookSecret —
// hier noch einmal per config() nach Modus zu unterscheiden
// wäre eine zweite Stelle, die dieselbe Entscheidung trifft.
satisfied: filled(StripeWebhookSecret::current()),
),
new Check(
key: 'billing.company_details',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.billing.company_details'),
breaks: __('readiness.billing.company_details_breaks'),
tab: 'company',
// Die vorhandene Liste wird gerufen, nicht verdoppelt: zwei
// Quellen für eine Frage ist der Weg, auf dem sie auseinanderlaufen.
satisfied: CompanyProfile::missingForInvoicing() === [],
),
new Check(
key: 'billing.invoice_series',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.billing.invoice_series'),
breaks: __('readiness.billing.invoice_series_breaks'),
tab: 'company',
satisfied: InvoiceSeries::query()
->whereIn('kind', ['invoice', 'credit_note', 'cancellation'])
->distinct()
->count('kind') === 3,
),
new Check(
key: 'billing.catalogue_synced',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.billing.catalogue_synced'),
breaks: __('readiness.billing.catalogue_synced_breaks'),
tab: 'services',
satisfied: PlanPrice::query()->whereNull('stripe_price_id')->doesntExist(),
),
];
}
}