85 lines
3.4 KiB
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(),
|
|
),
|
|
];
|
|
}
|
|
}
|