Compare commits

4 Commits

Author SHA1 Message Date
1d6238e9cb Merge pull request #9 from kingjaypee12/jp/updates-on-sales
Jp/updates on sales
2026-02-18 22:58:34 +08:00
Jp
d8077f200a feat: replace Excel export with PDF export for transmittals
- Add new TransmittalPDFExportJob to generate PDFs using dompdf
- Remove old Excel export implementation (TransmittalsExport)
- Update ExportCompleteJob to use new PDF job instead of Excel
- Add TestQueueJob for queue testing with new route
- Update notification label from "Download File" to "Download PDF File"
- Fix auth() helper usage by importing Auth facade consistently
2026-02-18 22:57:34 +08:00
Jp
7899ed75ea feat(sales): add discount support with ledger accounting
- Add discount_type column to transactions table via migration
- Update Sale model to use fillable instead of guarded for better security
- Implement discount account ledger creation when discount is applied
- Fix net amount calculation to include discount in CreateSaleAction
- Remove unused "Exempt" column from sale transaction table
- Make discount_type required when discount is enabled in form
- Update form data mutation to properly handle discount calculations
2026-02-18 21:40:39 +08:00
Jp
5d427cdea4 feat: add discount management and PDF export for transmittals
- Create Discount model, migration, and Filament resource with relation to Client
- Add PDF export functionality for transmittals using DomPDF
- Include discount type selection in sales transactions
- Fix account filtering logic in expense resource
- Update export job to generate PDF instead of Excel
2026-02-18 01:42:44 +08:00
27 changed files with 904 additions and 298 deletions

11
.devdbrc Normal file
View File

@@ -0,0 +1,11 @@
[
{
"name": "My test MySQL database",
"type": "mysql",
"host": "192.168.100.105",
"port": "3306",
"username": "root",
"password": "root",
"database": "mkm_admin"
}
]

View File

@@ -24,7 +24,6 @@ class CreateSaleAction
try {
DB::beginTransaction();
//create transactions for the sale
app(CreateRecordTransactionsAction::class)($record, $transactions);

View File

@@ -24,6 +24,10 @@ class CreateTransactionAction extends BaseAction
$this->cashAccountLedger($payload);
if ($payload->transaction->discount !== 0) {
$this->discountAccountLedger($payload);
}
return $next($payload);
}
@@ -33,11 +37,13 @@ class CreateTransactionAction extends BaseAction
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
$type = $isExpense ? 'debit' : 'credit';
$discount = $payload->transaction->discount ?? 0.00;
if ($branch->isClientVatable) {
//create transaction account ledger
$ledgerPayload = new CreateLedgerDTO(
branch_id: $payload->transactionable->branch_id,
amount: $payload->transaction->net_amount ?? 0.00,
amount: $payload->transaction->net_amount + $discount ?? 0.00,
transaction: $payload->transaction,
account: $payload->transaction->account,
type: $type,
@@ -144,4 +150,28 @@ class CreateTransactionAction extends BaseAction
$this->ledgerPipe($ledgerPayload);
}
}
public function discountAccountLedger($payload): void
{
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
$type = $isExpense ? 'credit' : 'debit';
$amount = $payload->transaction->discount ?? 0.00;
$clientId = $payload->transactionable->branch->client_id;
$discountAccount = Account::query()
->where('account', 'Sales Discount')
->where('client_id', $clientId)
->first();
if ($discountAccount && $amount > 0) {
$ledgerPayload = new CreateLedgerDTO(
branch_id: $payload->transactionable->branch_id,
amount: $amount,
transaction: $payload->transaction,
account: $discountAccount,
type: $type,
);
$this->ledgerPipe($ledgerPayload);
}
}
}

View File

@@ -1,144 +0,0 @@
<?php
namespace App\Exports;
use App\Models\Transmittal;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\View;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Style;
class TransmittalsExport implements FromCollection, ShouldAutoSize, ShouldQueue, WithDefaultStyles, WithHeadings, WithMapping
{
use Exportable, Queueable, SerializesModels;
public function __construct(
private readonly array $id
) {}
public function view(): \Illuminate\Contracts\View\View
{
$transmittals = Transmittal::query()->with(['client', 'branch', 'files.notes', 'files.remarks'])->whereIn('id', Arr::flatten($this->id))->get();
return View::make('transmittal.export.transmittal-export-table')->with(['transmittals' => $transmittals]);
}
/**
* @throws Exception
*/
public function defaultStyles(Style $defaultStyle)
{
return $defaultStyle->applyFromArray([
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
]);
}
public function headings(): array
{
return [
'series',
'files',
'notes',
'remarks',
];
}
public function collection()
{
$transmittals = Transmittal::query()->with(['client', 'branch', 'files.notes', 'files.remarks'])
->withCount(['files', 'notes', 'remarks'])->with(['files' => function ($files) {
$files->withCount(['notes', 'remarks']);
}])
->whereIn('id', Arr::flatten($this->id))->get();
return $transmittals;
}
public function map($transmittal): array
{
$data = [];
$firstFile = $transmittal->files->first();
$data[] = [
$transmittal->series,
$firstFile?->description,
$firstFile->notes->first()?->comment,
$firstFile->remarks->first()?->remark,
];
//iterate comments and remarks for first file
$notes = $firstFile->notes->pluck('comment');
$remarks = $firstFile->remarks->pluck('remark');
$fileNoteCount = count($notes);
$fileRemarkCount = count($remarks);
$fileRowCount = $fileNoteCount;
if ($fileRemarkCount > $fileNoteCount) {
$fileRowCount = $fileRemarkCount;
}
for ($i = 1; $i < $fileRowCount; $i++) {
$data[] = [
'',
'',
$notes[$i] ?? '',
$remarks[$i] ?? '',
];
}
//file iteration except for first file
$fileRowCounter = 0;
foreach ($transmittal->files as $file) {
$notes = $file->notes->pluck('comment');
$remarks = $file->remarks->pluck('remark');
$fileNoteCount = count($notes);
$fileRemarkCount = count($remarks);
$fileRowCount = $fileNoteCount;
if ($fileRemarkCount > $fileNoteCount) {
$fileRowCount = $fileRemarkCount;
}
if ($fileRowCounter != 0) {
$data[] = [
'',
$file->description,
$file->notes->first()?->comment ?? '',
$file->remarks->first()?->remark ?? '',
];
//iterate for remaining notes and remarks
for ($i = 1; $i < $fileRowCount; $i++) {
$data[] = [
'',
'',
$notes[$i] ?? '',
$remarks[$i] ?? '',
];
}
}
$fileRowCounter++;
}
return $data;
}
}

View File

@@ -10,6 +10,7 @@ use App\Filament\Resources\ClientResource\Pages\GeneralLedger;
use App\Filament\Resources\ClientResource\Pages\TrialBalance;
use App\Filament\Resources\ClientResource\RelationManagers\AccountsRelationManager;
use App\Filament\Resources\ClientResource\RelationManagers\BranchesRelationManager;
use App\Filament\Resources\ClientResource\RelationManagers\DiscountRelationManager;
use App\Filament\Resources\ClientResource\RelationManagers\ExpensesRelationManager;
use App\Filament\Resources\ClientResource\RelationManagers\JournalsRelationManager;
use App\Filament\Resources\ClientResource\RelationManagers\SalesRelationManager;
@@ -109,6 +110,7 @@ class ClientResource extends Resource
SalesRelationManager::class,
ExpensesRelationManager::class,
JournalsRelationManager::class,
DiscountRelationManager::class,
];
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Filament\Resources\ClientResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class DiscountRelationManager extends RelationManager
{
protected static string $relationship = 'discounts';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('discount')
->required()
->maxLength(255),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('discount')
->columns([
Tables\Columns\TextColumn::make('discount'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\DiscountResource\Pages;
use App\Filament\Resources\DiscountResource\RelationManagers;
use App\Models\Discount;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class DiscountResource extends Resource
{
protected static ?string $model = Discount::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static bool $shouldRegisterNavigation = false;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('discount')
->label('Discount')
->required(),
Forms\Components\Hidden::make('client_id')
->default(fn () => request()->client_id),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('discount')
->label('Discount')
->searchable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListDiscounts::route('/'),
'create' => Pages\CreateDiscount::route('/create'),
'edit' => Pages\EditDiscount::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\DiscountResource\Pages;
use App\Filament\Resources\DiscountResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateDiscount extends CreateRecord
{
protected static string $resource = DiscountResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DiscountResource\Pages;
use App\Filament\Resources\DiscountResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditDiscount extends EditRecord
{
protected static string $resource = DiscountResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DiscountResource\Pages;
use App\Filament\Resources\DiscountResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListDiscounts extends ListRecords
{
protected static string $resource = DiscountResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -195,11 +195,11 @@ class ExpenseResource extends Resource
'client_id' => $get('../../client'),
]);
if ($get('../../branch_id')) {
$query->whereHas('balances', function ($query) use ($get) {
return $query->where('branch_id', $get('../../branch_id'));
});
}
// if ($get('../../branch_id')) {
// $query->whereHas('balances', function ($query) use ($get) {
// return $query->where('branch_id', $get('../../branch_id'));
// });
// }
$query->whereHas('accountType', function ($query) {
return $query->where('type', 'Expenses');
@@ -208,7 +208,6 @@ class ExpenseResource extends Resource
return $query->get()->pluck('account', 'id');
}
#[NoReturn]
public static function setDefaultFormValues(Get $get, Set $set, ?string $old, ?string $state): void
{

View File

@@ -6,6 +6,7 @@ use App\Filament\Resources\SaleResource\Pages;
use App\Models\Account;
use App\Models\Branch;
use App\Models\Client;
use App\Models\Discount;
use App\Models\Sale;
use Awcodes\TableRepeater\Components\TableRepeater;
use Awcodes\TableRepeater\Header;
@@ -30,17 +31,17 @@ class SaleResource extends Resource
protected static bool $shouldRegisterNavigation = false;
public static function form(Form $form): Form
{
return $form
->schema([
Select::make('client')
->default(request()->query('client_id'))
->default(fn () => request()->integer('client_id'))
->options(Client::query()->get()->pluck('company', 'id'))
->afterStateUpdated(function ($set, $get) {
$set('branch_id', '');
})
->disabled()
->required()
->live(),
Select::make('branch_id')
@@ -72,6 +73,8 @@ class SaleResource extends Resource
]);
}
public static function getSeries(Get $get): string
{
$branch = Branch::find($get('branch_id'));
@@ -93,11 +96,12 @@ class SaleResource extends Resource
Header::make('Charge Account'),
Header::make('Description'),
Header::make('Gross Amount'),
Header::make('Exempt'),
// Header::make('Exempt'),
Header::make('Vatable Amount'),
Header::make('Output Tax'),
Header::make('Withholding Tax'),
Header::make('Discount'),
Header::make('Discount Type'),
Header::make('Net Amount'),
];
}
@@ -106,7 +110,7 @@ class SaleResource extends Resource
Header::make('Charge Account'),
Header::make('Description'),
Header::make('Gross Amount'),
Header::make('Exempt'),
// Header::make('Exempt'),
Header::make('Vatable Amount'),
Header::make('Output Tax'),
Header::make('Withholding Tax'),
@@ -129,6 +133,7 @@ class SaleResource extends Resource
TextInput::make('exempt')
->numeric()
->live()
->hidden()
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
static::setDefaultFormValues($get, $set, $old, $state);
})->default(0),
@@ -136,7 +141,7 @@ class SaleResource extends Resource
->numeric()
->nullable()
->live()
->readOnly()
->readOnly(fn (Get $get) => $get('exempt') == 0)
->default(0),
Hidden::make('happened_on')->default(fn (Get $get) => $get('../../happened_on')),
Hidden::make('with_discount')->default(fn (Get $get) => $get('../../with_discount')),
@@ -151,14 +156,17 @@ class SaleResource extends Resource
->numeric()
->live()
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
static::setDefaultFormValues($get, $set, $old, $state);
})->default(0),
TextInput::make('discount')
->numeric()
->readOnly()
// ->readOnly()
->visible(fn (Get $get) => $get('../../with_discount'))
->live(),
Select::make('discount_type')
->options(fn (Get $get) => static::getDiscountOptions($get))
->required(fn (Get $get) => $get('../../with_discount'))
->visible(fn (Get $get) => $get('../../with_discount')),
TextInput::make('net_amount')->numeric()->default(0),
];
}
@@ -184,6 +192,13 @@ class SaleResource extends Resource
return $query->get()->pluck('account', 'id');
}
private static function getDiscountOptions(Get $get)
{
$query = Discount::query()->where('client_id', $get('../../client'));
return $query->pluck('discount', 'id');
}
private static function setDefaultFormValues(Get $get, Set $set, ?string $old, ?string $state)
{
$exempt = (float) $get('exempt');
@@ -211,7 +226,7 @@ class SaleResource extends Resource
}
$set('output_tax', number_format($outputTax, 2, '.', ''));
$set('discount', number_format($discount, 2, '.', ''));
// $set('discount', number_format($discount, 2, '.', ''));
$set('vatable_amount', number_format($vatableAmount, 2, '.', ''));
$set('net_amount', number_format($netAmount, 2, '.', ''));
}

View File

@@ -76,10 +76,11 @@ class CreateSale extends CreateRecord
$data['vatable_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['vatable_amount'] ?? 0));
$data['output_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['output_tax'] ?? 0));
$data['payable_withholding_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['payable_withholding_tax'] ?? 0));
$data['discount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['discount'] ?? 0));
$data['net_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['net_amount'] ?? 0));
$discount = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['discount'] ?? 0));
$data['discount'] = $discount;
$data['net_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['net_amount'] ?? 0)) + $discount;
return Arr::except($data, ['client', 'transactions', 'with_discount']);
return Arr::except($data, ['client', 'transactions']);
}
public function processCreate(array $data, array $transactions): Model

View File

@@ -4,9 +4,9 @@ namespace App\Filament\Resources;
use App\Commands\Transmittal\GenerateTransmittalSeries;
use App\Commands\Transmittal\StoreTransmittalCommand;
use App\Exports\TransmittalsExport;
use App\Filament\Resources\TransmittalResource\Pages;
use App\Jobs\ExportCompleteJob;
use App\Jobs\TransmittalPDFExportJob;
use App\Models\Branch;
use App\Models\Client;
use App\Models\Transmittal;
@@ -26,6 +26,7 @@ use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Malzariey\FilamentDaterangepickerFilter\Filters\DateRangeFilter;
class TransmittalResource extends Resource
@@ -112,7 +113,7 @@ class TransmittalResource extends Resource
public static function getTableActions(): array
{
return [
Tables\Actions\Action::make('Export')->action(fn ($record) => static::exportTransmittal([$record->id])),
Tables\Actions\Action::make('Export')->label('Export as PDF')->action(fn ($record) => static::exportTransmittal([$record->id])),
Tables\Actions\ViewAction::make(),
Tables\Actions\Action::make('Update Status')
->fillForm(function ($record) {
@@ -139,7 +140,7 @@ class TransmittalResource extends Resource
})
->icon('heroicon-o-pencil-square')
->slideOver()
->hidden(! auth()->user()->can('update_transmittal')),
->hidden(! Auth::user()->can('update_transmittal')),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
];
@@ -147,13 +148,11 @@ class TransmittalResource extends Resource
public static function exportTransmittal(array $id): void
{
$recipient = auth()->user();
$recipient = Auth::user();
static::generateExportNotification();
(new TransmittalsExport([$id]))->store('public/transmittal-export.xlsx')->chain([
app(ExportCompleteJob::class, ['user' => $recipient]),
]);
dispatch(new TransmittalPDFExportJob($recipient, $id));
}
public static function generateExportNotification(): Notification

View File

@@ -2,6 +2,8 @@
namespace App\Jobs;
use App\Models\Transmittal;
use Barryvdh\DomPDF\Facade\Pdf;
use Filament\Notifications\Actions\Action as NotificationAction;
use Filament\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -13,30 +15,37 @@ use Illuminate\Support\Facades\Storage;
class ExportCompleteJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Create a new job instance.
*/
public function __construct(private $user)
public function __construct(private $user, private array $ids)
{
}
/**
* Execute the job.
*/
public function handle(): void
{
Notification::make()->success()
$transmittals = Transmittal::query()
->with(['client', 'branch', 'files.notes', 'files.remarks'])
->whereIn('id', $this->ids)
->get();
$pdf = Pdf::loadView('transmittal.export.transmittal-export-pdf', [
'transmittals' => $transmittals,
]);
Storage::disk('public')->put('transmittal-export.pdf', $pdf->output());
Notification::make()
->success()
->title('Export Completed')
->actions([
NotificationAction::make('download_transmittal-export.xlsx')
->label('Download File')
->url(url: Storage::url('public/transmittal-export.xlsx') ,shouldOpenInNewTab: true)
->markAsRead(),
]
)
NotificationAction::make('download_transmittal-export.pdf')
->label('Download PDF File')
->url(Storage::url('transmittal-export.pdf'), true)
->markAsRead(),
])
->sendToDatabase($this->user);
}
}

28
app/Jobs/TestQueueJob.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class TestQueueJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public function __construct()
{
}
public function handle(): void
{
Log::info('TestQueueJob executed');
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Jobs;
use App\Models\Transmittal;
use Barryvdh\DomPDF\Facade\Pdf;
use Filament\Forms\Components\Actions;
use Filament\Notifications\Livewire\Notifications;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
class TransmittalPDFExportJob implements ShouldQueue
{
use Queueable, Dispatchable, InteractsWithQueue, SerializesModels;
/**
* Create a new job instance.
*/
public function __construct(private $user, private array $ids)
{}
/**
* Execute the job.
*/
public function handle(): void
{
$transmittals = Transmittal::query()
->with(['client', 'branch', 'files.notes', 'files.remarks'])
->whereIn('id', $this->ids)
->get();
$pdf = Pdf::loadView('transmittal.export.transmittal-export-pdf', [
'transmittals' => $transmittals,
]);
Storage::disk('public')->put('transmittal-export.pdf', $pdf->output());
Notifications::make()
->success()
->title('Export Completed')
->actions([
Actions\Action::make('download_transmittal-export.pdf')
->label('Download PDF File')
->url(Storage::url('transmittal-export.pdf'), true)
->markAsRead(),
])
->sendToDatabase($this->user);
}
}

View File

@@ -78,4 +78,9 @@ class Client extends Model
{
return $this->hasManyThrough(Journal::class, Branch::class);
}
public function discounts(): HasMany
{
return $this->hasMany(Discount::class);
}
}

10
app/Models/Discount.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Discount extends Model
{
protected $fillable = ['discount'];
}

View File

@@ -12,7 +12,14 @@ class Sale extends Model
{
use HasFactory;
protected $guarded = [];
protected $fillable = [
'branch_id',
'user_id',
'client_id',
'happened_on',
'reference_number',
'buyer'
];
protected $casts = [
'happened_on' => 'date:Y-m-d',

View File

@@ -18,6 +18,7 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
@@ -45,7 +46,7 @@ class AdminPanelProvider extends PanelProvider
->url(fn (): string => url(config('horizon.path')))
->icon('heroicon-o-queue-list')
->group('System')
->visible(fn (): bool => auth()->user()?->hasRole('super_admin') ?? false),
->visible(fn (): bool => Auth::user()?->hasRole('super_admin') ?? false),
])
->databaseNotifications()
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')

View File

@@ -10,6 +10,7 @@
"require": {
"php": "^8.2",
"awcodes/filament-table-repeater": "^3.0",
"barryvdh/laravel-dompdf": "^2.0",
"bezhansalleh/filament-shield": "^3.2",
"filament/filament": "^3.2",
"laravel/framework": "^11.9",

510
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "60653f82a7ab603cb6e06b89358e7eec",
"content-hash": "129ac831ea23f38c47c3ba81e3f7e133",
"packages": [
{
"name": "anourvalar/eloquent-serialize",
@@ -147,6 +147,83 @@
],
"time": "2026-01-06T23:41:22+00:00"
},
{
"name": "barryvdh/laravel-dompdf",
"version": "v2.2.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
"reference": "c96f90c97666cebec154ca1ffb67afed372114d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/c96f90c97666cebec154ca1ffb67afed372114d8",
"reference": "c96f90c97666cebec154ca1ffb67afed372114d8",
"shasum": ""
},
"require": {
"dompdf/dompdf": "^2.0.7",
"illuminate/support": "^6|^7|^8|^9|^10|^11",
"php": "^7.2 || ^8.0"
},
"require-dev": {
"larastan/larastan": "^1.0|^2.7.0",
"orchestra/testbench": "^4|^5|^6|^7|^8|^9",
"phpro/grumphp": "^1 || ^2.5",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
},
"providers": [
"Barryvdh\\DomPDF\\ServiceProvider"
]
},
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\DomPDF\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "A DOMPDF Wrapper for Laravel",
"keywords": [
"dompdf",
"laravel",
"pdf"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v2.2.0"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2024-04-25T13:16:04+00:00"
},
{
"name": "bezhansalleh/filament-shield",
"version": "3.9.10",
@@ -1170,6 +1247,68 @@
],
"time": "2024-02-05T11:56:58+00:00"
},
{
"name": "dompdf/dompdf",
"version": "v2.0.8",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "c20247574601700e1f7c8dab39310fca1964dc52"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/c20247574601700e1f7c8dab39310fca1964dc52",
"reference": "c20247574601700e1f7c8dab39310fca1964dc52",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-mbstring": "*",
"masterminds/html5": "^2.0",
"phenx/php-font-lib": ">=0.5.4 <1.0.0",
"phenx/php-svg-lib": ">=0.5.2 <1.0.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"ext-json": "*",
"ext-zip": "*",
"mockery/mockery": "^1.3",
"phpunit/phpunit": "^7.5 || ^8 || ^9",
"squizlabs/php_codesniffer": "^3.5"
},
"suggest": {
"ext-gd": "Needed to process images",
"ext-gmagick": "Improves image processing performance",
"ext-imagick": "Improves image processing performance",
"ext-zlib": "Needed for pdf stream compression"
},
"type": "library",
"autoload": {
"psr-4": {
"Dompdf\\": "src/"
},
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "The Dompdf Community",
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"support": {
"issues": "https://github.com/dompdf/dompdf/issues",
"source": "https://github.com/dompdf/dompdf/tree/v2.0.8"
},
"time": "2024-04-29T13:06:17+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.6.0",
@@ -2817,16 +2956,16 @@
},
{
"name": "laravel/tinker",
"version": "v2.11.0",
"version": "v2.11.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/tinker.git",
"reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468"
"reference": "c9f80cc835649b5c1842898fb043f8cc098dd741"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468",
"reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468",
"url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741",
"reference": "c9f80cc835649b5c1842898fb043f8cc098dd741",
"shasum": ""
},
"require": {
@@ -2877,9 +3016,9 @@
],
"support": {
"issues": "https://github.com/laravel/tinker/issues",
"source": "https://github.com/laravel/tinker/tree/v2.11.0"
"source": "https://github.com/laravel/tinker/tree/v2.11.1"
},
"time": "2025-12-19T19:16:45+00:00"
"time": "2026-02-06T14:12:35+00:00"
},
{
"name": "league/commonmark",
@@ -3533,16 +3672,16 @@
},
{
"name": "livewire/livewire",
"version": "v3.7.9",
"version": "v3.7.10",
"source": {
"type": "git",
"url": "https://github.com/livewire/livewire.git",
"reference": "112b27e41e87e89d828a96e37b257aff2a058c7a"
"reference": "0dc679eb4c8b4470cb12522b5927ef08ca2358bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/livewire/livewire/zipball/112b27e41e87e89d828a96e37b257aff2a058c7a",
"reference": "112b27e41e87e89d828a96e37b257aff2a058c7a",
"url": "https://api.github.com/repos/livewire/livewire/zipball/0dc679eb4c8b4470cb12522b5927ef08ca2358bb",
"reference": "0dc679eb4c8b4470cb12522b5927ef08ca2358bb",
"shasum": ""
},
"require": {
@@ -3597,7 +3736,7 @@
"description": "A front-end framework for Laravel.",
"support": {
"issues": "https://github.com/livewire/livewire/issues",
"source": "https://github.com/livewire/livewire/tree/v3.7.9"
"source": "https://github.com/livewire/livewire/tree/v3.7.10"
},
"funding": [
{
@@ -3605,7 +3744,7 @@
"type": "github"
}
],
"time": "2026-02-05T23:27:27+00:00"
"time": "2026-02-09T22:49:33+00:00"
},
{
"name": "livewire/volt",
@@ -4353,16 +4492,16 @@
},
{
"name": "nette/utils",
"version": "v4.1.2",
"version": "v4.1.3",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5"
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
"url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe",
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe",
"shasum": ""
},
"require": {
@@ -4374,8 +4513,10 @@
},
"require-dev": {
"jetbrains/phpstorm-attributes": "^1.2",
"nette/phpstan-rules": "^1.0",
"nette/tester": "^2.5",
"phpstan/phpstan": "^2.0@stable",
"phpstan/extension-installer": "^1.4@stable",
"phpstan/phpstan": "^2.1@stable",
"tracy/tracy": "^2.9"
},
"suggest": {
@@ -4436,9 +4577,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.1.2"
"source": "https://github.com/nette/utils/tree/v4.1.3"
},
"time": "2026-02-03T17:21:09+00:00"
"time": "2026-02-13T03:05:33+00:00"
},
{
"name": "nikic/php-parser",
@@ -4500,31 +4641,31 @@
},
{
"name": "nunomaduro/termwind",
"version": "v2.3.3",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
"reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017"
"reference": "712a31b768f5daea284c2169a7d227031001b9a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017",
"reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8",
"reference": "712a31b768f5daea284c2169a7d227031001b9a8",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.2",
"symfony/console": "^7.3.6"
"symfony/console": "^7.4.4 || ^8.0.4"
},
"require-dev": {
"illuminate/console": "^11.46.1",
"laravel/pint": "^1.25.1",
"illuminate/console": "^11.47.0",
"laravel/pint": "^1.27.1",
"mockery/mockery": "^1.6.12",
"pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3",
"pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2",
"phpstan/phpstan": "^1.12.32",
"phpstan/phpstan-strict-rules": "^1.6.2",
"symfony/var-dumper": "^7.3.5",
"symfony/var-dumper": "^7.3.5 || ^8.0.4",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
@@ -4556,7 +4697,7 @@
"email": "enunomaduro@gmail.com"
}
],
"description": "Its like Tailwind CSS, but for the console.",
"description": "It's like Tailwind CSS, but for the console.",
"keywords": [
"cli",
"console",
@@ -4567,7 +4708,7 @@
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
"source": "https://github.com/nunomaduro/termwind/tree/v2.3.3"
"source": "https://github.com/nunomaduro/termwind/tree/v2.4.0"
},
"funding": [
{
@@ -4583,7 +4724,7 @@
"type": "github"
}
],
"time": "2025-11-20T02:34:59+00:00"
"time": "2026-02-16T23:10:27+00:00"
},
{
"name": "openspout/openspout",
@@ -4678,6 +4819,96 @@
],
"time": "2025-09-03T16:03:54+00:00"
},
{
"name": "phenx/php-font-lib",
"version": "0.5.6",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-font-lib.git",
"reference": "a1681e9793040740a405ac5b189275059e2a9863"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a1681e9793040740a405ac5b189275059e2a9863",
"reference": "a1681e9793040740a405ac5b189275059e2a9863",
"shasum": ""
},
"require": {
"ext-mbstring": "*"
},
"require-dev": {
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
},
"type": "library",
"autoload": {
"psr-4": {
"FontLib\\": "src/FontLib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Fabien Ménager",
"email": "fabien.menager@gmail.com"
}
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/PhenX/php-font-lib",
"support": {
"issues": "https://github.com/dompdf/php-font-lib/issues",
"source": "https://github.com/dompdf/php-font-lib/tree/0.5.6"
},
"time": "2024-01-29T14:45:26+00:00"
},
{
"name": "phenx/php-svg-lib",
"version": "0.5.4",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-svg-lib.git",
"reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/46b25da81613a9cf43c83b2a8c2c1bdab27df691",
"reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabberworm/php-css-parser": "^8.4"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Svg\\": "src/Svg"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "Fabien Ménager",
"email": "fabien.menager@gmail.com"
}
],
"description": "A library to read, parse and export to PDF SVG files.",
"homepage": "https://github.com/PhenX/php-svg-lib",
"support": {
"issues": "https://github.com/dompdf/php-svg-lib/issues",
"source": "https://github.com/dompdf/php-svg-lib/tree/0.5.4"
},
"time": "2024-04-08T12:52:34+00:00"
},
{
"name": "phpdocumentor/reflection",
"version": "6.4.4",
@@ -5618,16 +5849,16 @@
},
{
"name": "psy/psysh",
"version": "v0.12.19",
"version": "v0.12.20",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
"reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee"
"reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/a4f766e5c5b6773d8399711019bb7d90875a50ee",
"reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/19678eb6b952a03b8a1d96ecee9edba518bb0373",
"reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373",
"shasum": ""
},
"require": {
@@ -5691,9 +5922,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.12.19"
"source": "https://github.com/bobthecow/psysh/tree/v0.12.20"
},
"time": "2026-01-30T17:33:13+00:00"
"time": "2026-02-11T15:05:28+00:00"
},
{
"name": "pxlrbt/filament-excel",
@@ -6038,6 +6269,72 @@
],
"time": "2025-02-25T09:09:36+00:00"
},
{
"name": "sabberworm/php-css-parser",
"version": "v8.9.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"require-dev": {
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
"rawr/cross-data-providers": "^2.0.0"
},
"suggest": {
"ext-mbstring": "for parsing UTF-8 CSS"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "9.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Sabberworm\\CSS\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Raphael Schweikert"
},
{
"name": "Oliver Klee",
"email": "github@oliverklee.de"
},
{
"name": "Jake Hotson",
"email": "jake.github@qzdesign.co.uk"
}
],
"description": "Parser for CSS Files written in PHP",
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
"keywords": [
"css",
"parser",
"stylesheet"
],
"support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0"
},
"time": "2025-07-11T13:20:48+00:00"
},
{
"name": "spatie/color",
"version": "1.8.0",
@@ -6301,16 +6598,16 @@
},
{
"name": "spatie/laravel-permission",
"version": "6.24.0",
"version": "6.24.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-permission.git",
"reference": "76adb1fc8d07c16a0721c35c4cc330b7a12598d7"
"reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/76adb1fc8d07c16a0721c35c4cc330b7a12598d7",
"reference": "76adb1fc8d07c16a0721c35c4cc330b7a12598d7",
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/eefc9d17eba80d023d6bff313f882cb2bcd691a3",
"reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3",
"shasum": ""
},
"require": {
@@ -6372,7 +6669,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-permission/issues",
"source": "https://github.com/spatie/laravel-permission/tree/6.24.0"
"source": "https://github.com/spatie/laravel-permission/tree/6.24.1"
},
"funding": [
{
@@ -6380,7 +6677,7 @@
"type": "github"
}
],
"time": "2025-12-13T21:45:21+00:00"
"time": "2026-02-09T21:10:03+00:00"
},
{
"name": "spatie/php-structure-discoverer",
@@ -9676,7 +9973,7 @@
},
{
"name": "illuminate/json-schema",
"version": "v12.50.0",
"version": "v12.52.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/json-schema.git",
@@ -9783,16 +10080,16 @@
},
{
"name": "laravel/boost",
"version": "v2.1.1",
"version": "v2.1.7",
"source": {
"type": "git",
"url": "https://github.com/laravel/boost.git",
"reference": "1c7d6f44c96937a961056778b9143218b1183302"
"reference": "3f999986f9dc0f1faa9a6607739e938d551e27df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/boost/zipball/1c7d6f44c96937a961056778b9143218b1183302",
"reference": "1c7d6f44c96937a961056778b9143218b1183302",
"url": "https://api.github.com/repos/laravel/boost/zipball/3f999986f9dc0f1faa9a6607739e938d551e27df",
"reference": "3f999986f9dc0f1faa9a6607739e938d551e27df",
"shasum": ""
},
"require": {
@@ -9803,7 +10100,7 @@
"illuminate/support": "^11.45.3|^12.41.1",
"laravel/mcp": "^0.5.1",
"laravel/prompts": "^0.3.10",
"laravel/roster": "^0.2.9",
"laravel/roster": "^0.4.0",
"php": "^8.2"
},
"require-dev": {
@@ -9845,7 +10142,7 @@
"issues": "https://github.com/laravel/boost/issues",
"source": "https://github.com/laravel/boost"
},
"time": "2026-02-06T10:41:29+00:00"
"time": "2026-02-18T12:19:28+00:00"
},
{
"name": "laravel/breeze",
@@ -9910,16 +10207,16 @@
},
{
"name": "laravel/mcp",
"version": "v0.5.5",
"version": "v0.5.9",
"source": {
"type": "git",
"url": "https://github.com/laravel/mcp.git",
"reference": "b3327bb75fd2327577281e507e2dbc51649513d6"
"reference": "39e8da60eb7bce4737c5d868d35a3fe78938c129"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/mcp/zipball/b3327bb75fd2327577281e507e2dbc51649513d6",
"reference": "b3327bb75fd2327577281e507e2dbc51649513d6",
"url": "https://api.github.com/repos/laravel/mcp/zipball/39e8da60eb7bce4737c5d868d35a3fe78938c129",
"reference": "39e8da60eb7bce4737c5d868d35a3fe78938c129",
"shasum": ""
},
"require": {
@@ -9979,20 +10276,20 @@
"issues": "https://github.com/laravel/mcp/issues",
"source": "https://github.com/laravel/mcp"
},
"time": "2026-02-05T14:05:18+00:00"
"time": "2026-02-17T19:05:53+00:00"
},
{
"name": "laravel/pint",
"version": "v1.27.0",
"version": "v1.27.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90"
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90",
"reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90",
"url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
"shasum": ""
},
"require": {
@@ -10003,13 +10300,13 @@
"php": "^8.2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.92.4",
"illuminate/view": "^12.44.0",
"larastan/larastan": "^3.8.1",
"laravel-zero/framework": "^12.0.4",
"friendsofphp/php-cs-fixer": "^3.93.1",
"illuminate/view": "^12.51.0",
"larastan/larastan": "^3.9.2",
"laravel-zero/framework": "^12.0.5",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3.3",
"pestphp/pest": "^3.8.4"
"pestphp/pest": "^3.8.5"
},
"bin": [
"builds/pint"
@@ -10046,35 +10343,35 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2026-01-05T16:49:17+00:00"
"time": "2026-02-10T20:00:20+00:00"
},
{
"name": "laravel/roster",
"version": "v0.2.9",
"version": "v0.4.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/roster.git",
"reference": "82bbd0e2de614906811aebdf16b4305956816fa6"
"reference": "77e6c1187952d0eef50a54922db47893f5e7c986"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/roster/zipball/82bbd0e2de614906811aebdf16b4305956816fa6",
"reference": "82bbd0e2de614906811aebdf16b4305956816fa6",
"url": "https://api.github.com/repos/laravel/roster/zipball/77e6c1187952d0eef50a54922db47893f5e7c986",
"reference": "77e6c1187952d0eef50a54922db47893f5e7c986",
"shasum": ""
},
"require": {
"illuminate/console": "^10.0|^11.0|^12.0",
"illuminate/contracts": "^10.0|^11.0|^12.0",
"illuminate/routing": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"php": "^8.1|^8.2",
"symfony/yaml": "^6.4|^7.2"
"illuminate/console": "^11.0|^12.0|^13.0",
"illuminate/contracts": "^11.0|^12.0|^13.0",
"illuminate/routing": "^11.0|^12.0|^13.0",
"illuminate/support": "^11.0|^12.0|^13.0",
"php": "^8.2",
"symfony/yaml": "^7.2|^8.0"
},
"require-dev": {
"laravel/pint": "^1.14",
"mockery/mockery": "^1.6",
"orchestra/testbench": "^8.22.0|^9.0|^10.0",
"pestphp/pest": "^2.0|^3.0",
"orchestra/testbench": "^9.0|^10.0|^11.0",
"pestphp/pest": "^3.0|^4.1",
"phpstan/phpstan": "^2.0"
},
"type": "library",
@@ -10107,32 +10404,32 @@
"issues": "https://github.com/laravel/roster/issues",
"source": "https://github.com/laravel/roster"
},
"time": "2025-10-20T09:56:46+00:00"
"time": "2026-02-11T07:24:41+00:00"
},
{
"name": "laravel/sail",
"version": "v1.52.0",
"version": "v1.53.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/sail.git",
"reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3"
"reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3",
"reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3",
"url": "https://api.github.com/repos/laravel/sail/zipball/e340eaa2bea9b99192570c48ed837155dbf24fbb",
"reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb",
"shasum": ""
},
"require": {
"illuminate/console": "^9.52.16|^10.0|^11.0|^12.0",
"illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0",
"illuminate/support": "^9.52.16|^10.0|^11.0|^12.0",
"illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0",
"illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0",
"illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0",
"php": "^8.0",
"symfony/console": "^6.0|^7.0",
"symfony/yaml": "^6.0|^7.0"
"symfony/console": "^6.0|^7.0|^8.0",
"symfony/yaml": "^6.0|^7.0|^8.0"
},
"require-dev": {
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0",
"phpstan/phpstan": "^2.0"
},
"bin": [
@@ -10170,7 +10467,7 @@
"issues": "https://github.com/laravel/sail/issues",
"source": "https://github.com/laravel/sail"
},
"time": "2026-01-01T02:46:03+00:00"
"time": "2026-02-06T12:16:02+00:00"
},
{
"name": "mockery/mockery",
@@ -12239,28 +12536,27 @@
},
{
"name": "symfony/yaml",
"version": "v7.4.1",
"version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "24dd4de28d2e3988b311751ac49e684d783e2345"
"reference": "7a1a90ba1df6e821a6b53c4cabdc32a56cabfb14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345",
"reference": "24dd4de28d2e3988b311751ac49e684d783e2345",
"url": "https://api.github.com/repos/symfony/yaml/zipball/7a1a90ba1df6e821a6b53c4cabdc32a56cabfb14",
"reference": "7a1a90ba1df6e821a6b53c4cabdc32a56cabfb14",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=8.4",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<6.4"
"symfony/console": "<7.4"
},
"require-dev": {
"symfony/console": "^6.4|^7.0|^8.0"
"symfony/console": "^7.4|^8.0"
},
"bin": [
"Resources/bin/yaml-lint"
@@ -12291,7 +12587,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v7.4.1"
"source": "https://github.com/symfony/yaml/tree/v8.0.1"
},
"funding": [
{
@@ -12311,27 +12607,27 @@
"type": "tidelift"
}
],
"time": "2025-12-04T18:11:45+00:00"
"time": "2025-12-04T18:17:06+00:00"
},
{
"name": "ta-tikoma/phpunit-architecture-test",
"version": "0.8.6",
"version": "0.8.7",
"source": {
"type": "git",
"url": "https://github.com/ta-tikoma/phpunit-architecture-test.git",
"reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e"
"reference": "1248f3f506ca9641d4f68cebcd538fa489754db8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/ad48430b92901fd7d003fdaf2d7b139f96c0906e",
"reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e",
"url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/1248f3f506ca9641d4f68cebcd538fa489754db8",
"reference": "1248f3f506ca9641d4f68cebcd538fa489754db8",
"shasum": ""
},
"require": {
"nikic/php-parser": "^4.18.0 || ^5.0.0",
"php": "^8.1.0",
"phpdocumentor/reflection-docblock": "^5.3.0 || ^6.0.0",
"phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0",
"phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0 || ^13.0.0",
"symfony/finder": "^6.4.0 || ^7.0.0 || ^8.0.0"
},
"require-dev": {
@@ -12368,9 +12664,9 @@
],
"support": {
"issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues",
"source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.6"
"source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.7"
},
"time": "2026-01-30T07:16:00+00:00"
"time": "2026-02-17T17:25:14+00:00"
},
{
"name": "theseer/tokenizer",

View File

@@ -0,0 +1,29 @@
<?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('discounts', function (Blueprint $table) {
$table->id();
$table->text('discount');
$table->foreignId('client_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('discounts');
}
};

View File

@@ -0,0 +1,28 @@
<?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::table('transactions', function (Blueprint $table) {
$table->string('discount_type')->after('with_discount')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('transactions', function (Blueprint $table) {
$table->dropColumn('discount_type');
});
}
};

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Transmittal Report</title>
<style>
body {
font-family: DejaVu Sans, sans-serif;
font-size: 12px;
}
.header {
text-align: center;
margin-bottom: 20px;
}
.header-logo {
height: 60px;
margin-bottom: 10px;
}
.header-title {
font-size: 20px;
font-weight: bold;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #000;
padding: 4px;
}
th {
text-transform: capitalize;
text-align: center;
}
</style>
</head>
<body>
<div class="header">
<img src="{{ public_path('images/logo.png') }}" alt="Logo" class="header-logo">
<div class="header-title">Transmittal Report</div>
</div>
@include('transmittal.export.transmittal-export-table', ['transmittals' => $transmittals])
</body>
</html>

View File

@@ -1,5 +1,6 @@
<?php
use App\Jobs\TestQueueJob;
use App\Models\Transmittal;
use Illuminate\Support\Facades\Route;
@@ -13,10 +14,16 @@ Route::view('profile', 'profile')
->middleware(['auth'])
->name('profile');
Route::get('preview-transmittal', function () {
return view('transmittal.export.transmittal-export-table')->with(['transmittals' => Transmittal::withCount(['files', 'notes', 'remarks'])->with(['files' => function ($files) {
$files->withCount(['notes', 'remarks']);
}])->get()]);
// Route::get('preview-transmittal', function () {
// return view('transmittal.export.transmittal-export-table')->with(['transmittals' => Transmittal::withCount(['files', 'notes', 'remarks'])->with(['files' => function ($files) {
// $files->withCount(['notes', 'remarks']);
// }])->get()]);
// });
Route::get('queue-test', function () {
TestQueueJob::dispatch();
return 'TestQueueJob dispatched';
});
require __DIR__.'/auth.php';