Commit 2be39175 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Unify receipt/invoice settings: 3-tab template system + fix seeder

- EnrollmentSettingsSeeder: fix Organization → Academy class name
- ReceiptTemplate: add defaultInvoiceFields/Settings + defaultPaymentFields/Settings
- ReceiptSettings: rewritten with pos/invoice/payment tabs; each tab loads
  its own ReceiptTemplate (type='invoice'|'payment') and saves independently
- receipt-settings.blade.php: 3-tab UI with field toggles + appearance settings
  per document type; link to branding page for logo/colors
- print/invoice.blade.php: all 15 fields now gated by invoice template flags
  (logo, academy name, branch, tax number, client details, items table,
  subtotal, discount, tax, service fee, paid amount, payments history,
  signature, terms & conditions, footer text)
- print/payment-receipt.blade.php: all 11 fields gated by payment template;
  footer text pulled from template settings instead of hardcoded string
Co-Authored-By: 's avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 20284ee2
......@@ -162,4 +162,58 @@ public static function defaultSettings(): array
'time_format' => 'H:i',
];
}
public static function defaultInvoiceFields(): array
{
return [
'header_logo' => true,
'header_academy_name' => true,
'header_branch' => true,
'header_tax_number' => false,
'client_details' => true,
'items_table' => true,
'subtotal' => true,
'discount' => true,
'tax_amount' => true,
'service_fee' => true,
'paid_amount' => true,
'payments_history' => true,
'signature' => false,
'terms_conditions' => false,
'footer_text' => true,
];
}
public static function defaultInvoiceSettings(): array
{
return [
'footer_text' => '',
'currency_symbol' => 'ج.م',
];
}
public static function defaultPaymentFields(): array
{
return [
'header_logo' => true,
'header_academy_name' => true,
'reference_number' => true,
'date' => true,
'payment_method' => true,
'invoice_number' => true,
'payer_name' => true,
'received_by' => true,
'status_badge' => true,
'notes' => true,
'footer_text' => true,
];
}
public static function defaultPaymentSettings(): array
{
return [
'footer_text' => 'تم إنشاء هذا المستند إلكترونياً ولا يحتاج إلى توقيع',
'currency_symbol' => 'ج.م',
];
}
}
This diff is collapsed.
......@@ -3,14 +3,14 @@
namespace Database\Seeders;
use App\Domain\Shared\Models\SystemSetting;
use App\Domain\Identity\Models\Organization;
use App\Domain\Shared\Models\Academy;
use Illuminate\Database\Seeder;
class EnrollmentSettingsSeeder extends Seeder
{
public function run(): void
{
$academies = Organization::all();
$academies = Academy::all();
$defaults = [
[
......
......@@ -8,9 +8,20 @@
$branding = app(\App\Domain\Shared\Services\SettingsService::class);
$brandLogo = $branding->get('branding.logo');
$brandPrimary = $branding->get('branding.primary_color', '#1e40af');
$receiptFooter = $branding->get('branding.receipt_footer_text', __('تم إنشاء هذه الفاتورة إلكترونياً ولا تحتاج إلى توقيع'));
$academyName = app()->bound('current_academy') ? app('current_academy')->name_ar : 'الكابتن';
$branch = \App\Domain\Identity\Models\Branch::where('academy_id', app('current_academy')?->id)->first();
// Load invoice template for field visibility
$invoiceTpl = $branch ? \App\Domain\POS\Models\ReceiptTemplate::resolveFor($branch->id, 'invoice') : null;
$f = $invoiceTpl?->visible_fields ?? \App\Domain\POS\Models\ReceiptTemplate::defaultInvoiceFields();
$tplSettings = $invoiceTpl?->settings ?? \App\Domain\POS\Models\ReceiptTemplate::defaultInvoiceSettings();
$receiptFooter = !empty($tplSettings['footer_text'])
? $tplSettings['footer_text']
: $branding->get('branding.receipt_footer_text', 'تم إنشاء هذه الفاتورة إلكترونياً ولا تحتاج إلى توقيع');
$showSignature = $branding->get('branding.show_signature_in_invoice', false);
$signature = $branding->get('branding.signature');
$termsText = $branding->get('branding.terms_and_conditions', '');
$taxNumber = $branding->get('financial.tax_registration_number', '');
@endphp
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700&display=swap" rel="stylesheet">
<style>
......@@ -151,15 +162,20 @@
<div class="invoice-wrapper">
<div class="header">
<div class="brand">
@if($brandLogo)
@if(($f['header_logo'] ?? true) && $brandLogo)
<img src="{{ Storage::disk('public')->url($brandLogo) }}" alt="{{ $academyName }}">
@endif
<div>
<h1>{{ __('فاتورة') }}</h1>
@if($f['header_academy_name'] ?? true)
<p style="color: #64748b; margin-top: 2px; font-size: 13px;">{{ $academyName }}</p>
@if($branch)
@endif
@if(($f['header_branch'] ?? true) && $branch)
<p style="color: #94a3b8; font-size: 11px;">{{ $branch->name_ar }}</p>
@endif
@if(($f['header_tax_number'] ?? false) && $taxNumber)
<p style="color: #94a3b8; font-size: 11px;">{{ __('الرقم الضريبي') }}: {{ $taxNumber }}</p>
@endif
</div>
</div>
<div class="meta">
......@@ -175,7 +191,9 @@
</div>
</div>
@if(($f['client_details'] ?? true) || ($f['header_branch'] ?? true))
<div class="parties">
@if($f['client_details'] ?? true)
<div class="party">
<h3>{{ __('العميل') }}</h3>
@if($invoice->billable)
......@@ -185,6 +203,8 @@
@endif
@endif
</div>
@endif
@if($f['header_branch'] ?? true)
<div class="party">
<h3>{{ __('من') }}</h3>
<p><strong>{{ $academyName }}</strong></p>
......@@ -197,8 +217,11 @@
@endif
@endif
</div>
@endif
</div>
@endif
@if($f['items_table'] ?? true)
<div class="items-table">
<table>
<thead>
......@@ -225,26 +248,29 @@
</tbody>
</table>
</div>
@endif
<div class="totals-section">
<div class="totals">
@if($f['subtotal'] ?? true)
<div class="row">
<span>{{ __('المجموع الفرعي') }}</span>
<span dir="ltr">{{ format_money($invoice->subtotal_amount ?? $invoice->total_amount) }}</span>
</div>
@if($invoice->discount_amount > 0)
@endif
@if(($f['discount'] ?? true) && $invoice->discount_amount > 0)
<div class="row">
<span>{{ __('الخصم') }}</span>
<span dir="ltr" style="color: #dc2626;">-{{ format_money($invoice->discount_amount) }}</span>
</div>
@endif
@if(($invoice->service_fee_amount ?? 0) > 0)
@if(($f['service_fee'] ?? true) && ($invoice->service_fee_amount ?? 0) > 0)
<div class="row">
<span>{{ __('رسوم الخدمة') }}</span>
<span dir="ltr">{{ format_money($invoice->service_fee_amount) }}</span>
</div>
@endif
@if($invoice->tax_amount > 0)
@if(($f['tax_amount'] ?? true) && $invoice->tax_amount > 0)
<div class="row">
<span>{{ __('الضريبة') }}</span>
<span dir="ltr">{{ format_money($invoice->tax_amount) }}</span>
......@@ -254,7 +280,7 @@
<span>{{ __('الإجمالي') }}</span>
<span dir="ltr">{{ format_money($invoice->total_amount) }}</span>
</div>
@if($invoice->paid_amount > 0)
@if(($f['paid_amount'] ?? true) && $invoice->paid_amount > 0)
<div class="row paid">
<span>{{ __('المدفوع') }}</span>
<span dir="ltr">{{ format_money($invoice->paid_amount) }}</span>
......@@ -267,7 +293,7 @@
</div>
</div>
@if($invoice->payments && $invoice->payments->count())
@if(($f['payments_history'] ?? true) && $invoice->payments && $invoice->payments->count())
<div class="payments-section">
<h3>{{ __('المدفوعات') }}</h3>
<table>
......@@ -293,9 +319,25 @@
</div>
@endif
@if(($f['signature'] ?? false) && $showSignature && $signature)
<div style="padding: 12px 20px; text-align: end;">
<img src="{{ Storage::disk('public')->url($signature) }}" alt="{{ __('التوقيع') }}" style="height: 50px; object-fit: contain;">
<p style="font-size: 11px; color: #94a3b8; margin-top: 4px;">{{ __('التوقيع المعتمد') }}</p>
</div>
@endif
@if(($f['terms_conditions'] ?? false) && $termsText)
<div style="padding: 12px 20px; border-top: 1px solid #e2e8f0; font-size: 11px; color: #64748b;">
<p style="font-weight: 600; margin-bottom: 4px;">{{ __('الشروط والأحكام') }}</p>
<p style="white-space: pre-wrap;">{{ $termsText }}</p>
</div>
@endif
@if($f['footer_text'] ?? true)
<div class="footer">
{{ $receiptFooter }}
</div>
@endif
<div class="actions">
<button onclick="window.print()" class="btn btn-print">
......
......@@ -9,6 +9,13 @@
$brandLogo = $branding->get('branding.logo');
$brandPrimary = $branding->get('branding.primary_color', '#1e40af');
$academyName = app()->bound('current_academy') ? app('current_academy')->name_ar : 'الكابتن';
$payBranch = \App\Domain\Identity\Models\Branch::where('academy_id', app('current_academy')?->id)->first();
$payTpl = $payBranch ? \App\Domain\POS\Models\ReceiptTemplate::resolveFor($payBranch->id, 'payment') : null;
$pf = $payTpl?->visible_fields ?? \App\Domain\POS\Models\ReceiptTemplate::defaultPaymentFields();
$payTplSettings = $payTpl?->settings ?? \App\Domain\POS\Models\ReceiptTemplate::defaultPaymentSettings();
$payFooter = !empty($payTplSettings['footer_text'])
? $payTplSettings['footer_text']
: 'تم إنشاء هذا المستند إلكترونياً ولا يحتاج إلى توقيع';
@endphp
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700&display=swap" rel="stylesheet">
<style>
......@@ -114,11 +121,13 @@
<body>
<div class="receipt-wrapper">
<div class="header">
@if($brandLogo)
@if(($pf['header_logo'] ?? true) && $brandLogo)
<img src="{{ Storage::disk('public')->url($brandLogo) }}" alt="{{ $academyName }}">
@endif
<h1>{{ __('إيصال دفع') }}</h1>
@if($pf['header_academy_name'] ?? true)
<div class="academy">{{ $academyName }}</div>
@endif
</div>
<div class="amount-section">
......@@ -126,50 +135,49 @@
<div class="amount-value">{{ format_money($payment->amount) }}</div>
</div>
@php
$methodLabels = ['cash'=>'نقدي','card'=>'بطاقة','bank_transfer'=>'تحويل بنكي','wallet'=>'محفظة','online'=>'إلكتروني','cheque'=>'شيك','other'=>'أخرى'];
$methodValue = $payment->method?->value ?? $payment->method ?? '';
$payerName = $payment->invoice?->contact_name
?? $payment->invoice?->billable?->person?->name_ar
?? $payment->invoice?->billable?->person?->name
?? null;
$statusValue = $payment->status?->value ?? $payment->status ?? 'pending';
$statusLabels = ['pending'=>'معلق','confirmed'=>'مؤكد','failed'=>'فاشل','cancelled'=>'ملغى','refunded'=>'مسترد'];
@endphp
<div class="info-section">
@if($pf['reference_number'] ?? true)
<div class="info-row">
<span class="label">{{ __('رقم المرجع') }}</span>
<span class="value" dir="ltr">{{ $payment->reference ?? 'PAY-' . str_pad($payment->id, 6, '0', STR_PAD_LEFT) }}</span>
</div>
@endif
@if($pf['date'] ?? true)
<div class="info-row">
<span class="label">{{ __('التاريخ') }}</span>
<span class="value" dir="ltr">{{ $payment->payment_date?->format('Y/m/d') ?? $payment->created_at?->format('Y/m/d') }}</span>
</div>
@php
$methodLabels = [
'cash' => 'نقدي',
'card' => 'بطاقة',
'bank_transfer' => 'تحويل بنكي',
'wallet' => 'محفظة',
'online' => 'إلكتروني',
'cheque' => 'شيك',
'other' => 'أخرى',
];
$methodValue = $payment->method?->value ?? $payment->method ?? '';
@endphp
@endif
@if($pf['payment_method'] ?? true)
<div class="info-row">
<span class="label">{{ __('طريقة الدفع') }}</span>
<span class="value">{{ $methodLabels[$methodValue] ?? $methodValue }}</span>
</div>
@if($payment->invoice)
@endif
@if(($pf['invoice_number'] ?? true) && $payment->invoice)
<div class="info-row">
<span class="label">{{ __('رقم الفاتورة') }}</span>
<span class="value" dir="ltr">{{ $payment->invoice->number }}</span>
</div>
@endif
@php
$payerName = $payment->invoice?->contact_name
?? $payment->invoice?->billable?->person?->name_ar
?? $payment->invoice?->billable?->person?->name
?? null;
@endphp
@if($payerName)
@if(($pf['payer_name'] ?? true) && $payerName)
<div class="info-row">
<span class="label">{{ __('الدافع') }}</span>
<span class="value">{{ $payerName }}</span>
</div>
@endif
@if($payment->creator)
@if(($pf['received_by'] ?? true) && $payment->creator)
<div class="info-row">
<span class="label">{{ __('استلم بواسطة') }}</span>
<span class="value">{{ $payment->creator->name ?? '' }}</span>
......@@ -177,30 +185,24 @@
@endif
</div>
@php
$statusValue = $payment->status?->value ?? $payment->status ?? 'pending';
$statusLabels = [
'pending' => 'معلق',
'confirmed' => 'مؤكد',
'failed' => 'فاشل',
'cancelled' => 'ملغى',
'refunded' => 'مسترد',
];
@endphp
@if($pf['status_badge'] ?? true)
<div style="text-align: center; padding: 12px 16px; border-bottom: 1px dashed #e2e8f0;">
<span class="status-badge status-{{ $statusValue }}">{{ $statusLabels[$statusValue] ?? $statusValue }}</span>
</div>
@endif
@if($payment->notes)
@if(($pf['notes'] ?? true) && $payment->notes)
<div class="info-section">
<div style="font-size: 12px; color: #64748b;">{{ __('ملاحظات') }}:</div>
<div style="font-size: 13px; margin-top: 4px;">{{ $payment->notes }}</div>
</div>
@endif
@if($pf['footer_text'] ?? true)
<div class="footer">
{{ __('تم إنشاء هذا المستند إلكترونياً ولا يحتاج إلى توقيع') }}
{{ $payFooter }}
</div>
@endif
<div class="actions">
<button onclick="window.print()" class="btn btn-print">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment