Demo plan + Payment integrations (Stripe/PayPal/Bank)
Models & migrations: - platform_settings table (key/value JSON store + Cache::remember 5min) - plans: is_demo bool + trial_days int - companies: is_demo bool Plans: - Demo plan seeded (is_demo=true, is_public=false, all features, 14 trial days) - Trial 14-day plan seeded (is_public=true, basic features) - Plan form: is_demo toggle + trial_days field - Plan table: badge 🎬 Demo / 🎁 N zile trial Central panel: - PaymentSettings page (heroicon-credit-card, sort 90) Form sections: General, Date legale, Stripe, PayPal, Transfer bancar Each gateway collapsible, fields hidden until enabled toggle Saves to platform_settings keyed by `payments.{gateway}` - CompanyResource: is_demo toggle + table description Payment flow (PaymentController): - GET /billing — tenant invoices list with Pay button - POST /pay/{sub} — start checkout (stripe/paypal/bank) - GET /pay/{sub}/{success,cancel} - POST /payments/stripe/webhook — mark paid + extend company.active_until - POST /payments/paypal/webhook — same Views: - site/billing.blade.php — invoices list with payment modal (3 methods) - site/bank-instructions — IBAN/BIC/reference for manual transfer - site/checkout-stub — placeholder until composer require stripe-php - site/payment-{success,cancel} Tenant panel: - userMenuItems → "Facturile mele" link to /billing
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Central\Pages;
|
||||
|
||||
use App\Models\Central\PlatformSetting;
|
||||
use Filament\Forms;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Schemas;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class PaymentSettings extends Page
|
||||
{
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-credit-card';
|
||||
|
||||
protected static ?string $navigationLabel = 'Setări plăți';
|
||||
|
||||
protected static ?string $title = 'Integrări de plată';
|
||||
|
||||
protected static ?int $navigationSort = 90;
|
||||
|
||||
protected string $view = 'filament.central.pages.payment-settings';
|
||||
|
||||
public ?array $data = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$s = PlatformSetting::many([
|
||||
'payments.stripe', 'payments.paypal', 'payments.bank',
|
||||
'payments.platform_currency', 'payments.invoice_prefix',
|
||||
'payments.terms', 'payments.company_legal',
|
||||
]);
|
||||
|
||||
$stripe = $s['payments.stripe'] ?? [];
|
||||
$paypal = $s['payments.paypal'] ?? [];
|
||||
$bank = $s['payments.bank'] ?? [];
|
||||
$legal = $s['payments.company_legal'] ?? [];
|
||||
|
||||
$this->form->fill([
|
||||
'platform_currency' => $s['payments.platform_currency'] ?? 'MDL',
|
||||
'invoice_prefix' => $s['payments.invoice_prefix'] ?? 'INV',
|
||||
'terms' => $s['payments.terms'] ?? 'Plata se efectuează în 7 zile de la emitere. Pentru întârzieri se aplică penalități 0.1%/zi.',
|
||||
|
||||
'legal_name' => $legal['name'] ?? null,
|
||||
'legal_idno' => $legal['idno'] ?? null,
|
||||
'legal_address' => $legal['address'] ?? null,
|
||||
'legal_phone' => $legal['phone'] ?? null,
|
||||
'legal_email' => $legal['email'] ?? null,
|
||||
|
||||
'stripe_enabled' => $stripe['enabled'] ?? false,
|
||||
'stripe_mode' => $stripe['mode'] ?? 'test',
|
||||
'stripe_publishable' => $stripe['publishable_key'] ?? null,
|
||||
'stripe_secret' => $stripe['secret_key'] ?? null,
|
||||
'stripe_webhook' => $stripe['webhook_secret'] ?? null,
|
||||
|
||||
'paypal_enabled' => $paypal['enabled'] ?? false,
|
||||
'paypal_mode' => $paypal['mode'] ?? 'sandbox',
|
||||
'paypal_client_id' => $paypal['client_id'] ?? null,
|
||||
'paypal_secret' => $paypal['secret'] ?? null,
|
||||
|
||||
'bank_enabled' => $bank['enabled'] ?? true,
|
||||
'bank_iban' => $bank['iban'] ?? null,
|
||||
'bank_bic' => $bank['bic'] ?? null,
|
||||
'bank_name' => $bank['bank_name'] ?? null,
|
||||
'bank_beneficiary' => $bank['beneficiary'] ?? null,
|
||||
'bank_instructions' => $bank['instructions'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Schemas\Components\Section::make('General')
|
||||
->columns(3)
|
||||
->schema([
|
||||
Forms\Components\Select::make('platform_currency')
|
||||
->label('Monedă platformă')
|
||||
->options(['MDL' => 'MDL', 'EUR' => 'EUR', 'USD' => 'USD'])
|
||||
->required(),
|
||||
Forms\Components\TextInput::make('invoice_prefix')
|
||||
->label('Prefix facturi')->maxLength(10)->default('INV'),
|
||||
Forms\Components\Textarea::make('terms')
|
||||
->label('Termeni de plată')->rows(2)->columnSpanFull(),
|
||||
]),
|
||||
Schemas\Components\Section::make('Date legale (apar pe facturi)')
|
||||
->columns(2)
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('legal_name')->label('Denumire companie')->maxLength(160),
|
||||
Forms\Components\TextInput::make('legal_idno')->label('IDNO / CUI')->maxLength(40),
|
||||
Forms\Components\TextInput::make('legal_address')->label('Adresă')->columnSpanFull()->maxLength(255),
|
||||
Forms\Components\TextInput::make('legal_phone')->label('Telefon')->tel()->maxLength(40),
|
||||
Forms\Components\TextInput::make('legal_email')->label('Email')->email()->maxLength(120),
|
||||
]),
|
||||
Schemas\Components\Section::make('💳 Stripe')
|
||||
->description('Procesare carduri online. Funcționează în 30+ țări. Comision ~2.9% + 0.30€/tranzacție.')
|
||||
->columns(3)
|
||||
->collapsible()
|
||||
->collapsed(fn (Get $get) => ! $get('stripe_enabled'))
|
||||
->schema([
|
||||
Forms\Components\Toggle::make('stripe_enabled')->label('Activează Stripe')->default(false)->live(),
|
||||
Forms\Components\Select::make('stripe_mode')
|
||||
->label('Mod')
|
||||
->options(['test' => '🧪 Test', 'live' => '🟢 Live'])
|
||||
->default('test')
|
||||
->required(fn (Get $get) => $get('stripe_enabled'))
|
||||
->visible(fn (Get $get) => $get('stripe_enabled')),
|
||||
Forms\Components\TextInput::make('stripe_publishable')
|
||||
->label('Publishable key')->placeholder('pk_test_...')
|
||||
->visible(fn (Get $get) => $get('stripe_enabled')),
|
||||
Forms\Components\TextInput::make('stripe_secret')
|
||||
->label('Secret key')->password()->revealable()->placeholder('sk_test_...')
|
||||
->visible(fn (Get $get) => $get('stripe_enabled')),
|
||||
Forms\Components\TextInput::make('stripe_webhook')
|
||||
->label('Webhook secret')->password()->revealable()->placeholder('whsec_...')
|
||||
->columnSpanFull()
|
||||
->helperText('Endpoint webhook: https://service.mir.md/payments/stripe/webhook')
|
||||
->visible(fn (Get $get) => $get('stripe_enabled')),
|
||||
]),
|
||||
Schemas\Components\Section::make('🅿️ PayPal')
|
||||
->description('Plăți internaționale. Mai potrivit pentru clienți din afara MD.')
|
||||
->columns(3)
|
||||
->collapsible()
|
||||
->collapsed(fn (Get $get) => ! $get('paypal_enabled'))
|
||||
->schema([
|
||||
Forms\Components\Toggle::make('paypal_enabled')->label('Activează PayPal')->default(false)->live(),
|
||||
Forms\Components\Select::make('paypal_mode')
|
||||
->label('Mod')
|
||||
->options(['sandbox' => '🧪 Sandbox', 'live' => '🟢 Live'])
|
||||
->default('sandbox')
|
||||
->visible(fn (Get $get) => $get('paypal_enabled')),
|
||||
Forms\Components\Placeholder::make('paypal_webhook_info')
|
||||
->label('Webhook')
|
||||
->content('https://service.mir.md/payments/paypal/webhook')
|
||||
->visible(fn (Get $get) => $get('paypal_enabled')),
|
||||
Forms\Components\TextInput::make('paypal_client_id')
|
||||
->label('Client ID')->placeholder('AYS...')
|
||||
->visible(fn (Get $get) => $get('paypal_enabled')),
|
||||
Forms\Components\TextInput::make('paypal_secret')
|
||||
->label('Secret')->password()->revealable()->placeholder('EJk...')
|
||||
->visible(fn (Get $get) => $get('paypal_enabled')),
|
||||
]),
|
||||
Schemas\Components\Section::make('🏦 Transfer bancar (manual)')
|
||||
->description('Datele apar pe facturi și pe pagina de plată a tenant-ului. Confirmarea o faci manual.')
|
||||
->columns(2)
|
||||
->collapsible()
|
||||
->schema([
|
||||
Forms\Components\Toggle::make('bank_enabled')->label('Activează plata prin transfer')->default(true)->live(),
|
||||
Forms\Components\TextInput::make('bank_beneficiary')
|
||||
->label('Beneficiar')->placeholder('AutoCRM SRL')
|
||||
->visible(fn (Get $get) => $get('bank_enabled')),
|
||||
Forms\Components\TextInput::make('bank_iban')
|
||||
->label('IBAN')->placeholder('MD00 AG00 0000 ...')
|
||||
->visible(fn (Get $get) => $get('bank_enabled')),
|
||||
Forms\Components\TextInput::make('bank_bic')
|
||||
->label('BIC / SWIFT')->placeholder('AGRNMD2X')
|
||||
->visible(fn (Get $get) => $get('bank_enabled')),
|
||||
Forms\Components\TextInput::make('bank_name')
|
||||
->label('Banca')->placeholder('Moldova-Agroindbank')
|
||||
->visible(fn (Get $get) => $get('bank_enabled')),
|
||||
Forms\Components\Textarea::make('bank_instructions')
|
||||
->label('Instrucțiuni adiționale')->rows(2)->columnSpanFull()
|
||||
->visible(fn (Get $get) => $get('bank_enabled')),
|
||||
]),
|
||||
])
|
||||
->statePath('data');
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$data = $this->form->getState();
|
||||
|
||||
PlatformSetting::put('payments.platform_currency', $data['platform_currency']);
|
||||
PlatformSetting::put('payments.invoice_prefix', $data['invoice_prefix']);
|
||||
PlatformSetting::put('payments.terms', $data['terms']);
|
||||
|
||||
PlatformSetting::put('payments.company_legal', [
|
||||
'name' => $data['legal_name'] ?? null,
|
||||
'idno' => $data['legal_idno'] ?? null,
|
||||
'address' => $data['legal_address'] ?? null,
|
||||
'phone' => $data['legal_phone'] ?? null,
|
||||
'email' => $data['legal_email'] ?? null,
|
||||
]);
|
||||
|
||||
PlatformSetting::put('payments.stripe', [
|
||||
'enabled' => (bool) ($data['stripe_enabled'] ?? false),
|
||||
'mode' => $data['stripe_mode'] ?? 'test',
|
||||
'publishable_key' => $data['stripe_publishable'] ?? null,
|
||||
'secret_key' => $data['stripe_secret'] ?? null,
|
||||
'webhook_secret' => $data['stripe_webhook'] ?? null,
|
||||
]);
|
||||
|
||||
PlatformSetting::put('payments.paypal', [
|
||||
'enabled' => (bool) ($data['paypal_enabled'] ?? false),
|
||||
'mode' => $data['paypal_mode'] ?? 'sandbox',
|
||||
'client_id' => $data['paypal_client_id'] ?? null,
|
||||
'secret' => $data['paypal_secret'] ?? null,
|
||||
]);
|
||||
|
||||
PlatformSetting::put('payments.bank', [
|
||||
'enabled' => (bool) ($data['bank_enabled'] ?? false),
|
||||
'beneficiary' => $data['bank_beneficiary'] ?? null,
|
||||
'iban' => $data['bank_iban'] ?? null,
|
||||
'bic' => $data['bank_bic'] ?? null,
|
||||
'bank_name' => $data['bank_name'] ?? null,
|
||||
'instructions' => $data['bank_instructions'] ?? null,
|
||||
]);
|
||||
|
||||
Notification::make()->title('Setări plăți salvate')->success()->send();
|
||||
}
|
||||
|
||||
protected function getFormActions(): array
|
||||
{
|
||||
return [
|
||||
\Filament\Actions\Action::make('save')
|
||||
->label('Salvează')
|
||||
->submit('save'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user