Compare commits
25 Commits
fix/error-
...
1d6238e9cb
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d6238e9cb | |||
|
|
d8077f200a | ||
|
|
7899ed75ea | ||
|
|
5d427cdea4 | ||
| 2644be0505 | |||
|
|
9ddb71f03d | ||
| eadcc0b3d7 | |||
|
|
8c6fa6cb08 | ||
|
|
7bcfaff311 | ||
|
|
e04689acca | ||
| 3cf5f6db6a | |||
|
|
f5c8ec04ad | ||
| 7bbe6e2d2a | |||
|
|
fbc01bf1a4 | ||
|
|
ff07f6f810 | ||
|
|
2bd8e99f64 | ||
|
|
950e5613e6 | ||
|
|
fc118b8a6c | ||
|
|
a80e9a7b1c | ||
| d793abec9e | |||
| fcac27b34d | |||
| 22ea384d52 | |||
| 7174bd6c90 | |||
| 4f9ec9ebfb | |||
| f63be7fa5e |
11
.devdbrc
Normal file
11
.devdbrc
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
54
app/Actions/Sales/CreateSaleAction.php
Normal file
54
app/Actions/Sales/CreateSaleAction.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Sales;
|
||||||
|
|
||||||
|
use App\Actions\Transactions\CreateRecordTransactionsAction;
|
||||||
|
use App\Commands\Sales\CreateSaleCommand;
|
||||||
|
use App\Commands\Series\CreateSeriesCommand;
|
||||||
|
use App\Models\Sale;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class CreateSaleAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new class instance.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private CreateSaleCommand $createSaleCommand,
|
||||||
|
private CreateSeriesCommand $createSeriesCommand,
|
||||||
|
){ }
|
||||||
|
|
||||||
|
public function __invoke(array $data, array $transactions): Sale
|
||||||
|
{
|
||||||
|
$record = $this->createSaleCommand->execute($data);
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
//create transactions for the sale
|
||||||
|
app(CreateRecordTransactionsAction::class)($record, $transactions);
|
||||||
|
|
||||||
|
$accountIds = collect($transactions)
|
||||||
|
->pluck('account_id')
|
||||||
|
->filter()
|
||||||
|
->unique()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
|
||||||
|
//sync accounts to sale
|
||||||
|
app(SyncAccountsAction::class)($record, $accountIds);
|
||||||
|
|
||||||
|
//increment current_series
|
||||||
|
$this->createSeriesCommand->execute([
|
||||||
|
'branch_id' => $record->branch_id,
|
||||||
|
'series' => $record->reference_number,
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new \Exception('Failed to save transactions : '.$exception->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
app/Actions/Sales/SyncAccountsAction.php
Normal file
16
app/Actions/Sales/SyncAccountsAction.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Sales;
|
||||||
|
|
||||||
|
use App\Models\Sale;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class SyncAccountsAction
|
||||||
|
{
|
||||||
|
public function __invoke(Sale $sale, array $accounts): void
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($sale, $accounts) {
|
||||||
|
$sale->accounts()->sync($accounts);
|
||||||
|
}, attempts: 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Actions/Transactions/CreateRecordTransactionsAction.php
Normal file
30
app/Actions/Transactions/CreateRecordTransactionsAction.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Transactions;
|
||||||
|
|
||||||
|
use App\DataObjects\CreateTransactionDTO;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Pipeline;
|
||||||
|
|
||||||
|
class CreateRecordTransactionsAction
|
||||||
|
{
|
||||||
|
public function __invoke(Model $record, array $transactions): void
|
||||||
|
{
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
$tData = [
|
||||||
|
'branch_id' => $record->branch_id,
|
||||||
|
'happened_on' => $record->happened_on,
|
||||||
|
...$transaction,
|
||||||
|
];
|
||||||
|
|
||||||
|
$payload = new CreateTransactionDTO(data: $tData, transactionable: $record);
|
||||||
|
|
||||||
|
Pipeline::send(passable: $payload)->through(
|
||||||
|
[
|
||||||
|
CreateTransactionAction::class,
|
||||||
|
]
|
||||||
|
)->thenReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -24,6 +24,10 @@ class CreateTransactionAction extends BaseAction
|
|||||||
|
|
||||||
$this->cashAccountLedger($payload);
|
$this->cashAccountLedger($payload);
|
||||||
|
|
||||||
|
if ($payload->transaction->discount !== 0) {
|
||||||
|
$this->discountAccountLedger($payload);
|
||||||
|
}
|
||||||
|
|
||||||
return $next($payload);
|
return $next($payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,11 +37,13 @@ class CreateTransactionAction extends BaseAction
|
|||||||
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
||||||
$type = $isExpense ? 'debit' : 'credit';
|
$type = $isExpense ? 'debit' : 'credit';
|
||||||
|
|
||||||
|
$discount = $payload->transaction->discount ?? 0.00;
|
||||||
|
|
||||||
if ($branch->isClientVatable) {
|
if ($branch->isClientVatable) {
|
||||||
//create transaction account ledger
|
//create transaction account ledger
|
||||||
$ledgerPayload = new CreateLedgerDTO(
|
$ledgerPayload = new CreateLedgerDTO(
|
||||||
branch_id: $payload->transactionable->branch_id,
|
branch_id: $payload->transactionable->branch_id,
|
||||||
amount: $payload->transaction->net_amount ?? 0.00,
|
amount: $payload->transaction->net_amount + $discount ?? 0.00,
|
||||||
transaction: $payload->transaction,
|
transaction: $payload->transaction,
|
||||||
account: $payload->transaction->account,
|
account: $payload->transaction->account,
|
||||||
type: $type,
|
type: $type,
|
||||||
@@ -144,4 +150,28 @@ class CreateTransactionAction extends BaseAction
|
|||||||
$this->ledgerPipe($ledgerPayload);
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
app/Commands/Clients/GenerateBaseAccountCommand.php
Normal file
64
app/Commands/Clients/GenerateBaseAccountCommand.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Commands\Clients;
|
||||||
|
|
||||||
|
use App\Commands\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class GenerateBaseAccountCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new class instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the command.
|
||||||
|
*/
|
||||||
|
public function execute($client): void
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($client) {
|
||||||
|
$client->accounts()->createMany([
|
||||||
|
[
|
||||||
|
'account_type_id' => 1,
|
||||||
|
'account' => 'Cash',
|
||||||
|
'normal_balance' => 'debit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'account_type_id' => 1,
|
||||||
|
'account' => 'Input Tax',
|
||||||
|
'normal_balance' => 'debit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'account_type_id' => 1,
|
||||||
|
'account' => 'Creditable Withholding Tax',
|
||||||
|
'normal_balance' => 'debit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'account_type_id' => 2,
|
||||||
|
'account' => 'Output Tax',
|
||||||
|
'normal_balance' => 'credit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'account_type_id' => 2,
|
||||||
|
'account' => 'Payable Withholding Tax',
|
||||||
|
'normal_balance' => 'credit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'account_type_id' => 5,
|
||||||
|
'account' => 'Vat Exempt Revenue',
|
||||||
|
'normal_balance' => 'credit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'account_type_id' => 4,
|
||||||
|
'account' => 'Sales Discount',
|
||||||
|
'normal_balance' => 'debit',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
app/Commands/Sales/CreateSaleCommand.php
Normal file
27
app/Commands/Sales/CreateSaleCommand.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Commands\Sales;
|
||||||
|
|
||||||
|
use App\Commands\Command;
|
||||||
|
use App\DataObjects\CreateSaleDTO;
|
||||||
|
use App\Models\Sale;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class CreateSaleCommand implements Command
|
||||||
|
{
|
||||||
|
public function execute(array $data): Sale
|
||||||
|
{
|
||||||
|
return DB::transaction(function () use ($data, &$sale) {
|
||||||
|
$tData = new CreateSaleDTO(
|
||||||
|
reference_number: $data['current_series'],
|
||||||
|
happened_on: \Carbon\Carbon::parse($data['happened_on']),
|
||||||
|
branch_id: $data['branch_id'],
|
||||||
|
user_id: Auth::user()->id,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Sale::create($tData->toArray());
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/DataObjects/CreateSaleDTO.php
Normal file
29
app/DataObjects/CreateSaleDTO.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\DataObjects;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
readonly class CreateSaleDTO
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new class instance.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
protected string $reference_number,
|
||||||
|
protected Carbon $happened_on,
|
||||||
|
protected int $branch_id,
|
||||||
|
protected int $user_id,
|
||||||
|
)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'reference_number' => $this->reference_number,
|
||||||
|
'happened_on' => $this->happened_on,
|
||||||
|
'branch_id' => $this->branch_id,
|
||||||
|
'user_id' => $this->user_id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,7 @@ use App\Filament\Resources\ClientResource\Pages\GeneralLedger;
|
|||||||
use App\Filament\Resources\ClientResource\Pages\TrialBalance;
|
use App\Filament\Resources\ClientResource\Pages\TrialBalance;
|
||||||
use App\Filament\Resources\ClientResource\RelationManagers\AccountsRelationManager;
|
use App\Filament\Resources\ClientResource\RelationManagers\AccountsRelationManager;
|
||||||
use App\Filament\Resources\ClientResource\RelationManagers\BranchesRelationManager;
|
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\ExpensesRelationManager;
|
||||||
use App\Filament\Resources\ClientResource\RelationManagers\JournalsRelationManager;
|
use App\Filament\Resources\ClientResource\RelationManagers\JournalsRelationManager;
|
||||||
use App\Filament\Resources\ClientResource\RelationManagers\SalesRelationManager;
|
use App\Filament\Resources\ClientResource\RelationManagers\SalesRelationManager;
|
||||||
@@ -109,6 +110,7 @@ class ClientResource extends Resource
|
|||||||
SalesRelationManager::class,
|
SalesRelationManager::class,
|
||||||
ExpensesRelationManager::class,
|
ExpensesRelationManager::class,
|
||||||
JournalsRelationManager::class,
|
JournalsRelationManager::class,
|
||||||
|
DiscountRelationManager::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Filament\Resources\ClientResource\RelationManagers;
|
namespace App\Filament\Resources\ClientResource\RelationManagers;
|
||||||
|
|
||||||
|
use App\Commands\Clients\GenerateBaseAccountCommand;
|
||||||
use App\Filament\Exports\ClientAccountsExporter;
|
use App\Filament\Exports\ClientAccountsExporter;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use Filament\Actions\Exports\Enums\ExportFormat;
|
use Filament\Actions\Exports\Enums\ExportFormat;
|
||||||
@@ -43,6 +44,20 @@ class AccountsRelationManager extends RelationManager
|
|||||||
//
|
//
|
||||||
])
|
])
|
||||||
->headerActions([
|
->headerActions([
|
||||||
|
Tables\Actions\Action::make('generate-base-accounts')
|
||||||
|
->requiresConfirmation()
|
||||||
|
->label('Generate Base Accounts')
|
||||||
|
->action(function () {
|
||||||
|
$client = $this->getOwnerRecord();
|
||||||
|
if (! $client ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($client->accounts()->count() > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
app(GenerateBaseAccountCommand::class)->execute($client);
|
||||||
|
}),
|
||||||
Tables\Actions\ExportAction::make('Export Accounts')->exporter(ClientAccountsExporter::class)->formats([ExportFormat::Csv]),
|
Tables\Actions\ExportAction::make('Export Accounts')->exporter(ClientAccountsExporter::class)->formats([ExportFormat::Csv]),
|
||||||
Tables\Actions\CreateAction::make()->label('New Account')->icon('heroicon-o-plus')->slideOver(),
|
Tables\Actions\CreateAction::make()->label('New Account')->icon('heroicon-o-plus')->slideOver(),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,31 +24,13 @@ class ExpensesRelationManager extends RelationManager
|
|||||||
|
|
||||||
public function table(Table $table): Table
|
public function table(Table $table): Table
|
||||||
{
|
{
|
||||||
return $table
|
return ExpenseResource::table($table)->headerActions([
|
||||||
->recordTitleAttribute('supplier')
|
Tables\Actions\Action::make('New Expense')->action('openCreateForm'),
|
||||||
->columns([
|
]);
|
||||||
TextColumn::make('supplier'),
|
}
|
||||||
TextColumn::make('reference_number'),
|
|
||||||
TextColumn::make('voucher_number'),
|
public function openCreateForm()
|
||||||
TextColumn::make('branch.code'),
|
{
|
||||||
TextColumn::make('happened_on'),
|
return redirect()->route('filament.admin.resources.expenses.create', ['client_id' => $this->getOwnerRecord()->id]);
|
||||||
])
|
|
||||||
->filters([
|
|
||||||
//
|
|
||||||
])
|
|
||||||
->headerActions([
|
|
||||||
Tables\Actions\CreateAction::make()
|
|
||||||
->url(fn () => ExpenseResource::getUrl('create', ['client_id' => $this->getOwnerRecord()->id])),
|
|
||||||
])
|
|
||||||
->actions([
|
|
||||||
Tables\Actions\EditAction::make()
|
|
||||||
->url(fn (Expense $record) => ExpenseResource::getUrl('edit', ['record' => $record])),
|
|
||||||
Tables\Actions\DeleteAction::make(),
|
|
||||||
])
|
|
||||||
->bulkActions([
|
|
||||||
Tables\Actions\BulkActionGroup::make([
|
|
||||||
Tables\Actions\DeleteBulkAction::make(),
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,36 +24,13 @@ class SalesRelationManager extends RelationManager
|
|||||||
|
|
||||||
public function table(Table $table): Table
|
public function table(Table $table): Table
|
||||||
{
|
{
|
||||||
return $table
|
return SaleResource::table($table)->headerActions([
|
||||||
->recordTitleAttribute('title')
|
Tables\Actions\Action::make('New Sale')->action('openCreateForm'),
|
||||||
->columns([
|
]);
|
||||||
TextColumn::make('id')->label('ID')->sortable(),
|
}
|
||||||
TextColumn::make('branch.code')->label('Branch')->sortable(),
|
|
||||||
TextColumn::make('happened_on')->label('Date')->date()->sortable(),
|
public function openCreateForm()
|
||||||
TextColumn::make('gross_amount')->label('Gross Amount')->numeric()->sortable(),
|
{
|
||||||
TextColumn::make('exempt')->label('Exempt')->numeric()->sortable(),
|
return redirect()->route('filament.admin.resources.sales.create', ['client_id' => $this->getOwnerRecord()->id]);
|
||||||
TextColumn::make('vatable_amount')->label('Vatable Amount')->numeric()->sortable(),
|
|
||||||
TextColumn::make('output_tax')->label('Output Tax')->numeric()->sortable(),
|
|
||||||
TextColumn::make('payable_withholding_tax')->label('Payable Withholding Tax')->numeric()->sortable(),
|
|
||||||
TextColumn::make('discount')->label('Discount')->numeric()->sortable(),
|
|
||||||
TextColumn::make('net_amount')->label('Net Amount')->numeric()->sortable(),
|
|
||||||
])
|
|
||||||
->filters([
|
|
||||||
//
|
|
||||||
])
|
|
||||||
->headerActions([
|
|
||||||
Tables\Actions\CreateAction::make()
|
|
||||||
->url(fn () => SaleResource::getUrl('create', ['client_id' => $this->getOwnerRecord()->id])),
|
|
||||||
])
|
|
||||||
->actions([
|
|
||||||
Tables\Actions\EditAction::make()
|
|
||||||
->url(fn (Sale $record) => SaleResource::getUrl('edit', ['record' => $record])),
|
|
||||||
Tables\Actions\DeleteAction::make(),
|
|
||||||
])
|
|
||||||
->bulkActions([
|
|
||||||
Tables\Actions\BulkActionGroup::make([
|
|
||||||
Tables\Actions\DeleteBulkAction::make(),
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
app/Filament/Resources/DiscountResource.php
Normal file
73
app/Filament/Resources/DiscountResource.php
Normal 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'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -195,11 +195,11 @@ class ExpenseResource extends Resource
|
|||||||
'client_id' => $get('../../client'),
|
'client_id' => $get('../../client'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($get('../../branch_id')) {
|
// if ($get('../../branch_id')) {
|
||||||
$query->whereHas('balances', function ($query) use ($get) {
|
// $query->whereHas('balances', function ($query) use ($get) {
|
||||||
return $query->where('branch_id', $get('../../branch_id'));
|
// return $query->where('branch_id', $get('../../branch_id'));
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
$query->whereHas('accountType', function ($query) {
|
$query->whereHas('accountType', function ($query) {
|
||||||
return $query->where('type', 'Expenses');
|
return $query->where('type', 'Expenses');
|
||||||
@@ -208,7 +208,6 @@ class ExpenseResource extends Resource
|
|||||||
return $query->get()->pluck('account', 'id');
|
return $query->get()->pluck('account', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NoReturn]
|
|
||||||
public static function setDefaultFormValues(Get $get, Set $set, ?string $old, ?string $state): void
|
public static function setDefaultFormValues(Get $get, Set $set, ?string $old, ?string $state): void
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -273,6 +272,7 @@ class ExpenseResource extends Resource
|
|||||||
Tables\Columns\TextColumn::make('branch.client.company'),
|
Tables\Columns\TextColumn::make('branch.client.company'),
|
||||||
Tables\Columns\TextColumn::make('branch.code'),
|
Tables\Columns\TextColumn::make('branch.code'),
|
||||||
Tables\Columns\TextColumn::make('happened_on'),
|
Tables\Columns\TextColumn::make('happened_on'),
|
||||||
|
Tables\Columns\TextColumn::make('accounts_list')->label('Accounts'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,52 @@
|
|||||||
|
|
||||||
namespace App\Filament\Resources\ExpenseResource\Pages;
|
namespace App\Filament\Resources\ExpenseResource\Pages;
|
||||||
|
|
||||||
use App\Actions\Transactions\CreateTransactionAction;
|
use App\Actions\Transactions\CreateRecordTransactionsAction;
|
||||||
use App\DataObjects\CreateTransactionDTO;
|
use App\Filament\Resources\ClientResource;
|
||||||
use App\Filament\Resources\ExpenseResource;
|
use App\Filament\Resources\ExpenseResource;
|
||||||
|
use App\Models\Client;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Filament\Resources\Pages\CreateRecord;
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\Pipeline;
|
|
||||||
use Symfony\Component\Console\Exception\LogicException;
|
use Symfony\Component\Console\Exception\LogicException;
|
||||||
|
|
||||||
class CreateExpense extends CreateRecord
|
class CreateExpense extends CreateRecord
|
||||||
{
|
{
|
||||||
protected static string $resource = ExpenseResource::class;
|
protected static string $resource = ExpenseResource::class;
|
||||||
|
|
||||||
|
public ?int $clientId = null;
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
parent::mount();
|
||||||
|
|
||||||
|
$this->clientId = request()->integer('client_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBreadcrumbs(): array
|
||||||
|
{
|
||||||
|
$client = $this->getClient();
|
||||||
|
|
||||||
|
if (! $client) {
|
||||||
|
return parent::getBreadcrumbs();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
ClientResource::getUrl('view', ['record' => $client->id]) => $client->company,
|
||||||
|
ClientResource::getUrl('view', ['record' => $client->id]).'?activeRelationManager=4' => 'Expenses',
|
||||||
|
$this->getResource()::getUrl('create', ['client_id' => $client->id]) => 'Create',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClient(): Client|null
|
||||||
|
{
|
||||||
|
if (! $this->clientId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Client::find($this->clientId);
|
||||||
|
}
|
||||||
|
|
||||||
protected function mutateFormDataBeforeCreate(array $data): array
|
protected function mutateFormDataBeforeCreate(array $data): array
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -23,6 +56,16 @@ class CreateExpense extends CreateRecord
|
|||||||
|
|
||||||
public function getFormDataMutation(array $data): array
|
public function getFormDataMutation(array $data): array
|
||||||
{
|
{
|
||||||
|
$transactions = $data['transactions'] ?? [];
|
||||||
|
|
||||||
|
$data['gross_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['gross_amount'] ?? 0));
|
||||||
|
$data['exempt'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['exempt'] ?? 0));
|
||||||
|
$data['zero_rated'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['zero_rated'] ?? 0));
|
||||||
|
$data['vatable_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['vatable_amount'] ?? 0));
|
||||||
|
$data['input_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['input_tax'] ?? 0));
|
||||||
|
$data['payable_withholding_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['payable_withholding_tax'] ?? 0));
|
||||||
|
$data['net_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['net_amount'] ?? 0));
|
||||||
|
|
||||||
return Arr::except($data, ['client', 'transactions']);
|
return Arr::except($data, ['client', 'transactions']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,24 +74,16 @@ class CreateExpense extends CreateRecord
|
|||||||
$transactions = $this->form->getState()['transactions'] ?? [];
|
$transactions = $this->form->getState()['transactions'] ?? [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$branch = $this->getRecord()->branch;
|
app(CreateRecordTransactionsAction::class)($this->getRecord(), $transactions);
|
||||||
|
|
||||||
foreach ($transactions as $transaction) {
|
$accountIds = collect($transactions)
|
||||||
|
->pluck('account_id')
|
||||||
|
->filter()
|
||||||
|
->unique()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
|
||||||
$data = [
|
$this->getRecord()->accounts()->sync($accountIds);
|
||||||
'branch_id' => $branch->id,
|
|
||||||
'happened_on' => $this->getRecord()->happened_on,
|
|
||||||
...$transaction,
|
|
||||||
];
|
|
||||||
|
|
||||||
$payload = new CreateTransactionDTO(data: $data, transactionable: $this->getRecord());
|
|
||||||
|
|
||||||
Pipeline::send(passable: $payload)->through(
|
|
||||||
[
|
|
||||||
CreateTransactionAction::class,
|
|
||||||
]
|
|
||||||
)->thenReturn();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->commitDatabaseTransaction();
|
$this->commitDatabaseTransaction();
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Filament\Resources\SaleResource\Pages;
|
|||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Branch;
|
use App\Models\Branch;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\Discount;
|
||||||
use App\Models\Sale;
|
use App\Models\Sale;
|
||||||
use Awcodes\TableRepeater\Components\TableRepeater;
|
use Awcodes\TableRepeater\Components\TableRepeater;
|
||||||
use Awcodes\TableRepeater\Header;
|
use Awcodes\TableRepeater\Header;
|
||||||
@@ -30,12 +31,13 @@ class SaleResource extends Resource
|
|||||||
|
|
||||||
protected static bool $shouldRegisterNavigation = false;
|
protected static bool $shouldRegisterNavigation = false;
|
||||||
|
|
||||||
|
|
||||||
public static function form(Form $form): Form
|
public static function form(Form $form): Form
|
||||||
{
|
{
|
||||||
return $form
|
return $form
|
||||||
->schema([
|
->schema([
|
||||||
Select::make('client')
|
Select::make('client')
|
||||||
->default(request()->query('client_id'))
|
->default(fn () => request()->integer('client_id'))
|
||||||
->options(Client::query()->get()->pluck('company', 'id'))
|
->options(Client::query()->get()->pluck('company', 'id'))
|
||||||
->afterStateUpdated(function ($set, $get) {
|
->afterStateUpdated(function ($set, $get) {
|
||||||
$set('branch_id', '');
|
$set('branch_id', '');
|
||||||
@@ -53,7 +55,7 @@ class SaleResource extends Resource
|
|||||||
->live(),
|
->live(),
|
||||||
TextInput::make('current_series')
|
TextInput::make('current_series')
|
||||||
->label('Series')
|
->label('Series')
|
||||||
->disabled(),
|
->readOnly(),
|
||||||
DatePicker::make('happened_on')->label('Date')
|
DatePicker::make('happened_on')->label('Date')
|
||||||
->required()
|
->required()
|
||||||
->afterStateUpdated(function ($set, $get) {
|
->afterStateUpdated(function ($set, $get) {
|
||||||
@@ -71,6 +73,8 @@ class SaleResource extends Resource
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static function getSeries(Get $get): string
|
public static function getSeries(Get $get): string
|
||||||
{
|
{
|
||||||
$branch = Branch::find($get('branch_id'));
|
$branch = Branch::find($get('branch_id'));
|
||||||
@@ -92,11 +96,12 @@ class SaleResource extends Resource
|
|||||||
Header::make('Charge Account'),
|
Header::make('Charge Account'),
|
||||||
Header::make('Description'),
|
Header::make('Description'),
|
||||||
Header::make('Gross Amount'),
|
Header::make('Gross Amount'),
|
||||||
Header::make('Exempt'),
|
// Header::make('Exempt'),
|
||||||
Header::make('Vatable Amount'),
|
Header::make('Vatable Amount'),
|
||||||
Header::make('Output Tax'),
|
Header::make('Output Tax'),
|
||||||
Header::make('Withholding Tax'),
|
Header::make('Withholding Tax'),
|
||||||
Header::make('Discount'),
|
Header::make('Discount'),
|
||||||
|
Header::make('Discount Type'),
|
||||||
Header::make('Net Amount'),
|
Header::make('Net Amount'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -105,7 +110,7 @@ class SaleResource extends Resource
|
|||||||
Header::make('Charge Account'),
|
Header::make('Charge Account'),
|
||||||
Header::make('Description'),
|
Header::make('Description'),
|
||||||
Header::make('Gross Amount'),
|
Header::make('Gross Amount'),
|
||||||
Header::make('Exempt'),
|
// Header::make('Exempt'),
|
||||||
Header::make('Vatable Amount'),
|
Header::make('Vatable Amount'),
|
||||||
Header::make('Output Tax'),
|
Header::make('Output Tax'),
|
||||||
Header::make('Withholding Tax'),
|
Header::make('Withholding Tax'),
|
||||||
@@ -128,6 +133,7 @@ class SaleResource extends Resource
|
|||||||
TextInput::make('exempt')
|
TextInput::make('exempt')
|
||||||
->numeric()
|
->numeric()
|
||||||
->live()
|
->live()
|
||||||
|
->hidden()
|
||||||
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
||||||
static::setDefaultFormValues($get, $set, $old, $state);
|
static::setDefaultFormValues($get, $set, $old, $state);
|
||||||
})->default(0),
|
})->default(0),
|
||||||
@@ -135,7 +141,7 @@ class SaleResource extends Resource
|
|||||||
->numeric()
|
->numeric()
|
||||||
->nullable()
|
->nullable()
|
||||||
->live()
|
->live()
|
||||||
->readOnly()
|
->readOnly(fn (Get $get) => $get('exempt') == 0)
|
||||||
->default(0),
|
->default(0),
|
||||||
Hidden::make('happened_on')->default(fn (Get $get) => $get('../../happened_on')),
|
Hidden::make('happened_on')->default(fn (Get $get) => $get('../../happened_on')),
|
||||||
Hidden::make('with_discount')->default(fn (Get $get) => $get('../../with_discount')),
|
Hidden::make('with_discount')->default(fn (Get $get) => $get('../../with_discount')),
|
||||||
@@ -150,14 +156,17 @@ class SaleResource extends Resource
|
|||||||
->numeric()
|
->numeric()
|
||||||
->live()
|
->live()
|
||||||
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
||||||
|
|
||||||
static::setDefaultFormValues($get, $set, $old, $state);
|
static::setDefaultFormValues($get, $set, $old, $state);
|
||||||
})->default(0),
|
})->default(0),
|
||||||
TextInput::make('discount')
|
TextInput::make('discount')
|
||||||
->numeric()
|
->numeric()
|
||||||
->readOnly()
|
// ->readOnly()
|
||||||
->visible(fn (Get $get) => $get('../../with_discount'))
|
->visible(fn (Get $get) => $get('../../with_discount'))
|
||||||
->live(),
|
->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),
|
TextInput::make('net_amount')->numeric()->default(0),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -170,11 +179,11 @@ class SaleResource extends Resource
|
|||||||
'client_id' => $get('../../client'),
|
'client_id' => $get('../../client'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($get('../../branch_id')) {
|
// if ($get('../../branch_id')) {
|
||||||
$query->whereHas('balances', function ($query) use ($get) {
|
// $query->whereHas('balances', function ($query) use ($get) {
|
||||||
return $query->where('branch_id', $get('../../branch_id'));
|
// return $query->where('branch_id', $get('../../branch_id'));
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
$query->whereHas('accountType', function ($query) {
|
$query->whereHas('accountType', function ($query) {
|
||||||
return $query->where('type', 'Revenue');
|
return $query->where('type', 'Revenue');
|
||||||
@@ -183,6 +192,13 @@ class SaleResource extends Resource
|
|||||||
return $query->get()->pluck('account', 'id');
|
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)
|
private static function setDefaultFormValues(Get $get, Set $set, ?string $old, ?string $state)
|
||||||
{
|
{
|
||||||
$exempt = (float) $get('exempt');
|
$exempt = (float) $get('exempt');
|
||||||
@@ -210,7 +226,7 @@ class SaleResource extends Resource
|
|||||||
}
|
}
|
||||||
|
|
||||||
$set('output_tax', number_format($outputTax, 2, '.', ''));
|
$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('vatable_amount', number_format($vatableAmount, 2, '.', ''));
|
||||||
$set('net_amount', number_format($netAmount, 2, '.', ''));
|
$set('net_amount', number_format($netAmount, 2, '.', ''));
|
||||||
}
|
}
|
||||||
@@ -219,17 +235,10 @@ class SaleResource extends Resource
|
|||||||
{
|
{
|
||||||
return $table
|
return $table
|
||||||
->columns([
|
->columns([
|
||||||
TextColumn::make('id')->label('ID')->sortable(),
|
TextColumn::make('branch.code')->label('Branch')->sortable(),
|
||||||
TextColumn::make('client.name')->label('Client')->sortable(),
|
TextColumn::make('reference_number')->label('Reference Number')->sortable(),
|
||||||
TextColumn::make('branch.name')->label('Branch')->sortable(),
|
|
||||||
TextColumn::make('happened_on')->label('Date')->date()->sortable(),
|
TextColumn::make('happened_on')->label('Date')->date()->sortable(),
|
||||||
TextColumn::make('gross_amount')->label('Gross Amount')->numeric()->sortable(),
|
TextColumn::make('user.name')->label('Created By')->sortable(),
|
||||||
TextColumn::make('exempt')->label('Exempt')->numeric()->sortable(),
|
|
||||||
TextColumn::make('vatable_amount')->label('Vatable Amount')->numeric()->sortable(),
|
|
||||||
TextColumn::make('output_tax')->label('Output Tax')->numeric()->sortable(),
|
|
||||||
TextColumn::make('payable_withholding_tax')->label('Payable Withholding Tax')->numeric()->sortable(),
|
|
||||||
TextColumn::make('discount')->label('Discount')->numeric()->sortable(),
|
|
||||||
TextColumn::make('net_amount')->label('Net Amount')->numeric()->sortable(),
|
|
||||||
])
|
])
|
||||||
->filters([
|
->filters([
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -2,21 +2,60 @@
|
|||||||
|
|
||||||
namespace App\Filament\Resources\SaleResource\Pages;
|
namespace App\Filament\Resources\SaleResource\Pages;
|
||||||
|
|
||||||
use App\Actions\Transactions\CreateTransactionAction;
|
use App\Actions\Sales\CreateSaleAction;
|
||||||
use App\DataObjects\CreateTransactionDTO;
|
use App\Actions\Sales\SyncAccountsAction;
|
||||||
|
use App\Actions\Transactions\CreateRecordTransactionsAction;
|
||||||
|
use App\Commands\Clients\GenerateBaseAccountCommand;
|
||||||
|
use App\Filament\Resources\ClientResource;
|
||||||
use App\Filament\Resources\SaleResource;
|
use App\Filament\Resources\SaleResource;
|
||||||
use App\Models\Branch;
|
use App\Models\Branch;
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\Sale;
|
use App\Models\Sale;
|
||||||
|
use App\Services\Sales\SaleService;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Forms\Components\Actions;
|
||||||
use Filament\Resources\Pages\CreateRecord;
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Pipeline;
|
|
||||||
|
|
||||||
class CreateSale extends CreateRecord
|
class CreateSale extends CreateRecord
|
||||||
{
|
{
|
||||||
protected static string $resource = SaleResource::class;
|
protected static string $resource = SaleResource::class;
|
||||||
|
|
||||||
|
public ?int $clientId = null;
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
parent::mount();
|
||||||
|
|
||||||
|
$this->clientId = request()->integer('client_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBreadcrumbs(): array
|
||||||
|
{
|
||||||
|
$client = $this->getClient();
|
||||||
|
|
||||||
|
if (! $client) {
|
||||||
|
return parent::getBreadcrumbs();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
ClientResource::getUrl('view', ['record' => $client->id]) => $client->company,
|
||||||
|
ClientResource::getUrl('view', ['record' => $client->id]).'?activeRelationManager=3' => 'Sales',
|
||||||
|
$this->getResource()::getUrl('create', ['client_id' => $client->id]) => 'Create',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClient(): Client|null
|
||||||
|
{
|
||||||
|
if (! $this->clientId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Client::find($this->clientId);
|
||||||
|
}
|
||||||
|
|
||||||
protected function mutateFormDataBeforeCreate(array $data): array
|
protected function mutateFormDataBeforeCreate(array $data): array
|
||||||
{
|
{
|
||||||
return $this->getFormDataMutation($data);
|
return $this->getFormDataMutation($data);
|
||||||
@@ -30,42 +69,33 @@ class CreateSale extends CreateRecord
|
|||||||
|
|
||||||
public function getFormDataMutation(array $data): array
|
public function getFormDataMutation(array $data): array
|
||||||
{
|
{
|
||||||
return Arr::except($data, ['client', 'transactions', 'with_discount']);
|
$transactions = $data['transactions'] ?? [];
|
||||||
|
|
||||||
|
$data['gross_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['gross_amount'] ?? 0));
|
||||||
|
$data['exempt'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['exempt'] ?? 0));
|
||||||
|
$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));
|
||||||
|
$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']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processCreate(array $data, array $transactions): Model
|
public function processCreate(array $data, array $transactions): Model
|
||||||
{
|
{
|
||||||
try {
|
$record = app(CreateSaleAction::class)($this->getFormDataMutation($data), $transactions);
|
||||||
DB::beginTransaction();
|
|
||||||
$record = Sale::create($data);
|
|
||||||
$branch = $record->branch;
|
|
||||||
|
|
||||||
foreach ($transactions as $transaction) {
|
|
||||||
$tData = [
|
|
||||||
'branch_id' => $branch->id,
|
|
||||||
'happened_on' => $record->happened_on,
|
|
||||||
...$transaction,
|
|
||||||
];
|
|
||||||
|
|
||||||
$payload = new CreateTransactionDTO(data: $tData, transactionable: $record);
|
|
||||||
|
|
||||||
Pipeline::send(passable: $payload)->through(
|
|
||||||
[
|
|
||||||
CreateTransactionAction::class,
|
|
||||||
]
|
|
||||||
)->thenReturn();
|
|
||||||
}
|
|
||||||
DB::commit();
|
|
||||||
} catch (\Exception $exception) {
|
|
||||||
DB::rollBack();
|
|
||||||
throw new \Exception('Failed to save transactions : '.$exception->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $record;
|
return $record;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterCreate(): void
|
protected function getRedirectUrl(): string
|
||||||
{
|
{
|
||||||
$branch = Branch::find($this->data['branch_id']);
|
$client = $this->getClient();
|
||||||
|
if (! $client) {
|
||||||
|
return parent::getRedirectUrl();
|
||||||
|
}
|
||||||
|
return ClientResource::getUrl('view', ['record' => $client->id]).'?activeRelationManager=3';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,16 @@ class EditSale extends EditRecord
|
|||||||
|
|
||||||
public function getFormDataMutation(array $data): array
|
public function getFormDataMutation(array $data): array
|
||||||
{
|
{
|
||||||
|
$transactions = $data['transactions'] ?? [];
|
||||||
|
|
||||||
|
$data['gross_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['gross_amount'] ?? 0));
|
||||||
|
$data['exempt'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['exempt'] ?? 0));
|
||||||
|
$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));
|
||||||
|
|
||||||
return Arr::except($data, ['client', 'transactions', 'with_discount']);
|
return Arr::except($data, ['client', 'transactions', 'with_discount']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +81,16 @@ class EditSale extends EditRecord
|
|||||||
]
|
]
|
||||||
)->thenReturn();
|
)->thenReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$accountIds = collect($transactions)
|
||||||
|
->pluck('account_id')
|
||||||
|
->filter()
|
||||||
|
->unique()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
|
||||||
|
$record->accounts()->sync($accountIds);
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ namespace App\Filament\Resources;
|
|||||||
|
|
||||||
use App\Commands\Transmittal\GenerateTransmittalSeries;
|
use App\Commands\Transmittal\GenerateTransmittalSeries;
|
||||||
use App\Commands\Transmittal\StoreTransmittalCommand;
|
use App\Commands\Transmittal\StoreTransmittalCommand;
|
||||||
use App\Exports\TransmittalsExport;
|
|
||||||
use App\Filament\Resources\TransmittalResource\Pages;
|
use App\Filament\Resources\TransmittalResource\Pages;
|
||||||
use App\Jobs\ExportCompleteJob;
|
use App\Jobs\ExportCompleteJob;
|
||||||
|
use App\Jobs\TransmittalPDFExportJob;
|
||||||
use App\Models\Branch;
|
use App\Models\Branch;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Transmittal;
|
use App\Models\Transmittal;
|
||||||
@@ -26,6 +26,7 @@ use Filament\Tables\Filters\SelectFilter;
|
|||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Malzariey\FilamentDaterangepickerFilter\Filters\DateRangeFilter;
|
use Malzariey\FilamentDaterangepickerFilter\Filters\DateRangeFilter;
|
||||||
|
|
||||||
class TransmittalResource extends Resource
|
class TransmittalResource extends Resource
|
||||||
@@ -112,7 +113,7 @@ class TransmittalResource extends Resource
|
|||||||
public static function getTableActions(): array
|
public static function getTableActions(): array
|
||||||
{
|
{
|
||||||
return [
|
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\ViewAction::make(),
|
||||||
Tables\Actions\Action::make('Update Status')
|
Tables\Actions\Action::make('Update Status')
|
||||||
->fillForm(function ($record) {
|
->fillForm(function ($record) {
|
||||||
@@ -139,7 +140,7 @@ class TransmittalResource extends Resource
|
|||||||
})
|
})
|
||||||
->icon('heroicon-o-pencil-square')
|
->icon('heroicon-o-pencil-square')
|
||||||
->slideOver()
|
->slideOver()
|
||||||
->hidden(! auth()->user()->can('update_transmittal')),
|
->hidden(! Auth::user()->can('update_transmittal')),
|
||||||
Tables\Actions\EditAction::make(),
|
Tables\Actions\EditAction::make(),
|
||||||
Tables\Actions\DeleteAction::make(),
|
Tables\Actions\DeleteAction::make(),
|
||||||
];
|
];
|
||||||
@@ -147,13 +148,11 @@ class TransmittalResource extends Resource
|
|||||||
|
|
||||||
public static function exportTransmittal(array $id): void
|
public static function exportTransmittal(array $id): void
|
||||||
{
|
{
|
||||||
$recipient = auth()->user();
|
$recipient = Auth::user();
|
||||||
|
|
||||||
static::generateExportNotification();
|
static::generateExportNotification();
|
||||||
|
|
||||||
(new TransmittalsExport([$id]))->store('public/transmittal-export.xlsx')->chain([
|
dispatch(new TransmittalPDFExportJob($recipient, $id));
|
||||||
app(ExportCompleteJob::class, ['user' => $recipient]),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function generateExportNotification(): Notification
|
public static function generateExportNotification(): Notification
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\Transmittal;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Filament\Notifications\Actions\Action as NotificationAction;
|
use Filament\Notifications\Actions\Action as NotificationAction;
|
||||||
use Filament\Notifications\Notification;
|
use Filament\Notifications\Notification;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@@ -13,30 +15,37 @@ use Illuminate\Support\Facades\Storage;
|
|||||||
|
|
||||||
class ExportCompleteJob implements ShouldQueue
|
class ExportCompleteJob implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
use InteractsWithQueue;
|
||||||
use Queueable;
|
use Queueable;
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(private $user, private array $ids)
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*/
|
|
||||||
public function __construct(private $user)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the job.
|
|
||||||
*/
|
|
||||||
public function handle(): void
|
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')
|
->title('Export Completed')
|
||||||
->actions([
|
->actions([
|
||||||
NotificationAction::make('download_transmittal-export.xlsx')
|
NotificationAction::make('download_transmittal-export.pdf')
|
||||||
->label('Download File')
|
->label('Download PDF File')
|
||||||
->url(url: Storage::url('public/transmittal-export.xlsx') ,shouldOpenInNewTab: true)
|
->url(Storage::url('transmittal-export.pdf'), true)
|
||||||
->markAsRead(),
|
->markAsRead(),
|
||||||
]
|
])
|
||||||
)
|
|
||||||
->sendToDatabase($this->user);
|
->sendToDatabase($this->user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
app/Jobs/TestQueueJob.php
Normal file
28
app/Jobs/TestQueueJob.php
Normal 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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
53
app/Jobs/TransmittalPDFExportJob.php
Normal file
53
app/Jobs/TransmittalPDFExportJob.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,4 +78,9 @@ class Client extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasManyThrough(Journal::class, Branch::class);
|
return $this->hasManyThrough(Journal::class, Branch::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function discounts(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Discount::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
app/Models/Discount.php
Normal file
10
app/Models/Discount.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Discount extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['discount'];
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||||
|
|
||||||
class Expense extends Model
|
class Expense extends Model
|
||||||
@@ -43,4 +44,14 @@ class Expense extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Branch::class);
|
return $this->belongsTo(Branch::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function accounts(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Account::class, 'account_expense')->withTimestamps();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAccountsListAttribute(): string
|
||||||
|
{
|
||||||
|
return $this->accounts->pluck('account')->implode(', ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,21 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||||
|
|
||||||
class Sale extends Model
|
class Sale extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $fillable = [
|
||||||
|
'branch_id',
|
||||||
|
'user_id',
|
||||||
|
'client_id',
|
||||||
|
'happened_on',
|
||||||
|
'reference_number',
|
||||||
|
'buyer'
|
||||||
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'happened_on' => 'date:Y-m-d',
|
'happened_on' => 'date:Y-m-d',
|
||||||
@@ -43,4 +51,19 @@ class Sale extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Branch::class);
|
return $this->belongsTo(Branch::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function accounts(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Account::class, 'account_sale')->withTimestamps();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAccountsListAttribute(): string
|
||||||
|
{
|
||||||
|
return $this->accounts->pluck('account')->implode(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Observers;
|
namespace App\Observers;
|
||||||
|
|
||||||
|
use App\Commands\Clients\GenerateBaseAccountCommand;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
@@ -12,45 +13,7 @@ class ClientObserver
|
|||||||
*/
|
*/
|
||||||
public function created(Client $client): void
|
public function created(Client $client): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($client) {
|
app(GenerateBaseAccountCommand::class)->execute($client);
|
||||||
$client->accounts()->createMany([
|
|
||||||
[
|
|
||||||
'account_type_id' => 1,
|
|
||||||
'account' => 'Cash',
|
|
||||||
'normal_balance' => 'debit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'account_type_id' => 1,
|
|
||||||
'account' => 'Input Tax',
|
|
||||||
'normal_balance' => 'debit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'account_type_id' => 1,
|
|
||||||
'account' => 'Creditable Withholding Tax',
|
|
||||||
'normal_balance' => 'debit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'account_type_id' => 2,
|
|
||||||
'account' => 'Output Tax',
|
|
||||||
'normal_balance' => 'credit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'account_type_id' => 2,
|
|
||||||
'account' => 'Payable Withholding Tax',
|
|
||||||
'normal_balance' => 'credit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'account_type_id' => 5,
|
|
||||||
'account' => 'Vat Exempt Revenue',
|
|
||||||
'normal_balance' => 'credit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'account_type_id' => 4,
|
|
||||||
'account' => 'Sales Discount',
|
|
||||||
'normal_balance' => 'debit',
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Providers\Filament;
|
namespace App\Providers\Filament;
|
||||||
|
|
||||||
use BezhanSalleh\FilamentShield\FilamentShieldPlugin;
|
use BezhanSalleh\FilamentShield\FilamentShieldPlugin;
|
||||||
|
use Filament\Navigation\NavigationItem;
|
||||||
use Filament\Http\Middleware\Authenticate;
|
use Filament\Http\Middleware\Authenticate;
|
||||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||||
@@ -17,6 +18,7 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
|||||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||||
use Illuminate\Session\Middleware\StartSession;
|
use Illuminate\Session\Middleware\StartSession;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||||
|
|
||||||
class AdminPanelProvider extends PanelProvider
|
class AdminPanelProvider extends PanelProvider
|
||||||
@@ -39,6 +41,13 @@ class AdminPanelProvider extends PanelProvider
|
|||||||
->pages([
|
->pages([
|
||||||
Pages\Dashboard::class,
|
Pages\Dashboard::class,
|
||||||
])
|
])
|
||||||
|
->navigationItems([
|
||||||
|
NavigationItem::make('Horizon')
|
||||||
|
->url(fn (): string => url(config('horizon.path')))
|
||||||
|
->icon('heroicon-o-queue-list')
|
||||||
|
->group('System')
|
||||||
|
->visible(fn (): bool => Auth::user()?->hasRole('super_admin') ?? false),
|
||||||
|
])
|
||||||
->databaseNotifications()
|
->databaseNotifications()
|
||||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
|
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
|
||||||
->widgets([
|
->widgets([
|
||||||
|
|||||||
34
app/Providers/HorizonServiceProvider.php
Normal file
34
app/Providers/HorizonServiceProvider.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Laravel\Horizon\Horizon;
|
||||||
|
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
||||||
|
|
||||||
|
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
// Horizon::routeSmsNotificationsTo('15556667777');
|
||||||
|
// Horizon::routeMailNotificationsTo('example@example.com');
|
||||||
|
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the Horizon gate.
|
||||||
|
*
|
||||||
|
* This gate determines who can access Horizon in non-local environments.
|
||||||
|
*/
|
||||||
|
protected function gate(): void
|
||||||
|
{
|
||||||
|
Gate::define('viewHorizon', function ($user) {
|
||||||
|
return $user->hasRole('super_admin');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,9 +10,11 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"awcodes/filament-table-repeater": "^3.0",
|
"awcodes/filament-table-repeater": "^3.0",
|
||||||
|
"barryvdh/laravel-dompdf": "^2.0",
|
||||||
"bezhansalleh/filament-shield": "^3.2",
|
"bezhansalleh/filament-shield": "^3.2",
|
||||||
"filament/filament": "^3.2",
|
"filament/filament": "^3.2",
|
||||||
"laravel/framework": "^11.9",
|
"laravel/framework": "^11.9",
|
||||||
|
"laravel/horizon": "^5.44",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
"livewire/livewire": "^3.4",
|
"livewire/livewire": "^3.4",
|
||||||
"livewire/volt": "^1.0",
|
"livewire/volt": "^1.0",
|
||||||
|
|||||||
617
composer.lock
generated
617
composer.lock
generated
File diff suppressed because it is too large
Load Diff
178
config/horizon.php
Normal file
178
config/horizon.php
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value is the prefix that will be used by Horizon to generate its
|
||||||
|
| routes. You are free to change this value to anything you like,
|
||||||
|
| such as "admin/horizon" or anything else you'd like it to be.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'domain' => env('HORIZON_DOMAIN'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the URI path where Horizon will be accessible from. Feel free
|
||||||
|
| to change this path to anything you like. Note that the path will be
|
||||||
|
| applied after the "domain" value defined above.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'path' => env('HORIZON_PATH', 'horizon'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Redis Connection
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the name of the Redis connection where Horizon will store the
|
||||||
|
| information about your jobs. This connection should be defined in
|
||||||
|
| your "database" configuration file.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use' => 'default',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Redis Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This prefix will be used when storing all Horizon data in Redis. You
|
||||||
|
| may modify the prefix if you are running multiple Horizon instances
|
||||||
|
| on the same server to avoid any collision between instances.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env(
|
||||||
|
'HORIZON_PREFIX',
|
||||||
|
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
|
||||||
|
),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Route Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These middleware will get attached onto each Horizon route, giving you
|
||||||
|
| the chance to add your own middleware to this list or change any of
|
||||||
|
| the existing middleware. Or, you can simply stick with this list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => ['web', 'auth'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Wait Time Thresholds
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to configure when the queue "wait time" is
|
||||||
|
| considered "long", helping you identify which queues are being
|
||||||
|
| backed up and need more workers to handle the incoming load.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'waits' => [
|
||||||
|
'redis:default' => 60,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Job Trimming Times
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These options determine how many minutes Horizon will keep different
|
||||||
|
| types of jobs in its database. This helps keep your database small
|
||||||
|
| and fast, while still giving you some history for debugging.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'recent' => 60,
|
||||||
|
'recent_failed' => 10080,
|
||||||
|
'failed' => 10080,
|
||||||
|
'monitored' => 10080,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Metrics Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure how many minutes Horizon will keep metrics.
|
||||||
|
| These metrics include things like throughput and average wait time
|
||||||
|
| for each of your queues, giving you insight into your performance.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'metrics' => [
|
||||||
|
'trim_snapshots' => [
|
||||||
|
'job' => 24,
|
||||||
|
'queue' => 24,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Fast Termination
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When this option is enabled, Horizon's "terminate" command will not
|
||||||
|
| wait for all jobs to finish before terminating the workers. This
|
||||||
|
| can be useful when you need to quickly restart your workers.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'fast_termination' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Memory Limit (MB)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value describes the maximum amount of memory the Horizon master
|
||||||
|
| process may consume before it is terminated and restarted. This
|
||||||
|
| helps prevent any memory leaks from affecting the entire server.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'memory_limit' => 64,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Worker Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define the queue worker settings used by your application
|
||||||
|
| in all environments. These settings determine how many workers will
|
||||||
|
| be used for each environment's respective queues.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'environments' => [
|
||||||
|
'production' => [
|
||||||
|
'supervisor-1' => [
|
||||||
|
'maxProcesses' => 10,
|
||||||
|
'balanceMaxShift' => 1,
|
||||||
|
'balanceCooldown' => 3,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'local' => [
|
||||||
|
'supervisor-1' => [
|
||||||
|
'maxProcesses' => 3,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('account_sale', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('sale_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('account_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['sale_id', 'account_id']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('account_expense', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('expense_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('account_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['expense_id', 'account_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('account_expense');
|
||||||
|
Schema::dropIfExists('account_sale');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -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');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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>
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Jobs\TestQueueJob;
|
||||||
use App\Models\Transmittal;
|
use App\Models\Transmittal;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
@@ -13,10 +14,16 @@ Route::view('profile', 'profile')
|
|||||||
->middleware(['auth'])
|
->middleware(['auth'])
|
||||||
->name('profile');
|
->name('profile');
|
||||||
|
|
||||||
Route::get('preview-transmittal', function () {
|
// Route::get('preview-transmittal', function () {
|
||||||
return view('transmittal.export.transmittal-export-table')->with(['transmittals' => Transmittal::withCount(['files', 'notes', 'remarks'])->with(['files' => function ($files) {
|
// return view('transmittal.export.transmittal-export-table')->with(['transmittals' => Transmittal::withCount(['files', 'notes', 'remarks'])->with(['files' => function ($files) {
|
||||||
$files->withCount(['notes', 'remarks']);
|
// $files->withCount(['notes', 'remarks']);
|
||||||
}])->get()]);
|
// }])->get()]);
|
||||||
|
// });
|
||||||
|
|
||||||
|
Route::get('queue-test', function () {
|
||||||
|
TestQueueJob::dispatch();
|
||||||
|
|
||||||
|
return 'TestQueueJob dispatched';
|
||||||
});
|
});
|
||||||
|
|
||||||
require __DIR__.'/auth.php';
|
require __DIR__.'/auth.php';
|
||||||
|
|||||||
Reference in New Issue
Block a user