Compare commits
31 Commits
update/led
...
2644be0505
| Author | SHA1 | Date | |
|---|---|---|---|
| 2644be0505 | |||
|
|
9ddb71f03d | ||
| eadcc0b3d7 | |||
|
|
8c6fa6cb08 | ||
|
|
7bcfaff311 | ||
|
|
e04689acca | ||
| 3cf5f6db6a | |||
|
|
f5c8ec04ad | ||
| 7bbe6e2d2a | |||
|
|
fbc01bf1a4 | ||
|
|
ff07f6f810 | ||
|
|
2bd8e99f64 | ||
|
|
950e5613e6 | ||
|
|
fc118b8a6c | ||
|
|
a80e9a7b1c | ||
| d793abec9e | |||
| fcac27b34d | |||
|
|
fc672e4f4a | ||
| 22ea384d52 | |||
| 7174bd6c90 | |||
|
|
a77e95d2a5 | ||
| 4f9ec9ebfb | |||
|
|
ee65bdfb31 | ||
| f63be7fa5e | |||
|
|
7fa8b75b29 | ||
|
|
a8ad07676a | ||
|
|
6f04a60e43 | ||
|
|
76a52d7e82 | ||
| 5715ab10f2 | |||
| 138740648c | |||
| 13a0f69ce3 |
55
app/Actions/Sales/CreateSaleAction.php
Normal file
55
app/Actions/Sales/CreateSaleAction.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Resources\ClientResource\RelationManagers;
|
||||
|
||||
use App\Commands\Clients\GenerateBaseAccountCommand;
|
||||
use App\Filament\Exports\ClientAccountsExporter;
|
||||
use App\Models\Account;
|
||||
use Filament\Actions\Exports\Enums\ExportFormat;
|
||||
@@ -43,6 +44,20 @@ class AccountsRelationManager extends RelationManager
|
||||
//
|
||||
])
|
||||
->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\CreateAction::make()->label('New Account')->icon('heroicon-o-plus')->slideOver(),
|
||||
])
|
||||
|
||||
@@ -24,31 +24,13 @@ class ExpensesRelationManager extends RelationManager
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('supplier')
|
||||
->columns([
|
||||
TextColumn::make('supplier'),
|
||||
TextColumn::make('reference_number'),
|
||||
TextColumn::make('voucher_number'),
|
||||
TextColumn::make('branch.code'),
|
||||
TextColumn::make('happened_on'),
|
||||
])
|
||||
->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(),
|
||||
]),
|
||||
return ExpenseResource::table($table)->headerActions([
|
||||
Tables\Actions\Action::make('New Expense')->action('openCreateForm'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function openCreateForm()
|
||||
{
|
||||
return redirect()->route('filament.admin.resources.expenses.create', ['client_id' => $this->getOwnerRecord()->id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,36 +24,13 @@ class SalesRelationManager extends RelationManager
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('title')
|
||||
->columns([
|
||||
TextColumn::make('id')->label('ID')->sortable(),
|
||||
TextColumn::make('branch.code')->label('Branch')->sortable(),
|
||||
TextColumn::make('happened_on')->label('Date')->date()->sortable(),
|
||||
TextColumn::make('gross_amount')->label('Gross Amount')->numeric()->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([
|
||||
//
|
||||
])
|
||||
->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(),
|
||||
]),
|
||||
return SaleResource::table($table)->headerActions([
|
||||
Tables\Actions\Action::make('New Sale')->action('openCreateForm'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function openCreateForm()
|
||||
{
|
||||
return redirect()->route('filament.admin.resources.sales.create', ['client_id' => $this->getOwnerRecord()->id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +273,7 @@ class ExpenseResource extends Resource
|
||||
Tables\Columns\TextColumn::make('branch.client.company'),
|
||||
Tables\Columns\TextColumn::make('branch.code'),
|
||||
Tables\Columns\TextColumn::make('happened_on'),
|
||||
Tables\Columns\TextColumn::make('accounts_list')->label('Accounts'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -2,19 +2,52 @@
|
||||
|
||||
namespace App\Filament\Resources\ExpenseResource\Pages;
|
||||
|
||||
use App\Actions\Transactions\CreateTransactionAction;
|
||||
use App\DataObjects\CreateTransactionDTO;
|
||||
use App\Actions\Transactions\CreateRecordTransactionsAction;
|
||||
use App\Filament\Resources\ClientResource;
|
||||
use App\Filament\Resources\ExpenseResource;
|
||||
use App\Models\Client;
|
||||
use Exception;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Pipeline;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
|
||||
class CreateExpense extends CreateRecord
|
||||
{
|
||||
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
|
||||
{
|
||||
|
||||
@@ -23,6 +56,16 @@ class CreateExpense extends CreateRecord
|
||||
|
||||
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']);
|
||||
}
|
||||
|
||||
@@ -31,24 +74,16 @@ class CreateExpense extends CreateRecord
|
||||
$transactions = $this->form->getState()['transactions'] ?? [];
|
||||
|
||||
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 = [
|
||||
'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->getRecord()->accounts()->sync($accountIds);
|
||||
|
||||
$this->commitDatabaseTransaction();
|
||||
} catch (Exception $exception) {
|
||||
|
||||
@@ -40,6 +40,7 @@ class SaleResource extends Resource
|
||||
->afterStateUpdated(function ($set, $get) {
|
||||
$set('branch_id', '');
|
||||
})
|
||||
->disabled()
|
||||
->required()
|
||||
->live(),
|
||||
Select::make('branch_id')
|
||||
@@ -53,7 +54,7 @@ class SaleResource extends Resource
|
||||
->live(),
|
||||
TextInput::make('current_series')
|
||||
->label('Series')
|
||||
->disabled(),
|
||||
->readOnly(),
|
||||
DatePicker::make('happened_on')->label('Date')
|
||||
->required()
|
||||
->afterStateUpdated(function ($set, $get) {
|
||||
@@ -170,11 +171,11 @@ class SaleResource 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', 'Revenue');
|
||||
@@ -219,17 +220,10 @@ class SaleResource extends Resource
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('id')->label('ID')->sortable(),
|
||||
TextColumn::make('client.name')->label('Client')->sortable(),
|
||||
TextColumn::make('branch.name')->label('Branch')->sortable(),
|
||||
TextColumn::make('branch.code')->label('Branch')->sortable(),
|
||||
TextColumn::make('reference_number')->label('Reference Number')->sortable(),
|
||||
TextColumn::make('happened_on')->label('Date')->date()->sortable(),
|
||||
TextColumn::make('gross_amount')->label('Gross Amount')->numeric()->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(),
|
||||
TextColumn::make('user.name')->label('Created By')->sortable(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
|
||||
@@ -2,21 +2,60 @@
|
||||
|
||||
namespace App\Filament\Resources\SaleResource\Pages;
|
||||
|
||||
use App\Actions\Transactions\CreateTransactionAction;
|
||||
use App\DataObjects\CreateTransactionDTO;
|
||||
use App\Actions\Sales\CreateSaleAction;
|
||||
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\Models\Branch;
|
||||
use App\Models\Client;
|
||||
use App\Models\Sale;
|
||||
use App\Services\Sales\SaleService;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Pipeline;
|
||||
|
||||
class CreateSale extends CreateRecord
|
||||
{
|
||||
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
|
||||
{
|
||||
return $this->getFormDataMutation($data);
|
||||
@@ -30,42 +69,32 @@ class CreateSale extends CreateRecord
|
||||
|
||||
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']);
|
||||
}
|
||||
|
||||
public function processCreate(array $data, array $transactions): Model
|
||||
{
|
||||
try {
|
||||
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());
|
||||
}
|
||||
$record = app(CreateSaleAction::class)($this->getFormDataMutation($data), $transactions);
|
||||
|
||||
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
|
||||
{
|
||||
$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']);
|
||||
}
|
||||
|
||||
@@ -71,6 +81,16 @@ class EditSale extends EditRecord
|
||||
]
|
||||
)->thenReturn();
|
||||
}
|
||||
|
||||
$accountIds = collect($transactions)
|
||||
->pluck('account_id')
|
||||
->filter()
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$record->accounts()->sync($accountIds);
|
||||
|
||||
DB::commit();
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
|
||||
@@ -45,16 +45,36 @@ class TransmittalResource extends Resource
|
||||
->columns([
|
||||
Tables\Columns\Layout\Split::make([
|
||||
Tables\Columns\TextColumn::make('series')
|
||||
->searchable()
|
||||
->searchable(query: function (Builder $query, string $search): Builder {
|
||||
$wildcardSearch = '%' . str_replace(' ', '%', $search) . '%';
|
||||
|
||||
return $query->where(function (Builder $query) use ($wildcardSearch) {
|
||||
$query->where('series', 'like', $wildcardSearch)
|
||||
->orWhereHas('notes', function (Builder $query) use ($wildcardSearch) {
|
||||
$query->where('comment', 'like', $wildcardSearch);
|
||||
})
|
||||
->orWhereHas('files', function (Builder $query) use ($wildcardSearch) {
|
||||
$query->where('description', 'like', $wildcardSearch);
|
||||
});
|
||||
});
|
||||
})
|
||||
->label('Series')
|
||||
->weight(FontWeight::Bold)
|
||||
->columnSpan(2),
|
||||
Tables\Columns\Layout\Stack::make([
|
||||
Tables\Columns\TextColumn::make('client.company')
|
||||
->searchable()
|
||||
->searchable(query: function (Builder $query, string $search): Builder {
|
||||
return $query->whereHas('client', function (Builder $query) use ($search) {
|
||||
$query->where('company', 'like', '%' . str_replace(' ', '%', $search) . '%');
|
||||
});
|
||||
})
|
||||
->weight(FontWeight::SemiBold)->label('Client'),
|
||||
Tables\Columns\TextColumn::make('branch.code')
|
||||
->searchable()
|
||||
->searchable(query: function (Builder $query, string $search): Builder {
|
||||
return $query->whereHas('branch', function (Builder $query) use ($search) {
|
||||
$query->where('code', 'like', '%' . str_replace(' ', '%', $search) . '%');
|
||||
});
|
||||
})
|
||||
->label('Branch'),
|
||||
]),
|
||||
]),
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
class Expense extends Model
|
||||
@@ -43,4 +44,14 @@ class Expense extends Model
|
||||
{
|
||||
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,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
class Sale extends Model
|
||||
@@ -43,4 +44,19 @@ class Sale extends Model
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,23 @@
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Filament\Models\Contracts\FilamentUser;
|
||||
use Filament\Panel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\Permission\Traits\HasPermissions;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
class User extends Authenticatable
|
||||
class User extends Authenticatable implements FilamentUser
|
||||
{
|
||||
use HasFactory, HasPermissions, HasRoles, Notifiable;
|
||||
|
||||
public function canAccessPanel(Panel $panel): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Commands\Clients\GenerateBaseAccountCommand;
|
||||
use App\Models\Client;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
@@ -12,45 +13,7 @@ class ClientObserver
|
||||
*/
|
||||
public function created(Client $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',
|
||||
],
|
||||
]);
|
||||
});
|
||||
app(GenerateBaseAccountCommand::class)->execute($client);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Providers;
|
||||
|
||||
use App\Policies\RolePolicy;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
@@ -22,6 +23,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
URL::forceScheme('https');
|
||||
|
||||
Gate::before(function ($user, $ability) {
|
||||
return $user->hasRole('super_admin') ? true : null;
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Providers\Filament;
|
||||
|
||||
use BezhanSalleh\FilamentShield\FilamentShieldPlugin;
|
||||
use Filament\Navigation\NavigationItem;
|
||||
use Filament\Http\Middleware\Authenticate;
|
||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||
@@ -39,6 +40,13 @@ class AdminPanelProvider extends PanelProvider
|
||||
->pages([
|
||||
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()
|
||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\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');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
"bezhansalleh/filament-shield": "^3.2",
|
||||
"filament/filament": "^3.2",
|
||||
"laravel/framework": "^11.9",
|
||||
"laravel/horizon": "^5.44",
|
||||
"laravel/tinker": "^2.9",
|
||||
"livewire/livewire": "^3.4",
|
||||
"livewire/volt": "^1.0",
|
||||
|
||||
109
composer.lock
generated
109
composer.lock
generated
@@ -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": "68d9041cb27c73080bced01f909a4567",
|
||||
"content-hash": "60653f82a7ab603cb6e06b89358e7eec",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@@ -386,16 +386,16 @@
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.14.7",
|
||||
"version": "0.14.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50"
|
||||
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/07ff363b16ef8aca9692bba3be9e73fe63f34e50",
|
||||
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629",
|
||||
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -434,7 +434,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.14.7"
|
||||
"source": "https://github.com/brick/math/tree/0.14.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -442,7 +442,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-07T10:57:35+00:00"
|
||||
"time": "2026-02-10T14:33:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
@@ -2617,17 +2617,96 @@
|
||||
"time": "2026-01-20T15:26:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
"version": "v0.3.12",
|
||||
"name": "laravel/horizon",
|
||||
"version": "v5.44.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/prompts.git",
|
||||
"reference": "4861ded9003b7f8a158176a0b7666f74ee761be8"
|
||||
"url": "https://github.com/laravel/horizon.git",
|
||||
"reference": "00c21e4e768112cce3f4fe576d75956dfc423de2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/4861ded9003b7f8a158176a0b7666f74ee761be8",
|
||||
"reference": "4861ded9003b7f8a158176a0b7666f74ee761be8",
|
||||
"url": "https://api.github.com/repos/laravel/horizon/zipball/00c21e4e768112cce3f4fe576d75956dfc423de2",
|
||||
"reference": "00c21e4e768112cce3f4fe576d75956dfc423de2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-pcntl": "*",
|
||||
"ext-posix": "*",
|
||||
"illuminate/contracts": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/queue": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/support": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||
"nesbot/carbon": "^2.17|^3.0",
|
||||
"php": "^8.0",
|
||||
"ramsey/uuid": "^4.0",
|
||||
"symfony/console": "^6.0|^7.0|^8.0",
|
||||
"symfony/error-handler": "^6.0|^7.0|^8.0",
|
||||
"symfony/polyfill-php83": "^1.28",
|
||||
"symfony/process": "^6.0|^7.0|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.0",
|
||||
"orchestra/testbench": "^7.55|^8.36|^9.15|^10.8|^11.0",
|
||||
"phpstan/phpstan": "^1.10|^2.0",
|
||||
"predis/predis": "^1.1|^2.0|^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-redis": "Required to use the Redis PHP driver.",
|
||||
"predis/predis": "Required when not using the Redis PHP driver (^1.1|^2.0|^3.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Horizon": "Laravel\\Horizon\\Horizon"
|
||||
},
|
||||
"providers": [
|
||||
"Laravel\\Horizon\\HorizonServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Horizon\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Dashboard and code-driven configuration for Laravel queues.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"queue"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/horizon/issues",
|
||||
"source": "https://github.com/laravel/horizon/tree/v5.44.0"
|
||||
},
|
||||
"time": "2026-02-10T18:18:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
"version": "v0.3.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/prompts.git",
|
||||
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d",
|
||||
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2671,9 +2750,9 @@
|
||||
"description": "Add beautiful and user-friendly forms to your command-line applications.",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/prompts/issues",
|
||||
"source": "https://github.com/laravel/prompts/tree/v0.3.12"
|
||||
"source": "https://github.com/laravel/prompts/tree/v0.3.13"
|
||||
},
|
||||
"time": "2026-02-03T06:57:26+00:00"
|
||||
"time": "2026-02-06T12:17:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
|
||||
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
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropForeign(['client_id']);
|
||||
$table->foreign('client_id')
|
||||
->references('id')
|
||||
->on('clients')
|
||||
->cascadeOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropForeign(['client_id']);
|
||||
$table->foreign('client_id')
|
||||
->references('id')
|
||||
->on('clients')
|
||||
->nullOnDelete(); // Since it is nullable
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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('transmittals', function (Blueprint $table) {
|
||||
$table->dropForeign(['client_id']);
|
||||
$table->dropForeign(['branch_id']);
|
||||
|
||||
$table->foreign('client_id')
|
||||
->references('id')
|
||||
->on('clients')
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreign('branch_id')
|
||||
->references('id')
|
||||
->on('branches')
|
||||
->cascadeOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('transmittals', function (Blueprint $table) {
|
||||
$table->dropForeign(['client_id']);
|
||||
$table->dropForeign(['branch_id']);
|
||||
|
||||
$table->foreign('client_id')
|
||||
->references('id')
|
||||
->on('clients');
|
||||
|
||||
$table->foreign('branch_id')
|
||||
->references('id')
|
||||
->on('branches');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user