#110 Invoice Report form feedback

This commit is contained in:
Nisse Lommerde 2025-03-05 15:29:57 -05:00
parent 1192ca681b
commit aa340852e7
34 changed files with 12001 additions and 558 deletions

View File

@ -3,9 +3,11 @@
namespace App\Filament\Admin\Resources; namespace App\Filament\Admin\Resources;
use App\Enums\IconEnum; use App\Enums\IconEnum;
use App\Enums\InvoiceStatus;
use App\Filament\Admin\Resources\InvoiceReportResource\RelationManagers\InvoicesRelationManager; use App\Filament\Admin\Resources\InvoiceReportResource\RelationManagers\InvoicesRelationManager;
use App\Models\InvoiceReport; use App\Models\InvoiceReport;
use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
@ -32,28 +34,34 @@ public static function form(Form $form): Form
return $form return $form
->schema([ ->schema([
Section::make([ Section::make([
Select::make('customer_id') Group::make([
->relationship('customer', 'company_name') Select::make('customer_id')
->preload() ->relationship('customer', 'company_name')
->required() ->preload()
->searchable(), ->required()
ToggleButtons::make('filter_paid') ->columnSpanFull()
->boolean() ->searchable(),
->required()
->default(false) ToggleButtons::make('payment_types')
->colors([ ->required()
'true' => 'info', ->options(InvoiceStatus::class)
'false' => 'info', ->multiple()
]) ->columnSpanFull()
->inline(), ->inline(),
DatePicker::make('date_start')
->required(), DatePicker::make('date_start')
DatePicker::make('date_end') ->required()
->required() ->columnSpan(1),
->default(today()),
DatePicker::make('date_end')
->required()
->default(today())
->columnSpan(1),
])->columnSpan(fn (?InvoiceReport $record) => $record === null ? 5 : 3)
->columns(2),
]) ])
->columns(2) ->columns(5)
->columnSpan(2), ->columnSpan(fn ($record) => $record === null ? 3 : 2),
Section::make([ Section::make([
Placeholder::make('created_at') Placeholder::make('created_at')
@ -114,9 +122,9 @@ public static function getRelations(): array
public static function getPages(): array public static function getPages(): array
{ {
return [ return [
'index' => \App\Filament\Admin\Resources\InvoiceReportResource\Pages\ListInvoiceReports::route('/'), 'index' => \App\Filament\Admin\Resources\InvoiceReportResource\Pages\ListInvoiceReports::route('/'),
'create' => \App\Filament\Admin\Resources\InvoiceReportResource\Pages\CreateInvoiceReport::route('/create'), // 'create' => \App\Filament\Admin\Resources\InvoiceReportResource\Pages\CreateInvoiceReport::route('/create'),
'view' => \App\Filament\Admin\Resources\InvoiceReportResource\Pages\ViewInvoiceReport::route('/{record}'), 'view' => \App\Filament\Admin\Resources\InvoiceReportResource\Pages\ViewInvoiceReport::route('/{record}'),
]; ];
} }
} }

View File

@ -2,10 +2,6 @@
namespace App\Filament\Admin\Resources\InvoiceReportResource\Pages; namespace App\Filament\Admin\Resources\InvoiceReportResource\Pages;
use App\Filament\Admin\Resources\InvoiceReportResource;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateInvoiceReport extends CreateRecord class CreateInvoiceReport extends CreateRecord {}
{
protected static string $resource = InvoiceReportResource::class;
}

View File

@ -3,6 +3,7 @@
namespace App\Filament\Admin\Resources\InvoiceReportResource\Pages; namespace App\Filament\Admin\Resources\InvoiceReportResource\Pages;
use App\Enums\IconEnum; use App\Enums\IconEnum;
use App\Enums\InvoiceStatus;
use App\Filament\Admin\Resources\InvoiceReportResource; use App\Filament\Admin\Resources\InvoiceReportResource;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
@ -17,7 +18,30 @@ protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() Actions\CreateAction::make()
->icon(IconEnum::NEW->value), ->modalWidth('xl')
->icon(IconEnum::NEW->value)
->mutateFormDataUsing(function ($data) {
/* Initialize all payment statues to false,
map selected payment types to corresponding status,
assign filtered statuses to specific keys */
$paymentTypes = array_fill_keys(array_map(fn ($status) => $status->name, InvoiceStatus::cases()), false);
if (! empty($data['payment_types'])) {
foreach ($data['payment_types'] as $type) {
$statusName = InvoiceStatus::from($type)->name;
$paymentTypes[$statusName] = true;
}
}
foreach ($paymentTypes as $status => $value) {
$data['with_'.strtolower($status)] = $value;
}
unset($data['payment_types']);
return $data;
}),
]; ];
} }
} }

View File

@ -2,6 +2,7 @@
namespace App\Filament\Admin\Resources\InvoiceReportResource\Pages; namespace App\Filament\Admin\Resources\InvoiceReportResource\Pages;
use App\Enums\InvoiceStatus;
use App\Filament\Admin\Resources\InvoiceReportResource; use App\Filament\Admin\Resources\InvoiceReportResource;
use App\Models\InvoiceReport; use App\Models\InvoiceReport;
use Filament\Actions\Action; use Filament\Actions\Action;
@ -19,6 +20,19 @@ public function getTitle(): string|Htmlable
return parent::getTitle().' '.$this->record->internal_id; return parent::getTitle().' '.$this->record->internal_id;
} }
public function mutateFormDataBeforeFill(array $data): array
{
foreach (InvoiceStatus::cases() as $case) {
$name = 'with_'.strtolower($case->name);
if ($data[$name]) {
$data['payment_types'][] = $case->value ?? null;
}
}
return $data;
}
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [

View File

@ -47,65 +47,66 @@ public static function form(Form $form): Form
Group::make() Group::make()
->schema([ ->schema([
Section::make([ Section::make([
Select::make('customer_id') Group::make([
->required()
->label('Customer')
->options(Customer::all()->pluck('company_name', 'id'))
->reactive()
->searchable()
->disabledOn('edit')
->columnSpan(2),
Split::make([ Select::make('customer_id')
DatePicker::make('date')
->required() ->required()
->default(today()), ->label('Customer')
DatePicker::make('due_date'), ->options(Customer::all()->pluck('company_name', 'id'))
]) ->reactive()
->columnSpan(2), ->searchable()
->disabledOn('edit')
->columnSpan(2),
Grid::make(3) Split::make([
->schema([ DatePicker::make('date')
ToggleButtons::make('has_gst') ->required()
->label('GST') ->default(today()),
->boolean('On', 'Off') DatePicker::make('due_date'),
->default(true) ])->columnSpan(2),
Grid::make(3)
->schema([
ToggleButtons::make('has_gst')
->label('GST')
->boolean('On', 'Off')
->default(true)
// ->inline() // ->inline()
->colors([ ->colors([
'true' => 'info', 'true' => 'info',
'false' => 'info', 'false' => 'info',
]), ]),
ToggleButtons::make('has_pst') ToggleButtons::make('has_pst')
->label('PST') ->label('PST')
->boolean('On', 'Off') ->boolean('On', 'Off')
->default(false) ->default(false)
// ->inline() // ->inline()
->colors([ ->colors([
'true' => 'info', 'true' => 'info',
'false' => 'info', 'false' => 'info',
]), ]),
ToggleButtons::make('has_hst') ToggleButtons::make('has_hst')
->label('HST') ->label('HST')
->boolean('On', 'Off') ->boolean('On', 'Off')
->default(false) ->default(false)
->colors([ ->colors([
'true' => 'info', 'true' => 'info',
'false' => 'info', 'false' => 'info',
]), ]),
])->columnSpan(1), ])->columnSpan(2),
ToggleButtons::make('status')
->options(InvoiceStatus::class)
->required()
->inline()
->default(InvoiceStatus::UNPAID)
->columnSpan(1),
ToggleButtons::make('status')
->options(InvoiceStatus::class)
->required()
->inline()
->default(InvoiceStatus::UNPAID)
->columnSpan(2),
])->columnSpan(fn (?Invoice $record) => $record === null ? 2 : 1),
]) ])
->columns(2) ->columns(2)
->columnSpan(2), ->columnSpan(fn (?Invoice $record) => $record === null ? 3 : 2),
Section::make() Section::make()
->schema([ ->schema([
@ -333,9 +334,9 @@ public static function getRelations(): array
public static function getPages(): array public static function getPages(): array
{ {
return [ return [
'index' => \App\Filament\Admin\Resources\InvoiceResource\Pages\ListInvoices::route('/'), 'index' => \App\Filament\Admin\Resources\InvoiceResource\Pages\ListInvoices::route('/'),
'create' => \App\Filament\Admin\Resources\InvoiceResource\Pages\CreateInvoice::route('/create'), // 'create' => \App\Filament\Admin\Resources\InvoiceResource\Pages\CreateInvoice::route('/create'),
'edit' => \App\Filament\Admin\Resources\InvoiceResource\Pages\EditInvoice::route('/{record}/edit'), 'edit' => \App\Filament\Admin\Resources\InvoiceResource\Pages\EditInvoice::route('/{record}/edit'),
]; ];
} }
} }

View File

@ -42,6 +42,8 @@ protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() Actions\CreateAction::make()
->modal()
->modalWidth('lg')
->icon(IconEnum::NEW->value), ->icon(IconEnum::NEW->value),
]; ];
} }

View File

@ -459,12 +459,6 @@ public static function table(Table $table): Table
]); ]);
} }
public static function getRelations(): array
{
return [
];
}
public static function getPages(): array public static function getPages(): array
{ {
return [ return [

View File

@ -74,7 +74,7 @@ public function getTabs(): array
'ready_for_invoice' => Tab::make() 'ready_for_invoice' => Tab::make()
->query(fn ($query) => $query->where('status', OrderStatus::READY_FOR_INVOICE)) ->query(fn ($query) => $query->where('status', OrderStatus::READY_FOR_INVOICE))
->icon(OrderStatus::READY_FOR_INVOICE->getIcon()) ->icon(OrderStatus::READY_FOR_INVOICE->getIcon())
->badge(fn () => $this->getBadgeCount(fn ($query) => $query->where('status', OrderStatus::READY_FOR_INVOICE))) ->badge(fn () => Order::query()->where('status', OrderStatus::READY_FOR_INVOICE)->count())
->badgeColor(OrderStatus::READY_FOR_INVOICE->getColor()), ->badgeColor(OrderStatus::READY_FOR_INVOICE->getColor()),
]; ];
} }

View File

@ -8,6 +8,8 @@
use App\Filament\Admin\Resources\PaymentResource\RelationManagers\InvoicesRelationManager; use App\Filament\Admin\Resources\PaymentResource\RelationManagers\InvoicesRelationManager;
use App\Models\Payment; use App\Models\Payment;
use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea; use Filament\Forms\Components\Textarea;
@ -32,32 +34,38 @@ public static function form(Form $form): Form
return $form return $form
->schema([ ->schema([
Section::make([ Section::make([
DatePicker::make('date') Group::make([
->default(today())
->columnSpan(2),
Select::make('customer_id') Select::make('customer_id')
->relationship('customer', 'company_name') ->relationship('customer', 'company_name')
->required() ->required()
->searchable() ->searchable()
->hidden(fn ($livewire) => $livewire::class === ListInvoices::class) ->hidden(fn ($livewire) => $livewire::class === ListInvoices::class)
->preload() ->preload()
->columnSpan(2), ->columnSpanFull(),
TextInput::make('amount') TextInput::make('amount')
->required() ->required()
->prefix('$') ->prefix('$')
->rules('numeric') ->rules('numeric')
->minValue(0) ->minValue(0)
->maxValue(99999999) ->maxValue(99999999)
->columnSpan(1), ->columnSpan(3),
TextInput::make('check_number') TextInput::make('check_number')
->columnSpan(3), ->columnSpan(6),
Textarea::make('notes') DatePicker::make('date')
->columnSpan(4), ->default(today())
])->columns(4), ->columnSpan(4),
Placeholder::make('break_2')->columnSpan(3)->hiddenLabel(),
Textarea::make('notes')
->columnSpanFull(),
])->columnSpan(fn (?Payment $record) => $record === null ? 9 : 3)
->columns(9),
])->columns(9),
]); ]);
} }

View File

@ -29,6 +29,7 @@ protected function getHeaderActions(): array
}),*/ }),*/
Actions\CreateAction::make() Actions\CreateAction::make()
->modalWidth('lg')
->icon(IconEnum::NEW->value), ->icon(IconEnum::NEW->value),
]; ];
} }

View File

@ -7,6 +7,7 @@
use App\Models\Quote; use App\Models\Quote;
use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Grid; use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
@ -36,21 +37,24 @@ public static function form(Form $form): Form
Grid::make(3) Grid::make(3)
->schema([ ->schema([
Section::make([ Section::make([
Select::make('customer_id') Group::make([
->required()
->label('Customer')
->options(Customer::all()->pluck('company_name', 'id'))
->reactive()
->searchable()
->columnSpan(1),
DatePicker::make('date') Select::make('customer_id')
->default(today()) ->required()
->required(), ->label('Customer')
->options(Customer::all()->pluck('company_name', 'id'))
->reactive()
->searchable()
->columnSpan(1),
TextArea::make('notes') DatePicker::make('date')
->rows(3) ->default(today())
->columnSpan(2), ->required(),
TextArea::make('notes')
->rows(3)
->columnSpan(2),
]),
]) ])
->columns(2) ->columns(2)
->columnSpan(fn (?Quote $record) => $record === null ? 3 : 2) ->columnSpan(fn (?Quote $record) => $record === null ? 3 : 2)

View File

@ -5,7 +5,6 @@
use App\Enums\IconEnum; use App\Enums\IconEnum;
use App\Filament\Admin\Resources\TaxRateResource\Pages; use App\Filament\Admin\Resources\TaxRateResource\Pages;
use App\Models\TaxRate; use App\Models\TaxRate;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
@ -36,24 +35,8 @@ public static function form(Form $form): Form
->label('Value in percentage') ->label('Value in percentage')
->numeric() ->numeric()
->prefix('%'), ->prefix('%'),
]) ]),
->columns(1) ]);
->columnSpan(2),
Section::make()
->schema([
Placeholder::make('created_at')
->label('Created')
->content(fn (TaxRate $record): ?string => $record->created_at?->diffForHumans()),
Placeholder::make('updated_at')
->label('Last modified')
->content(fn (TaxRate $record): ?string => $record->updated_at?->diffForHumans()),
])
->columnSpan(1)
->hidden(fn (?TaxRate $record) => $record === null)
->extraAttributes(['class' => 'h-full']),
])->columns(3);
} }
public static function table(Table $table): Table public static function table(Table $table): Table
@ -70,7 +53,8 @@ public static function table(Table $table): Table
// //
]) ])
->actions([ ->actions([
Tables\Actions\EditAction::make(), Tables\Actions\EditAction::make()
->modalWidth('xs'),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkActionGroup::make([

View File

@ -15,7 +15,9 @@ protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() Actions\CreateAction::make()
->icon(IconEnum::NEW->value), ->modalWidth('xs')
->icon(IconEnum::NEW->value)
->createAnother(false),
]; ];
} }
} }

View File

@ -4,7 +4,6 @@
use App\Enums\IconEnum; use App\Enums\IconEnum;
use App\Models\User; use App\Models\User;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
@ -36,32 +35,29 @@ public static function form(Form $form): Form
->autocomplete('new-username') ->autocomplete('new-username')
->unique() ->unique()
->required() ->required()
->columnSpan(1), ->columnSpanFull(),
Grid::make(2) TextInput::make('password')
->schema([ ->password()
TextInput::make('password') ->autocomplete('new-password')
->password() ->revealable()
->autocomplete('new-password') ->dehydrated(fn ($state) => ! empty($state))
->revealable() ->required(fn (string $operation): bool => $operation === 'create'),
->dehydrated(fn ($state) => ! empty($state))
->required(fn (string $operation): bool => $operation === 'create'),
TextInput::make('password_verify') TextInput::make('password_verify')
->label('Verify password') ->label('Verify password')
->password() ->password()
->revealable() ->revealable()
->same('password') ->same('password')
->dehydrated(false) ->dehydrated(false)
->required(fn (string $operation) => $operation === 'create'), ->required(fn (string $operation) => $operation === 'create'),
])
->columnSpan(2),
]), ]),
Section::make('Permissions') Section::make('Permissions')
->description('Administrators can access financial information and change settings.') ->description('Administrators can access invoices and settings')
->schema([ ->schema([
Toggle::make('is_admin') Toggle::make('is_admin')
->columnSpanFull()
->label('User is an administrator') ->label('User is an administrator')
->reactive() ->reactive()
->afterStateUpdated(fn ($state, callable $set) => $set('customer_id', null)) ->afterStateUpdated(fn ($state, callable $set) => $set('customer_id', null))
@ -70,7 +66,7 @@ public static function form(Form $form): Form
->columns(2), ->columns(2),
Section::make('Customer Login') Section::make('Customer Login')
->description('If this account is for a customer, select them here.') ->description('If this account is for a customer, select them here')
->schema([ ->schema([
Select::make('customer_id') Select::make('customer_id')
@ -102,7 +98,9 @@ public static function table(Table $table): Table
// //
]) ])
->actions([ ->actions([
Tables\Actions\EditAction::make()->modal(), Tables\Actions\EditAction::make()
->modalWidth('md')
->modal(),
]) ])
->defaultSort('customer_id', 'asc'); ->defaultSort('customer_id', 'asc');
} }

View File

@ -15,6 +15,7 @@ protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() Actions\CreateAction::make()
->modalWidth('md')
->icon(IconEnum::NEW->value) ->icon(IconEnum::NEW->value)
->modal(), ->modal(),
]; ];

View File

@ -1,43 +0,0 @@
<?php
namespace App\Livewire;
use App\Enums\OrderStatus;
use App\Enums\OrderType;
use App\Models\Customer;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use Livewire\Component;
class CreateOrder extends Component
{
public Collection $customers;
public string $selectedCustomer;
public $contacts;
public function mount(Collection $customers): void
{
$this->customers = $customers;
$this->contacts = $customers->first()->contacts;
}
public function getContacts(): void
{
$this->contacts = Customer::find($this->selectedCustomer)->contacts;
}
public function render(): View
{
return view('livewire.create-order', [
'contacts' => $this->contacts,
'order_types' => OrderType::cases(),
'order_status' => OrderStatus::cases(),
'customers' => $this->customers,
'today' => Carbon::today()->format('Y-m-d'),
'due_default' => Carbon::today()->addDay(10)->format('Y-m-d'),
]);
}
}

View File

@ -1,41 +0,0 @@
<?php
namespace App\Livewire;
use App\Models\Customer;
use Illuminate\Support\Collection;
use Livewire\Component;
class CustomerAndContactSelect extends Component
{
public Collection $customers;
public Collection $contacts;
public string $selectedCustomer;
public function mount(Collection $customers)
{
$this->customers = $customers;
if (isset($this->selectedCustomer)) {
$this->contacts = Customer::find($this->selectedCustomer)->contacts;
} else {
$this->contacts = $customers->first()->contacts;
}
}
public function updateContactList()
{
$this->contacts = Customer::find($this->selectedCustomer)->contacts;
}
public function render()
{
return view('livewire.customer-and-contact-select', [
'customers' => $this->customers,
'contacts' => $this->contacts,
]);
}
}

View File

@ -1,172 +0,0 @@
<?php
namespace App\Livewire;
use Exception;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Application;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Livewire\Component;
class OrderProductsCreate extends Component
{
/** @var Collection<string, int> */
public Collection $productInputs;
/** @var Collection<string, int> */
public Collection $serviceInputs;
/** @var array<int> */
public array $sizes = [];
/** @var array<int> */
public array $totals = [];
/** @var array<int> */
public array $units = [];
/**
* @var array<int>
*/
public array $prices = [];
/**
* @var array<int>
*/
public array $priceTotals = [];
public int $totalQuantity = 0;
public string $totalPrice = '$0.00';
public function updated(): void
{
try {
foreach ($this->sizes as $index => $size) {
$this->totals[$index] = array_sum($size);
}
} catch (Exception $e) {
}
try {
foreach ($this->units as $index => $unit) {
$this->priceTotals[$index] = $unit * $this->prices[$index];
}
} catch (Exception $e) {
}
$this->totalQuantity = array_sum($this->totals);
$this->totalPrice = '$'.number_format(round(array_sum($this->priceTotals), 2), 2);
}
public function addProductInput(): void
{
$index = $this->productInputs->count();
$this->productInputs->push([
$index => [
'sku' => '',
'product_name' => '',
'product_color' => '',
'size_xs' => '',
'size_s' => '',
'size_m' => '',
'size_l' => '',
'size_xl' => '',
'size_2xl' => '',
'size_3xl' => '',
'size_osfa' => '',
'product_total' => '',
],
]);
}
public function determineAddProductRow(int $index): void
{
if ($index == $this->productInputs->count() - 1) {
$this->addProductInput();
}
}
public function determineAddServiceProductRow(int $index): void
{
if ($index == $this->serviceInputs->count() - 1) {
$this->addServiceInput();
}
}
public function removeProductInput(int $key): void
{
if ($this->productInputs->count() > 1) {
$this->productInputs->pull($key);
}
}
public function addServiceInput(): void
{
$this->serviceInputs->push([
$this->serviceInputs->count() => [
'service_name' => '',
'product_name' => '',
'product_color' => '',
'logo_name' => '',
'setup_number' => '',
'service_width' => '',
'service_height' => '',
'service_setup_unit' => '',
'service_setup_price' => '',
'service_total' => '',
],
]);
}
public function removeServiceInput(int $key): void
{
if ($this->serviceInputs->count() > 1) {
$this->serviceInputs->pull($key);
}
}
public function mount(): void
{
$this->fill([
'productInputs' => collect([
[
'sku' => '',
'product_name' => '',
'product_color' => '',
'size_xs' => '',
'size_s' => '',
'size_m' => '',
'size_l' => '',
'size_xl' => '',
'size_2xl' => '',
'size_3xl' => '',
'size_osfa' => '',
'product_total' => '0',
],
]),
'serviceInputs' => collect([
[
'sku' => '',
'product_name' => '',
'product_color' => '',
'logo_name' => '',
'setup_number' => '',
'service_width' => '',
'service_height' => '',
'service_setup_unit' => '',
'service_setup_price' => '',
'service_total' => '',
],
]),
]);
}
public function render(): \Illuminate\Contracts\View\View|Factory|Application|View
{
return view('livewire.order-products-create');
}
}

View File

@ -1,64 +0,0 @@
<?php
namespace App\Livewire;
use App\Models\Order;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Application;
use Illuminate\Support\Carbon;
use Illuminate\View\View;
use Livewire\Component;
use Livewire\WithPagination;
class OrdersTable extends Component
{
use WithPagination;
protected string $paginationTheme = 'bootstrap';
public bool $showCustomerColumn;
public string $orderType = 'active';
public string $search = '';
public string $title = '';
public string $customer_id = '';
public Carbon $today;
public function mount(bool $showCustomerColumn, string $orderType, string $title, ?string $customer_id = null): void
{
$this->today = Carbon::today();
$this->showCustomerColumn = $showCustomerColumn;
$this->orderType = $orderType;
$this->title = $title;
$this->customer_id = $customer_id ?? '';
}
public function render(): \Illuminate\Contracts\View\View|Factory|Application|View
{
return view('livewire.orders-table', [
'orders' => Order::with('customer')
->when($this->customer_id != null, fn ($q) => $q->where('customer_id', $this->customer_id))
->when($this->orderType === 'active', fn ($q) => $q->active())
->when($this->orderType === 'invoiced', fn ($q) => $q->invoiced())
->when($this->orderType === 'finished', fn ($q) => $q->finished())
->when($this->search !== '', function ($query) {
$query->whereHas('customer', function ($query) {
$query->where('company_name', 'like', '%'.$this->search.'%');
})->orWhere('customer_po', 'like', '%'.$this->search.'%')
->orWhere('internal_po', 'like', '%'.$this->search.'%')
->orWhere('order_date', 'like', '%'.$this->search.'%')
->orWhere('due_date', 'like', '%'.$this->search.'%')
->orWhere('status', 'like', '%'.$this->search.'%');
})
->orderByDesc('rush')
->orderBy('due_date')
->paginate(15)
->withQueryString(),
'today' => $this->today,
]);
}
}

View File

@ -56,8 +56,12 @@ class Invoice extends Model
'total' => 'float', 'total' => 'float',
]; ];
public function scopeSearchByBalance(Builder $query, float $amount): Builder public function scopeSearchByBalance(Builder $query, $amount): Builder
{ {
if (! is_numeric($amount)) {
return $query;
}
return $query->whereRaw('total - (SELECT IFNULL(SUM(applied_amount), 0) return $query->whereRaw('total - (SELECT IFNULL(SUM(applied_amount), 0)
FROM payments FROM payments
INNER JOIN invoice_payment INNER JOIN invoice_payment

View File

@ -17,8 +17,11 @@ class InvoiceReport extends Model
'customer_id', 'customer_id',
'date_start', 'date_start',
'date_end', 'date_end',
'filter_paid',
'subtotal', 'subtotal',
'with_unpaid',
'with_partially_paid',
'with_paid',
'with_void',
'pst', 'pst',
'gst', 'gst',
]; ];
@ -42,10 +45,10 @@ public static function boot(): void
$invoices = Invoice::whereBetween('date', [$model->date_start, $model->date_end]) $invoices = Invoice::whereBetween('date', [$model->date_start, $model->date_end])
->where('customer_id', $model->customer_id) ->where('customer_id', $model->customer_id)
->when($model->filter_paid, function ($query) { ->when(! $model->with_unpaid, fn ($query) => $query->whereNot('status', InvoiceStatus::UNPAID))
$query->where('status', InvoiceStatus::UNPAID) ->when(! $model->with_partially_paid, fn ($query) => $query->whereNot('status', InvoiceStatus::PARTIALLY_PAID))
->orWhere('status', InvoiceStatus::PARTIALLY_PAID); ->when(! $model->with_paid, fn ($query) => $query->whereNot('status', InvoiceStatus::PAID))
}); ->when(! $model->with_void, fn ($query) => $query->whereNot('status', InvoiceStatus::VOID));
$model->invoices()->sync($invoices->pluck('id')->toArray()); $model->invoices()->sync($invoices->pluck('id')->toArray());

11716
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,12 +14,15 @@ class InvoiceReportFactory extends Factory
public function definition(): array public function definition(): array
{ {
return [ return [
'customer_id' => Customer::all()->shuffle()->first()->id, 'customer_id' => Customer::all()->shuffle()->first()->id,
'date_start' => Carbon::now()->subYear(), 'date_start' => Carbon::now()->subYear(),
'date_end' => Carbon::now(), 'date_end' => Carbon::now(),
'filter_paid' => $this->faker->boolean(40), 'with_unpaid' => $this->faker->boolean(40),
'created_at' => Carbon::now(), 'with_partially_paid' => $this->faker->boolean(40),
'updated_at' => Carbon::now(), 'with_paid' => $this->faker->boolean(40),
'with_void' => $this->faker->boolean(40),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]; ];
} }
} }

View File

@ -11,16 +11,16 @@ public function up(): void
Schema::create('invoice_reports', function (Blueprint $table) { Schema::create('invoice_reports', function (Blueprint $table) {
$table->id(); $table->id();
$table->string('internal_id')->nullable(); $table->string('internal_id')->nullable();
$table->foreignId('customer_id')->constrained(); $table->foreignId('customer_id')->constrained();
$table->date('date_start'); $table->date('date_start');
$table->date('date_end'); $table->date('date_end');
$table->boolean('filter_paid'); $table->boolean('with_unpaid')->default(false);
$table->boolean('with_partially_paid')->default(false);
$table->boolean('with_paid')->default(false);
$table->boolean('with_void')->default(false);
$table->float('subtotal', 2)->default(0); $table->float('subtotal', 2)->default(0);
$table->float('pst', 2)->default(0); $table->float('pst', 2)->default(0);
$table->float('gst', 2)->default(0); $table->float('gst', 2)->default(0);
// $table->float('total', 2)->default(0);
$table->timestamps(); $table->timestamps();
}); });

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

View File

@ -1 +1 @@
function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},reorderTags:function(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{["x-on:blur"]:"createTag()",["x-model"]:"newTag",["x-on:keydown"](t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},["x-on:paste"](){this.$nextTick(()=>{if(n.length===0){this.createTag();return}let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default}; function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},reorderTags:function(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{"x-on:blur":"createTag()","x-model":"newTag","x-on:keydown"(t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},"x-on:paste"(){this.$nextTick(()=>{if(n.length===0){this.createTag();return}let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default};

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