Work on Payments
This commit is contained in:
parent
f937302159
commit
b2c8ce7405
@ -4,21 +4,20 @@
|
||||
|
||||
enum IconEnum: string
|
||||
{
|
||||
case DEFAULT = 'heroicon-o-rectangle-stack';
|
||||
case INVOICE = 'lucide-receipt-text';
|
||||
case ORDER = 'lucide-shopping-cart';
|
||||
case QUOTE = 'lucide-quote';
|
||||
case CUSTOMER = 'lucide-building';
|
||||
case PACKING_SLIP = 'lucide-package';
|
||||
case SHIPPING_ENTRY = 'lucide-truck';
|
||||
case USER = 'lucide-users';
|
||||
case TAX_RATE = 'lucide-circle-dollar-sign';
|
||||
|
||||
// case PRODUCT_SERVICE = 'heroicon-o-rectangle-stack';
|
||||
// case CUSTOMER_SALES = 'heroicon-o-rectangle-stack';
|
||||
// case INVOICE_REPORT = 'heroicon-o-rectangle-stack';
|
||||
|
||||
case TAB_ALL = 'lucide-layout-grid';
|
||||
case TAB_OVERDUE = 'lucide-calendar-clock';
|
||||
case TAB_UNPRINTED = 'lucide-printer';
|
||||
case DEFAULT = 'heroicon-o-rectangle-stack';
|
||||
case INVOICE = 'lucide-file-text';
|
||||
case ORDER = 'lucide-shopping-cart';
|
||||
case QUOTE = 'lucide-quote';
|
||||
case CUSTOMER = 'lucide-building';
|
||||
case PACKING_SLIP = 'lucide-package';
|
||||
case SHIPPING_ENTRY = 'lucide-truck';
|
||||
case USER = 'lucide-users';
|
||||
case TAX_RATE = 'lucide-circle-dollar-sign';
|
||||
case DISTRIBUTE_PAYMENTS = 'lucide-rotate-cw';
|
||||
case PRODUCT_SERVICE = 'heroicon-o-rectangle';
|
||||
case CUSTOMER_SALES = 'lucide-book-user';
|
||||
case INVOICE_REPORT = 'lucide-files';
|
||||
case TAB_ALL = 'lucide-layout-grid';
|
||||
case TAB_OVERDUE = 'lucide-calendar-clock';
|
||||
case TAB_UNPRINTED = 'lucide-printer';
|
||||
}
|
||||
|
33
app/Events/InvoiceCreated.php
Normal file
33
app/Events/InvoiceCreated.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class InvoiceCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('channel-name'),
|
||||
];
|
||||
}
|
||||
}
|
@ -18,13 +18,13 @@ class CustomerReportResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Customer::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconEnum::CUSTOMER_SALES->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Reports';
|
||||
|
||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
||||
protected static ?string $navigationLabel = 'Customer Reports';
|
||||
|
||||
protected static ?string $navigationLabel = 'Customer Sales';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
protected static ?int $navigationSort = 4;
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\ContactsRelationManager;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\InvoicesRelationManager;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\PaymentsRelationManager;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\ShippingEntriesRelationManager;
|
||||
use App\Models\Customer;
|
||||
use Filament\Forms\Components\Section;
|
||||
@ -29,7 +31,8 @@ public static function form(Form $form): Form
|
||||
return $form
|
||||
->schema([
|
||||
Section::make([
|
||||
TextInput::make('company_name'),
|
||||
TextInput::make('company_name')
|
||||
->required(),
|
||||
TextInput::make('phone'),
|
||||
TextInput::make('shipping_address_line_1'),
|
||||
TextInput::make('shipping_address_line_2'),
|
||||
@ -44,10 +47,14 @@ public static function table(Table $table): Table
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('company_name')
|
||||
->extraHeaderAttributes(['class' => 'w-full'])
|
||||
->searchable()
|
||||
->sortable(),
|
||||
// TextColumn::make('shipping_address'),
|
||||
TextColumn::make('phone'),
|
||||
TextColumn::make('balance')
|
||||
->getStateUsing(fn (Customer $customer) => $customer->calculateBalance())
|
||||
->money()
|
||||
->hidden(! auth()->user()->is_admin),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
@ -65,19 +72,19 @@ public static function table(Table $table): Table
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
// RelationGroup::make('Relations', [
|
||||
InvoicesRelationManager::class,
|
||||
PaymentsRelationManager::class,
|
||||
ContactsRelationManager::class,
|
||||
ShippingEntriesRelationManager::class,
|
||||
// ]),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => \App\Filament\Admin\Resources\CustomerResource\Pages\ListCustomers::route('/'),
|
||||
'create' => \App\Filament\Admin\Resources\CustomerResource\Pages\CreateCustomer::route('/create'),
|
||||
'edit' => \App\Filament\Admin\Resources\CustomerResource\Pages\EditCustomer::route('/{record}/edit'),
|
||||
'index' => \App\Filament\Admin\Resources\CustomerResource\Pages\ListCustomers::route('/'),
|
||||
// 'create' => \App\Filament\Admin\Resources\CustomerResource\Pages\CreateCustomer::route('/create'),
|
||||
'edit' => \App\Filament\Admin\Resources\CustomerResource\Pages\EditCustomer::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class EditCustomer extends EditRecord
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
//todo: make report
|
||||
// todo: make report
|
||||
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources\CustomerResource\RelationManagers;
|
||||
|
||||
use App\Filament\Admin\Resources\InvoiceResource;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class InvoicesRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'invoices';
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return InvoiceResource::table($table);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources\CustomerResource\RelationManagers;
|
||||
|
||||
use App\Filament\Admin\Resources\PaymentResource;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class PaymentsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'payments';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
// PaymentResource
|
||||
// Forms\Components\TextInput::make('amount')
|
||||
// ->required()
|
||||
// ->maxLength(255),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return PaymentResource::table($table);
|
||||
|
||||
/* return $table
|
||||
->recordTitleAttribute('amount')
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('amount'),
|
||||
])
|
||||
->headerActions([
|
||||
Tables\Actions\CreateAction::make(),
|
||||
]);*/
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
|
||||
class InvoiceReportResource extends Resource
|
||||
{
|
||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
||||
protected static ?string $navigationIcon = IconEnum::INVOICE_REPORT->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Reports';
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Admin\Resources\InvoiceReportResource\RelationManagers;
|
||||
|
||||
use App\Filament\Admin\Resources\InvoiceResource;
|
||||
use App\Models\Invoice;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
@ -50,9 +51,9 @@ public function table(Table $table): Table
|
||||
->formatStateUsing(function ($state) {
|
||||
return $state == 0.00 ? '-' : '$'.$state;
|
||||
}),
|
||||
TextColumn::make('total')
|
||||
->label('Balance Due')
|
||||
TextColumn::make('balance')
|
||||
->alignRight()
|
||||
->getStateUsing(fn (Invoice $record) => $record->remainingBalance())
|
||||
->money()
|
||||
->weight(FontWeight::Bold),
|
||||
TextColumn::make('status'),
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\InvoicesRelationManager;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\RelationManagers\OrdersRelationManager;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\RelationManagers\ProductServicesRelationManager;
|
||||
use App\Models\Customer;
|
||||
@ -19,6 +20,7 @@
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Support\Enums\FontWeight;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
@ -31,9 +33,9 @@ class InvoiceResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = IconEnum::INVOICE->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Production';
|
||||
protected static ?string $navigationGroup = 'Financial';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
@ -42,40 +44,30 @@ public static function form(Form $form): Form
|
||||
Group::make()
|
||||
->schema([
|
||||
Section::make([
|
||||
Grid::make(2)
|
||||
->schema([
|
||||
Select::make('customer_id')
|
||||
->required()
|
||||
->label('Customer')
|
||||
->options(Customer::all()->pluck('company_name', 'id'))
|
||||
->reactive()
|
||||
->searchable()
|
||||
->disabledOn('edit')
|
||||
->columnSpan(2),
|
||||
Select::make('customer_id')
|
||||
->required()
|
||||
->label('Customer')
|
||||
->options(Customer::all()->pluck('company_name', 'id'))
|
||||
->reactive()
|
||||
->searchable()
|
||||
->disabledOn('edit')
|
||||
->columnSpan(2),
|
||||
|
||||
Split::make([
|
||||
DatePicker::make('date')
|
||||
->required()
|
||||
->default(today()),
|
||||
DatePicker::make('due_date'),
|
||||
])
|
||||
->columnSpan(2),
|
||||
Split::make([
|
||||
DatePicker::make('date')
|
||||
->required()
|
||||
->default(today()),
|
||||
DatePicker::make('due_date'),
|
||||
])
|
||||
->columnSpan(2),
|
||||
|
||||
ToggleButtons::make('status')
|
||||
->options(InvoiceStatus::class)
|
||||
->required()
|
||||
->inline()
|
||||
->default(InvoiceStatus::UNPAID)
|
||||
->columnSpan(2),
|
||||
])->columnSpan(2),
|
||||
|
||||
Grid::make(1)
|
||||
Grid::make(3)
|
||||
->schema([
|
||||
ToggleButtons::make('has_gst')
|
||||
->label('GST')
|
||||
->boolean('On', 'Off')
|
||||
->default(true)
|
||||
->inline()
|
||||
// ->inline()
|
||||
->colors([
|
||||
'true' => 'info',
|
||||
'false' => 'info',
|
||||
@ -85,7 +77,7 @@ public static function form(Form $form): Form
|
||||
->label('PST')
|
||||
->boolean('On', 'Off')
|
||||
->default(false)
|
||||
->inline()
|
||||
// ->inline()
|
||||
->colors([
|
||||
'true' => 'info',
|
||||
'false' => 'info',
|
||||
@ -95,14 +87,22 @@ public static function form(Form $form): Form
|
||||
->label('HST')
|
||||
->boolean('On', 'Off')
|
||||
->default(false)
|
||||
->inline()
|
||||
// ->inline()
|
||||
->colors([
|
||||
'true' => 'info',
|
||||
'false' => 'info',
|
||||
]),
|
||||
])->columnSpan(1),
|
||||
|
||||
ToggleButtons::make('status')
|
||||
->options(InvoiceStatus::class)
|
||||
->required()
|
||||
->inline()
|
||||
->default(InvoiceStatus::UNPAID)
|
||||
->columnSpan(1),
|
||||
|
||||
])
|
||||
->columns(3)
|
||||
->columns(2)
|
||||
->columnSpan(2),
|
||||
|
||||
Section::make()
|
||||
@ -111,16 +111,15 @@ public static function form(Form $form): Form
|
||||
->label('ID')
|
||||
->content(fn (Invoice $record): ?string => $record->internal_id),
|
||||
|
||||
Placeholder::make('Tax Rates '.'(if applicable)')
|
||||
Placeholder::make('Amounts')
|
||||
->content(fn (Invoice $record): ?string => 'Total: $'.$record->total.', balance: $'.$record->remainingBalance()),
|
||||
|
||||
Placeholder::make('Tax Rates when created')
|
||||
->content(fn (Invoice $record): ?string => $record->gst_rate.'% GST, '.$record->pst_rate.'% PST, '.$record->hst_rate.'% HST'),
|
||||
|
||||
Placeholder::make('created_at')
|
||||
->label('Created')
|
||||
->content(fn (Invoice $record): ?string => $record->created_at->format('Y-m-d')),
|
||||
|
||||
Placeholder::make('updated_at')
|
||||
->label('Last modified')
|
||||
->content(fn (Invoice $record): ?string => $record->updated_at->format('Y-m-d')),
|
||||
->label('Timestamps')
|
||||
->content(fn (Invoice $record): ?string => 'Created at '.$record->created_at->format('Y-m-d').', updated at '.$record->updated_at->format('Y-m-d')),
|
||||
|
||||
])
|
||||
->columnSpan(1)
|
||||
@ -138,6 +137,7 @@ public static function table(Table $table): Table
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('internal_id')
|
||||
->extraHeaderAttributes(fn ($livewire) => $livewire::class === InvoicesRelationManager::class ? ['class' => 'w-full'] : false)
|
||||
->label('ID')
|
||||
->fontFamily('mono')
|
||||
->color('primary')
|
||||
@ -151,6 +151,7 @@ public static function table(Table $table): Table
|
||||
}),
|
||||
|
||||
TextColumn::make('customer.company_name')
|
||||
->hidden(fn ($livewire) => $livewire::class === InvoicesRelationManager::class)
|
||||
->sortable()
|
||||
->extraHeaderAttributes(['class' => 'w-full'])
|
||||
->searchable(),
|
||||
@ -186,22 +187,11 @@ public static function table(Table $table): Table
|
||||
return '-';
|
||||
})
|
||||
->alignRight(),
|
||||
TextColumn::make('has_hst')
|
||||
->label('HST')
|
||||
TextColumn::make('balance')
|
||||
->getStateUsing(fn (Invoice $record) => $record->remainingBalance())
|
||||
->money()
|
||||
->formatStateUsing(function (Invoice $record) {
|
||||
if ($record->has_hst) {
|
||||
return '$'.number_format($record->hst_amount, 2);
|
||||
}
|
||||
|
||||
return '-';
|
||||
})
|
||||
->alignRight(),
|
||||
TextColumn::make('total')
|
||||
->label('Total')
|
||||
->money()
|
||||
->weight('bold')
|
||||
->alignRight(),
|
||||
->alignRight()
|
||||
->weight(FontWeight::Bold),
|
||||
TextColumn::make('status')
|
||||
->badge(InvoiceStatus::class)
|
||||
->sortable(),
|
||||
@ -239,7 +229,8 @@ public static function table(Table $table): Table
|
||||
->defaultSort('id', 'desc')
|
||||
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\EditAction::make()
|
||||
->hidden(fn ($livewire) => $livewire::class === InvoicesRelationManager::class),
|
||||
])
|
||||
|
||||
->bulkActions([
|
||||
|
@ -24,7 +24,7 @@ class PackingSlipResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = IconEnum::PACKING_SLIP->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Management';
|
||||
protected static ?string $navigationGroup = 'Production';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
@ -112,9 +112,9 @@ public static function getRelations(): array
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => \App\Filament\Admin\Resources\PackingSlipResource\Pages\ListPackingSlips::route('/'),
|
||||
'create' => \App\Filament\Admin\Resources\PackingSlipResource\Pages\CreatePackingSlip::route('/create'),
|
||||
'edit' => \App\Filament\Admin\Resources\PackingSlipResource\Pages\EditPackingSlip::route('/{record}/edit'),
|
||||
'index' => \App\Filament\Admin\Resources\PackingSlipResource\Pages\ListPackingSlips::route('/'),
|
||||
// 'create' => \App\Filament\Admin\Resources\PackingSlipResource\Pages\CreatePackingSlip::route('/create'),
|
||||
// 'edit' => \App\Filament\Admin\Resources\PackingSlipResource\Pages\EditPackingSlip::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
109
app/Filament/Admin/Resources/PaymentResource.php
Normal file
109
app/Filament/Admin/Resources/PaymentResource.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\PaymentsRelationManager;
|
||||
use App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||
use App\Models\Payment;
|
||||
use Filament\Forms\Components\Section;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class PaymentResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Payment::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'lucide-hand-coins';
|
||||
|
||||
protected static ?string $navigationGroup = 'Financial';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Section::make([
|
||||
Select::make('customer_id')
|
||||
->relationship('customer', 'company_name')
|
||||
->required()
|
||||
->searchable()
|
||||
->preload(),
|
||||
TextInput::make('amount')
|
||||
->required()
|
||||
->minValue(0)
|
||||
->maxValue(99999999)
|
||||
->numeric(),
|
||||
Textarea::make('notes'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('created_at')
|
||||
->label('Date')
|
||||
->date('Y-m-d')
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer.company_name')
|
||||
->hidden(fn ($livewire) => $livewire::class === PaymentsRelationManager::class)
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('notes')
|
||||
->limit(100)
|
||||
->extraHeaderAttributes(['class' => 'w-full']),
|
||||
|
||||
TextColumn::make('amount')
|
||||
->searchable()
|
||||
->numeric()
|
||||
->money(),
|
||||
|
||||
TextColumn::make('unapplied_amount')
|
||||
->label('Balance')
|
||||
->money(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
ViewAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
// Tables\Actions\BulkActionGroup::make([
|
||||
// Tables\Actions\DeleteBulkAction::make(),
|
||||
// ]),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return auth()->user()->is_admin;
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListPayments::route('/'),
|
||||
// 'view' => Pages\ViewPayment::route('/{record}'),
|
||||
// 'create' => Pages\CreatePayment::route('/create'),
|
||||
// 'edit' => Pages\EditPayment::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||
|
||||
use App\Filament\Admin\Resources\PaymentResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreatePayment extends CreateRecord
|
||||
{
|
||||
protected static string $resource = PaymentResource::class;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||
|
||||
use App\Filament\Admin\Resources\PaymentResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditPayment extends EditRecord
|
||||
{
|
||||
protected static string $resource = PaymentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Admin\Resources\PaymentResource;
|
||||
use App\Services\PaymentService;
|
||||
use Filament\Actions;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListPayments extends ListRecords
|
||||
{
|
||||
protected static string $resource = PaymentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\Action::make('distributePayments')
|
||||
->icon(IconEnum::DISTRIBUTE_PAYMENTS->value)
|
||||
->action(function (PaymentService $paymentService) {
|
||||
$paymentService->distributePayments();
|
||||
|
||||
Notification::make()
|
||||
->title('Success!')
|
||||
->body('Payments have been distributed')
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
|
||||
Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||
|
||||
use App\Filament\Admin\Resources\PaymentResource;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewPayment extends ViewRecord
|
||||
{
|
||||
protected static string $resource = PaymentResource::class;
|
||||
}
|
@ -22,6 +22,8 @@ class ServiceTypeResource extends Resource
|
||||
|
||||
protected static ?string $label = 'Product Services';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
public static function getWidgets(): array
|
||||
{
|
||||
return [
|
||||
|
@ -4,10 +4,11 @@
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Models\User;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
use Filament\Forms\Components\Grid;
|
||||
use Filament\Forms\Components\Section;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
@ -28,32 +29,49 @@ public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Section::make()
|
||||
Section::make('Login details')
|
||||
->description(fn (string $operation) => $operation == 'edit' ? 'To leave the password unchanged, leave both fields empty,' : false)
|
||||
->schema([
|
||||
TextInput::make('username')
|
||||
->autocomplete(false)
|
||||
->autocomplete('new-username')
|
||||
->unique()
|
||||
->required(),
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('password')
|
||||
->password()
|
||||
->autocomplete(false)
|
||||
->dehydrated(fn ($state) => ! empty($state))
|
||||
->required(fn (string $operation): bool => $operation === 'create'),
|
||||
Grid::make(2)
|
||||
->schema([
|
||||
TextInput::make('password')
|
||||
->password()
|
||||
->autocomplete('new-password')
|
||||
->revealable()
|
||||
->dehydrated(fn ($state) => ! empty($state))
|
||||
->required(fn (string $operation): bool => $operation === 'create'),
|
||||
|
||||
TextInput::make('password_verify')
|
||||
->label('Verify password')
|
||||
->password()
|
||||
->same('password')
|
||||
->dehydrated(false)
|
||||
->autocomplete(false)
|
||||
->required(fn (string $operation) => $operation === 'create'),
|
||||
TextInput::make('password_verify')
|
||||
->label('Verify password')
|
||||
->password()
|
||||
->revealable()
|
||||
->same('password')
|
||||
->dehydrated(false)
|
||||
->required(fn (string $operation) => $operation === 'create'),
|
||||
])
|
||||
->columnSpan(2),
|
||||
]),
|
||||
|
||||
Checkbox::make('is_admin')
|
||||
->label('Admin')
|
||||
Section::make('Permissions')
|
||||
->description('Administrators can access financial information and change settings.')
|
||||
->schema([
|
||||
Toggle::make('is_admin')
|
||||
->label('User is an administrator')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set) => $set('customer_id', null))
|
||||
->disabled(fn (?User $record, $operation) => $operation !== 'create' && auth()->user()->id === $record->id),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Section::make('Customer Login')
|
||||
->description('If this account is for a customer, select them here.')
|
||||
->schema([
|
||||
|
||||
Select::make('customer_id')
|
||||
->relationship('customer', 'company_name')
|
||||
@ -73,7 +91,8 @@ public static function table(Table $table): Table
|
||||
TextColumn::make('username')
|
||||
->extraHeaderAttributes(['class' => 'w-full']),
|
||||
TextColumn::make('customer.company_name')
|
||||
->sortable(),
|
||||
->sortable()
|
||||
->placeholder('Internal'),
|
||||
Tables\Columns\IconColumn::make('is_admin')
|
||||
->label('Admin')
|
||||
->boolean()
|
||||
@ -83,7 +102,7 @@ public static function table(Table $table): Table
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\EditAction::make()->modal(),
|
||||
])
|
||||
->defaultSort('customer_id', 'asc');
|
||||
}
|
||||
@ -103,9 +122,9 @@ public static function getRelations(): array
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => \App\Filament\Admin\Resources\UserResource\Pages\ListUsers::route('/'),
|
||||
'create' => \App\Filament\Admin\Resources\UserResource\Pages\CreateUser::route('/create'),
|
||||
'edit' => \App\Filament\Admin\Resources\UserResource\Pages\EditUser::route('/{record}/edit'),
|
||||
'index' => \App\Filament\Admin\Resources\UserResource\Pages\ListUsers::route('/'),
|
||||
];
|
||||
}
|
||||
|
||||
private static function Grid() {}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Admin\Resources\UserResource\Pages;
|
||||
|
||||
use App\Filament\Admin\Resources\UserResource;
|
||||
use App\Models\User;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
@ -13,7 +14,8 @@ class EditUser extends EditRecord
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
Actions\DeleteAction::make()
|
||||
->disabled(fn (User $record) => $record->id == auth()->user()->id),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ class ListUsers extends ListRecords
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make(),
|
||||
Actions\CreateAction::make()
|
||||
->modal(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public function store(PackingSlipRequest $request): RedirectResponse
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back(); //todo: change to packing slips page
|
||||
return redirect()->back(); // todo: change to packing slips page
|
||||
}
|
||||
|
||||
public function show($id): void {}
|
||||
|
@ -31,6 +31,14 @@ class Customer extends Model
|
||||
'total',
|
||||
];
|
||||
|
||||
public function calculateBalance(): float
|
||||
{
|
||||
$invoiceTotal = $this->invoices->sum('total');
|
||||
$paymentTotal = $this->payments->sum('amount');
|
||||
|
||||
return $paymentTotal - $invoiceTotal;
|
||||
}
|
||||
|
||||
public function getSubtotalAttribute($created_at = null, $created_until = null): float
|
||||
{
|
||||
return $this->invoices()
|
||||
@ -106,4 +114,9 @@ public function user(): HasOne
|
||||
{
|
||||
return $this->hasOne(User::class);
|
||||
}
|
||||
|
||||
public function payments(): HasMany
|
||||
{
|
||||
return $this->hasMany(Payment::class);
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,13 @@ class Invoice extends Model
|
||||
'total' => 'float',
|
||||
];
|
||||
|
||||
public function remainingBalance(): float
|
||||
{
|
||||
$applied = $this->payments()->sum('applied_amount');
|
||||
|
||||
return max(0, $this->total - $applied);
|
||||
}
|
||||
|
||||
public function calculateTotals(): void
|
||||
{
|
||||
$this->refresh();
|
||||
@ -120,4 +127,11 @@ public function invoiceReports(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(InvoiceReport::class);
|
||||
}
|
||||
|
||||
public function payments(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Payment::class)
|
||||
->withPivot('applied_amount')
|
||||
->withTimestamps();
|
||||
}
|
||||
}
|
||||
|
69
app/Models/Payment.php
Normal file
69
app/Models/Payment.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Observers\PaymentObserver;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
#[ObservedBy(PaymentObserver::class)]
|
||||
|
||||
class Payment extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'customer_id',
|
||||
'amount',
|
||||
'unapplied_amount',
|
||||
'notes',
|
||||
];
|
||||
|
||||
public function applyToInvoices(): void
|
||||
{
|
||||
$remaining = $this->unapplied_amount ?? $this->amount;
|
||||
|
||||
$invoices = Invoice::where('customer_id', $this->customer_id)
|
||||
->where('status', InvoiceStatus::UNPAID)
|
||||
->orderBy('date')
|
||||
->get();
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
$balance = $invoice->remainingBalance();
|
||||
|
||||
if ($remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
$applied = min($remaining, $balance);
|
||||
$invoice->payments()->attach($this->id, ['applied_amount' => $applied]);
|
||||
|
||||
$remaining -= $applied;
|
||||
|
||||
if ($invoice->remainingBalance() == 0) {
|
||||
$invoice->setStatus(InvoiceStatus::PAID);
|
||||
} elseif ($applied > 0) {
|
||||
$invoice->setStatus(InvoiceStatus::UNPAID);
|
||||
}
|
||||
}
|
||||
|
||||
$this->unapplied_amount = $remaining;
|
||||
$this->saveQuietly();
|
||||
}
|
||||
|
||||
public function customer(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Customer::class);
|
||||
}
|
||||
|
||||
public function invoices(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Invoice::class)
|
||||
->withPivot('applied_amount')
|
||||
->withTimestamps();
|
||||
}
|
||||
}
|
@ -22,12 +22,16 @@ public function creating(Invoice $invoice): void
|
||||
*/
|
||||
public function created(Invoice $invoice): void
|
||||
{
|
||||
|
||||
$invoice->internal_id = 'INV4'.str_pad($invoice->id, 5, '0', STR_PAD_LEFT);
|
||||
$invoice->saveQuietly();
|
||||
|
||||
$invoice->calculateTotals();
|
||||
|
||||
}
|
||||
|
||||
public function saved(Invoice $invoice) {}
|
||||
|
||||
/**
|
||||
* Handle the Invoice "updated" event.
|
||||
*/
|
||||
|
56
app/Observers/PaymentObserver.php
Normal file
56
app/Observers/PaymentObserver.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Payment;
|
||||
|
||||
class PaymentObserver
|
||||
{
|
||||
/**
|
||||
* Handle the Payment "saved" event.
|
||||
*/
|
||||
public function saved(Payment $payment): void
|
||||
{
|
||||
$payment->applyToInvoices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Payment "created" event.
|
||||
*/
|
||||
public function created(Payment $payment): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Payment "updated" event.
|
||||
*/
|
||||
public function updated(Payment $payment): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Payment "deleted" event.
|
||||
*/
|
||||
public function deleted(Payment $payment): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Payment "restored" event.
|
||||
*/
|
||||
public function restored(Payment $payment): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Payment "force deleted" event.
|
||||
*/
|
||||
public function forceDeleted(Payment $payment): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
16
app/Policies/InvoicePolicy.php
Normal file
16
app/Policies/InvoicePolicy.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class InvoicePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return auth()->user()->is_admin;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
use Filament\Http\Middleware\Authenticate;
|
||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||
use Filament\Navigation\NavigationGroup;
|
||||
use Filament\Pages;
|
||||
use Filament\Panel;
|
||||
use Filament\PanelProvider;
|
||||
@ -53,6 +54,13 @@ public function panel(Panel $panel): Panel
|
||||
->authMiddleware([
|
||||
Authenticate::class,
|
||||
])
|
||||
->sidebarWidth('13rem');
|
||||
->sidebarWidth('13rem')
|
||||
->navigationGroups([
|
||||
NavigationGroup::make('Production'),
|
||||
NavigationGroup::make('Management'),
|
||||
NavigationGroup::make('Financial'),
|
||||
NavigationGroup::make('Reports'),
|
||||
NavigationGroup::make('Settings'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
18
app/Services/PaymentService.php
Normal file
18
app/Services/PaymentService.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Payment;
|
||||
|
||||
class PaymentService
|
||||
{
|
||||
public function distributePayments()
|
||||
{
|
||||
|
||||
$payments = Payment::where('unapplied_amount', '>', 0)->get();
|
||||
|
||||
foreach ($payments as $payment) {
|
||||
$payment->applyToInvoices(); // Apply remaining amounts to the new invoice
|
||||
}
|
||||
}
|
||||
}
|
1505
composer.lock
generated
1505
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@ public function definition(): array
|
||||
'has_pst' => $this->faker->boolean(40),
|
||||
'has_hst' => false,
|
||||
'date' => Carbon::now()->subDays(rand(1, 60)),
|
||||
'status' => $this->faker->randomElement(InvoiceStatus::cases())->value,
|
||||
'status' => InvoiceStatus::UNPAID->value,
|
||||
'customer_id' => $customer->id,
|
||||
'updated_at' => Carbon::now(),
|
||||
];
|
||||
|
@ -12,12 +12,12 @@ public function up()
|
||||
$table->id();
|
||||
|
||||
$table->string('company_name');
|
||||
$table->string('internal_name');
|
||||
$table->string('shipping_address_line_1');
|
||||
$table->string('shipping_address_line_2');
|
||||
$table->string('billing_address_line_1');
|
||||
$table->string('billing_address_line_2');
|
||||
$table->string('phone');
|
||||
$table->string('internal_name')->nullable();
|
||||
$table->string('shipping_address_line_1')->nullable();
|
||||
$table->string('shipping_address_line_2')->nullable();
|
||||
$table->string('billing_address_line_1')->nullable();
|
||||
$table->string('billing_address_line_2')->nullable();
|
||||
$table->string('phone')->nullable();
|
||||
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
|
@ -11,7 +11,7 @@ public function up(): void
|
||||
Schema::create('packing_slips', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('order_id')->nullable()->constrained(); //todo: replace this once orders are actually in da system
|
||||
$table->foreignId('order_id')->nullable()->constrained(); // todo: replace this once orders are actually in da system
|
||||
$table->foreignId('customer_id')->nullable()->constrained();
|
||||
$table->date('date_received');
|
||||
$table->string('amount')->nullable();
|
||||
|
34
database/migrations/018_create_payments_table.php
Normal file
34
database/migrations/018_create_payments_table.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('payments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('customer_id')->constrained();
|
||||
$table->decimal('amount', 8, 2);
|
||||
$table->decimal('unapplied_amount', 8, 2)->nullable();
|
||||
$table->text('notes')->nullable();
|
||||
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('payments');
|
||||
}
|
||||
};
|
31
database/migrations/019_create_invoice_payment_table.php
Normal file
31
database/migrations/019_create_invoice_payment_table.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('invoice_payment', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('invoice_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('payment_id')->constrained()->cascadeOnDelete();
|
||||
$table->decimal('applied_amount', 8, 2);
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('invoice_payment');
|
||||
}
|
||||
};
|
1473
package-lock.json
generated
1473
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -12,22 +12,22 @@
|
||||
use App\Http\Controllers\ShippingEntryController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
//Route::get('/', function () {
|
||||
// Route::get('/', function () {
|
||||
// return redirect()->route('dashboard');
|
||||
//});
|
||||
// });
|
||||
//
|
||||
//Auth::routes();
|
||||
// Auth::routes();
|
||||
|
||||
Route::get('/pdf/invoicereport/{id}', [PdfController::class, 'invoiceReport'])->name('pdf.invoice-report');
|
||||
Route::get('orders/{order}/pdf', [OrderController::class, 'pdf'])->name('orders.pdf');
|
||||
Route::get('invoices/{invoice}/pdf', [InvoiceController::class, 'pdf'])->name('invoice.pdf');
|
||||
Route::get('customers/{customer}/pdf', [CustomerController::class, 'pdf'])->name('customer.pdf');
|
||||
|
||||
//Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
||||
//Route::get('/management/{tab?}', [ManagementController::class, 'index'])->name('management.index');
|
||||
//Route::resource('order-products', OrderProductController::class);
|
||||
//Route::resource('contacts', ContactController::class);
|
||||
//Route::post('/contacts/request-destroy', [ContactController::class, 'requestDestroy'])->name('contacts.requestDestroy');
|
||||
//Route::resource('packing-slips', PackingSlipController::class);
|
||||
//Route::resource('shipping-entries', ShippingEntryController::class);
|
||||
//Route::resource('orders', OrderController::class);
|
||||
// Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
||||
// Route::get('/management/{tab?}', [ManagementController::class, 'index'])->name('management.index');
|
||||
// Route::resource('order-products', OrderProductController::class);
|
||||
// Route::resource('contacts', ContactController::class);
|
||||
// Route::post('/contacts/request-destroy', [ContactController::class, 'requestDestroy'])->name('contacts.requestDestroy');
|
||||
// Route::resource('packing-slips', PackingSlipController::class);
|
||||
// Route::resource('shipping-entries', ShippingEntryController::class);
|
||||
// Route::resource('orders', OrderController::class);
|
||||
|
@ -35,9 +35,9 @@
|
||||
|
|
||||
*/
|
||||
|
||||
//expect()->extend('toBeOne', function () {
|
||||
// expect()->extend('toBeOne', function () {
|
||||
// return $this->toBe(1);
|
||||
//});
|
||||
// });
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
26
tests/Unit/PaymentTest.php
Normal file
26
tests/Unit/PaymentTest.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use App\Filament\Admin\Resources\PaymentResource\Pages\CreatePayment;
|
||||
use App\Models\Customer;
|
||||
use App\Models\User;
|
||||
|
||||
it('can create a payment', function () {
|
||||
$user = User::factory(['is_admin' => true])->create();
|
||||
$this->actingAs($user);
|
||||
$customer = Customer::factory()->create();
|
||||
|
||||
$formData = [
|
||||
'customer_id' => $customer->id,
|
||||
'amount' => 500,
|
||||
];
|
||||
|
||||
$this->livewire(CreatePayment::class)
|
||||
->fillForm($formData)
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('payments', [
|
||||
'customer_id' => $formData['customer_id'],
|
||||
'amount' => $formData['amount'],
|
||||
]);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user