feat: updates
This commit is contained in:
1
.devcontainer.json
Normal file
1
.devcontainer.json
Normal file
@@ -0,0 +1 @@
|
||||
{"image":"mcr.microsoft.com/devcontainers/base:ubuntu"}
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -18,3 +18,11 @@ yarn-error.log
|
||||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
||||
|
||||
/caddy
|
||||
frankenphp
|
||||
frankenphp-worker.php
|
||||
|
||||
/caddy
|
||||
frankenphp
|
||||
frankenphp-worker.php
|
||||
|
||||
23
app/Actions/Ledgers/CreateLedgerAction.php
Normal file
23
app/Actions/Ledgers/CreateLedgerAction.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Ledgers;
|
||||
|
||||
use App\Actions\BaseAction;
|
||||
use App\Commands\Ledgers\CreateLedgerCommand;
|
||||
use App\DataObjects\CreateLedgerDTO;
|
||||
use Closure;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
class CreateLedgerAction extends BaseAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CreateLedgerCommand $createLedgerCommand,
|
||||
) {}
|
||||
|
||||
public function __invoke(CreateLedgerDTO|Data $payload, Closure $next)
|
||||
{
|
||||
$this->createLedgerCommand->execute($payload->data);
|
||||
|
||||
return $next($payload);
|
||||
}
|
||||
}
|
||||
91
app/Actions/Transactions/CreateTransactionAction.php
Normal file
91
app/Actions/Transactions/CreateTransactionAction.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Transactions;
|
||||
|
||||
use App\Actions\BaseAction;
|
||||
use App\Actions\Ledgers\CreateLedgerAction;
|
||||
use App\DataObjects\CreateLedgerDTO;
|
||||
use App\DataObjects\CreateTransactionDTO;
|
||||
use App\Models\Account;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Pipeline;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
class CreateTransactionAction extends BaseAction
|
||||
{
|
||||
public function __invoke(CreateTransactionDTO|Data $payload, Closure $next)
|
||||
{
|
||||
$payload->transaction = $payload->transactionable->transactions()->create($payload->data);
|
||||
|
||||
$this->transactionAccountLedger($payload);
|
||||
|
||||
$this->withHoldingAccountLedger($payload);
|
||||
|
||||
return $next($payload);
|
||||
}
|
||||
|
||||
public function transactionAccountLedger($payload): void
|
||||
{
|
||||
$branch = $payload->transaction->branch;
|
||||
|
||||
if ($branch->isClientVatable) {
|
||||
//create transaction account ledger
|
||||
$ledgerPayload = new CreateLedgerDTO(
|
||||
branch_id: $payload->transactionable->branch_id,
|
||||
amount: $payload->transaction->net_amount ?? 0.00,
|
||||
transaction: $payload->transaction,
|
||||
account: $payload->transaction->account,
|
||||
);
|
||||
$this->ledgerPipe($ledgerPayload);
|
||||
|
||||
$this->inputTaxAccountLedger($payload);
|
||||
} else {
|
||||
//create transaction account ledger
|
||||
$ledgerPayload = new CreateLedgerDTO(
|
||||
branch_id: $payload->transactionable->branch_id,
|
||||
amount: $payload->transaction->gross_amount ?? 0.00,
|
||||
transaction: $payload->transaction,
|
||||
account: $payload->transaction->account,
|
||||
);
|
||||
$this->ledgerPipe($ledgerPayload);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function ledgerPipe(CreateLedgerDTO $ledgerPayload): mixed
|
||||
{
|
||||
return Pipeline::send(passable: $ledgerPayload)->through([
|
||||
CreateLedgerAction::class,
|
||||
])->thenReturn();
|
||||
}
|
||||
|
||||
public function inputTaxAccountLedger($payload): void
|
||||
{
|
||||
$inputTax = Account::query()->where('account', 'Input Tax')->whereHas('balances', function ($balance) use ($payload) {
|
||||
return $balance->where('branch_id', $payload->transactionable->branch_id);
|
||||
})->first();
|
||||
|
||||
$ledgerPayload = new CreateLedgerDTO(
|
||||
branch_id: $payload->transactionable->branch_id,
|
||||
amount: $payload->transactionable->input_tax ?? 0.00,
|
||||
transaction: $payload->transaction,
|
||||
account: $inputTax,
|
||||
);
|
||||
$this->ledgerPipe($ledgerPayload);
|
||||
}
|
||||
|
||||
public function withHoldingAccountLedger($payload): void
|
||||
{
|
||||
$withholdingAccount = Account::query()->where('account', 'Payable Withholding Tax')->whereHas('balances', function ($balance) use ($payload) {
|
||||
return $balance->where('branch_id', $payload->transactionable->branch_id);
|
||||
})->first();
|
||||
|
||||
$ledgerPayload = new CreateLedgerDTO(
|
||||
branch_id: $payload->transactionable->branch_id,
|
||||
amount: $payload->transaction->payable_withholding_tax,
|
||||
transaction: $payload->transaction,
|
||||
account: $withholdingAccount,
|
||||
);
|
||||
$this->ledgerPipe($ledgerPayload);
|
||||
}
|
||||
}
|
||||
23
app/Commands/Expenses/GenerateVoucher.php
Normal file
23
app/Commands/Expenses/GenerateVoucher.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Commands\Expenses;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Expense;
|
||||
|
||||
class GenerateVoucher
|
||||
{
|
||||
public static function execute(Branch $branch): string
|
||||
{
|
||||
$year = now()->format('y');
|
||||
$lastVoucher = Expense::query()->where('branch_id', $branch->id)->orderBy('created_at', 'desc')->first();
|
||||
|
||||
if (! $lastVoucher) {
|
||||
return $year.'-'.str_pad(1, 6, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$voucherNumber = (int) explode('-', $lastVoucher->voucher_number)[1];
|
||||
|
||||
return $year.'-'.str_pad($voucherNumber + 1, 6, '0', STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
27
app/Commands/Ledgers/CreateLedgerCommand.php
Normal file
27
app/Commands/Ledgers/CreateLedgerCommand.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Commands\Ledgers;
|
||||
|
||||
use App\Commands\Command;
|
||||
use App\Models\Ledger;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class CreateLedgerCommand implements Command
|
||||
{
|
||||
public function execute(array $data): mixed
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
return Ledger::query()->updateOrCreate([
|
||||
'id' => $data['id'] ?? null,
|
||||
'transaction_id' => $data['transaction_id'] ?? null,
|
||||
'account_id' => $data['account_id'] ?? null,
|
||||
], [
|
||||
'credit_amount' => $data['credit_amount'] ?? null,
|
||||
'debit_amount' => $data['debit_amount'] ?? null,
|
||||
'description' => $data['description'] ?? null,
|
||||
'branch_id' => $data['branch_id'] ?? null,
|
||||
'client_id' => $data['client_id'] ?? null,
|
||||
]);
|
||||
}, attempts: 2);
|
||||
}
|
||||
}
|
||||
13
app/Commands/Transactions/CreateTransactionCommand.php
Normal file
13
app/Commands/Transactions/CreateTransactionCommand.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Commands\Transactions;
|
||||
|
||||
use App\Commands\Command;
|
||||
|
||||
class CreateTransactionCommand implements Command
|
||||
{
|
||||
public function execute(array $data): mixed
|
||||
{
|
||||
// TODO: Implement execute() method.
|
||||
}
|
||||
}
|
||||
49
app/DataObjects/CreateLedgerDTO.php
Normal file
49
app/DataObjects/CreateLedgerDTO.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\DataObjects;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Spatie\LaravelData\Attributes\Computed;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
class CreateLedgerDTO extends Data
|
||||
{
|
||||
#[Computed]
|
||||
public array $data;
|
||||
|
||||
#[Computed]
|
||||
public int $transaction_id;
|
||||
|
||||
#[Computed]
|
||||
public int $account_id;
|
||||
|
||||
#[Computed]
|
||||
public int $client_id;
|
||||
|
||||
#[Computed]
|
||||
public ?string $description;
|
||||
|
||||
#[Computed]
|
||||
public float $credit_amount;
|
||||
|
||||
#[Computed]
|
||||
public float $debit_amount;
|
||||
|
||||
public function __construct(
|
||||
public int $branch_id,
|
||||
public float $amount,
|
||||
public ?Model $ledger = null,
|
||||
public ?Model $transaction = null,
|
||||
public ?Model $account = null,
|
||||
) {
|
||||
$this->transaction_id = $this->transaction->id;
|
||||
$this->account_id = $this->account->id;
|
||||
$this->client_id = $this->transaction->branch->client_id;
|
||||
$this->credit_amount = $this->transaction->account_type == 'credit' ? $this->amount : 0.00;
|
||||
$this->debit_amount = $this->transaction->account_type == 'debit' ? $this->amount : 0.00;
|
||||
$this->description = $this->transaction->description;
|
||||
|
||||
$this->data = Arr::except($this->toArray(), ['transaction', 'ledger', 'account', 'amount']);
|
||||
}
|
||||
}
|
||||
15
app/DataObjects/CreateTransactionDTO.php
Normal file
15
app/DataObjects/CreateTransactionDTO.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\DataObjects;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
class CreateTransactionDTO extends Data
|
||||
{
|
||||
public function __construct(
|
||||
public array $data,
|
||||
public ?Model $transaction = null,
|
||||
public ?Model $transactionable = null,
|
||||
) {}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\BranchResource\Pages;
|
||||
use App\Filament\Resources\BranchResource\RelationManagers\BalancesRelationManager;
|
||||
use App\Filament\Resources\BranchResource\RelationManagers\ExpenseRelationManager;
|
||||
use App\Models\Branch;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
@@ -75,6 +76,7 @@ class BranchResource extends Resource
|
||||
return [
|
||||
// AccountsRelationManager::make(),
|
||||
BalancesRelationManager::make(),
|
||||
ExpenseRelationManager::make(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\BranchResource\RelationManagers;
|
||||
|
||||
use App\Filament\Resources\ExpenseResource;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables\Actions\CreateAction;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class ExpenseRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'expenses';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema(ExpenseResource::getExpenseFormFields());
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('branch_id')
|
||||
->columns(ExpenseResource::getTableColumns())
|
||||
->headerActions([
|
||||
CreateAction::make()
|
||||
->mutateFormDataUsing(
|
||||
fn (array $data): array => app(ExpenseResource\Pages\CreateExpense::class)
|
||||
->getFormDataMutation($data)
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class AccountsRelationManager extends RelationManager
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('account')->description(fn (Account $record): string => $record->description ?? ''),
|
||||
Tables\Columns\TextColumn::make('accountType.type'),
|
||||
Tables\Columns\TextColumn::make('normal_balance'),
|
||||
Tables\Columns\TextColumn::make('accountType.normal_balance'),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
|
||||
@@ -2,12 +2,23 @@
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Commands\Expenses\GenerateVoucher;
|
||||
use App\Filament\Resources\ExpenseResource\Pages;
|
||||
use App\Models\Account;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Client;
|
||||
use App\Models\Expense;
|
||||
use Awcodes\TableRepeater\Components\TableRepeater;
|
||||
use Awcodes\TableRepeater\Header;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ExpenseResource extends Resource
|
||||
{
|
||||
@@ -18,21 +29,69 @@ class ExpenseResource extends Resource
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
//
|
||||
]);
|
||||
->schema(static::getExpenseFormFields());
|
||||
}
|
||||
|
||||
public static function getExpenseFormFields(): array
|
||||
{
|
||||
return [
|
||||
Select::make('client')
|
||||
->options(Client::query()->get()->pluck('company', 'id'))->live(),
|
||||
Select::make('branch_id')->options(fn ($get) => Branch::query()->where('client_id', $get('client'))->get()->pluck('code', 'id'))
|
||||
->afterStateUpdated(fn ($state, $set) => $set('voucher_number', GenerateVoucher::execute(Branch::find($state))))->live(),
|
||||
TextInput::make('supplier')->label('Supplier Name'),
|
||||
TextInput::make('reference_number')->label('Reference Number'),
|
||||
TextInput::make('voucher_number')->label('Voucher Number'),
|
||||
DatePicker::make('happened_on')->label('Date')->native(false),
|
||||
|
||||
TableRepeater::make('transactions')
|
||||
->headers([
|
||||
Header::make('Charge Account'),
|
||||
Header::make('Description'),
|
||||
Header::make('Gross Amount'),
|
||||
Header::make('Withholding Tax'),
|
||||
Header::make('Net Amount'),
|
||||
])
|
||||
->schema([
|
||||
Select::make('account_id')->options(fn ($get) => static::getAccountOptions($get)),
|
||||
TextInput::make('description')->label('Description'),
|
||||
TextInput::make('gross_amount'),
|
||||
TextInput::make('payable_withholding_tax'),
|
||||
TextInput::make('net_amount'),
|
||||
])->columnSpan('full'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getAccountOptions(Get $get): Collection
|
||||
{
|
||||
$query = Account::query();
|
||||
|
||||
$query->where([
|
||||
'client_id' => $get('../../client'),
|
||||
]);
|
||||
|
||||
if ($get('../../branch_id')) {
|
||||
$query->whereHas('balances', function ($query) use ($get) {
|
||||
return $query->where('branch_id', $get('../../branch_id'));
|
||||
});
|
||||
}
|
||||
|
||||
$query->whereHas('accountType', function ($query) {
|
||||
return $query->where('type', 'Expenses');
|
||||
});
|
||||
|
||||
return $query->get()->pluck('account', 'id');
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
//
|
||||
])
|
||||
->columns(static::getTableColumns())
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\DeleteAction::make(),
|
||||
Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
@@ -42,6 +101,18 @@ class ExpenseResource extends Resource
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getTableColumns(): array
|
||||
{
|
||||
return [
|
||||
Tables\Columns\TextColumn::make('supplier'),
|
||||
Tables\Columns\TextColumn::make('reference_number'),
|
||||
Tables\Columns\TextColumn::make('voucher_number'),
|
||||
Tables\Columns\TextColumn::make('branch.client.company'),
|
||||
Tables\Columns\TextColumn::make('branch.code'),
|
||||
Tables\Columns\TextColumn::make('happened_on'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -2,10 +2,57 @@
|
||||
|
||||
namespace App\Filament\Resources\ExpenseResource\Pages;
|
||||
|
||||
use App\Actions\Transactions\CreateTransactionAction;
|
||||
use App\DataObjects\CreateTransactionDTO;
|
||||
use App\Filament\Resources\ExpenseResource;
|
||||
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;
|
||||
|
||||
protected function mutateFormDataBeforeCreate(array $data): array
|
||||
{
|
||||
return $this->getFormDataMutation($data);
|
||||
}
|
||||
|
||||
public function getFormDataMutation(array $data): array
|
||||
{
|
||||
return Arr::except($data, ['client', 'transactions']);
|
||||
}
|
||||
|
||||
protected function afterCreate()
|
||||
{
|
||||
$transactions = Arr::only($this->form->getState(), ['transactions']);
|
||||
|
||||
try {
|
||||
$branch = $this->getRecord()->branch;
|
||||
|
||||
foreach ($transactions as $transaction) {
|
||||
|
||||
$data = [
|
||||
'branch_id' => $branch->id,
|
||||
'happened_on' => $this->getRecord()->happened_on,
|
||||
...Arr::first($transaction),
|
||||
];
|
||||
|
||||
$payload = new CreateTransactionDTO(data: $data, transactionable: $this->getRecord());
|
||||
|
||||
Pipeline::send(passable: $payload)->through(
|
||||
[
|
||||
CreateTransactionAction::class,
|
||||
]
|
||||
)->thenReturn();
|
||||
}
|
||||
|
||||
$this->commitDatabaseTransaction();
|
||||
} catch (Exception $exception) {
|
||||
$this->rollBackDatabaseTransaction();
|
||||
throw new LogicException('Failed to save transactions : '.$exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ class RoleResource extends Resource implements HasShieldPermissions
|
||||
);
|
||||
|
||||
return Forms\Components\Section::make($sectionLabel)
|
||||
->description(fn () => new HtmlString('<span style="word-break: break-word;">' . Utils::showModelPath($entity['fqcn']) . '</span>'))
|
||||
->description(fn () => new HtmlString('<span style="word-break: break-word;">'.Utils::showModelPath($entity['fqcn']).'</span>'))
|
||||
->compact()
|
||||
->schema([
|
||||
static::getCheckBoxListComponentForResource($entity),
|
||||
@@ -231,7 +231,7 @@ class RoleResource extends Resource implements HasShieldPermissions
|
||||
{
|
||||
return collect(Utils::getResourcePermissionPrefixes($entity['fqcn']))
|
||||
->flatMap(function ($permission) use ($entity) {
|
||||
$name = $permission . '_' . $entity['resource'];
|
||||
$name = $permission.'_'.$entity['resource'];
|
||||
$label = static::shield()->hasLocalizedPermissionLabels()
|
||||
? FilamentShield::getLocalizedResourcePermissionLabel($permission)
|
||||
: $name;
|
||||
|
||||
@@ -16,6 +16,11 @@ class Account extends Model
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function getTypeAttribute(): string
|
||||
{
|
||||
return $this->accountType->type;
|
||||
}
|
||||
|
||||
public function accountType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AccountType::class);
|
||||
|
||||
@@ -18,14 +18,6 @@ class Branch extends Model
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* Get the client that owns the Branch
|
||||
*/
|
||||
public function client(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Client::class);
|
||||
}
|
||||
|
||||
public function getCurrentSeriesAttribute()
|
||||
{
|
||||
if ($this->series()->count() > 0) {
|
||||
@@ -43,8 +35,21 @@ class Branch extends Model
|
||||
return $this->hasMany(Series::class);
|
||||
}
|
||||
|
||||
public function getIsClientVatableAttribute(): bool
|
||||
{
|
||||
return $this->client->vatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the sales for the Branch
|
||||
* Get the client that owns the Branch
|
||||
*/
|
||||
public function client(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Client::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the sales for the Branch
|
||||
*/
|
||||
public function sales(): HasMany
|
||||
{
|
||||
@@ -52,7 +57,7 @@ class Branch extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the expenses for the Branch
|
||||
* Get all the expenses for the Branch
|
||||
*/
|
||||
public function expenses(): HasMany
|
||||
{
|
||||
@@ -68,4 +73,9 @@ class Branch extends Model
|
||||
{
|
||||
return $this->belongsToThrough(Account::class, Balance::class);
|
||||
}
|
||||
|
||||
public function transactions(): HasMany
|
||||
{
|
||||
return $this->hasMany(Transaction::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,13 @@ class Client extends Model
|
||||
return $this->lname.', '.$this->fname.' '.$this->mname;
|
||||
}
|
||||
|
||||
public function getVatableAttribute()
|
||||
public function getVatableAttribute(): bool
|
||||
{
|
||||
return $this->type->type == 'Vatable' ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the branches for the Client
|
||||
* Get all the branches for the Client
|
||||
*/
|
||||
public function branches(): HasMany
|
||||
{
|
||||
|
||||
@@ -4,8 +4,29 @@ 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\MorphToMany;
|
||||
|
||||
class Expense extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = [
|
||||
'happened_on' => 'date:Y-m-d',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get all the transactions for the Sale
|
||||
*/
|
||||
public function transactions(): MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Transaction::class, 'transactionable');
|
||||
}
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,14 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
|
||||
class Sale extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public function transactions(): MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Transaction::class, 'transactionable');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
class Transaction extends Model
|
||||
{
|
||||
@@ -13,43 +15,36 @@ class Transaction extends Model
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* Get the expense that owns the Transaction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function expense(): BelongsTo
|
||||
public function transactionable(): MorphTo
|
||||
{
|
||||
return $this->belongsTo(Expense::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sale that owns the Transaction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function sale(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Sale::class);
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account that owns the Transaction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function account(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function getAccountTypeAttribute(): string
|
||||
{
|
||||
return $this->account->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ledgers associated with the Transaction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
* @return HasOne
|
||||
*/
|
||||
public function ledgers(): HasMany
|
||||
{
|
||||
return $this->hasMany(Ledger::class);
|
||||
}
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class);
|
||||
}
|
||||
}
|
||||
|
||||
68
app/Observers/ExpenseObserver.php
Normal file
68
app/Observers/ExpenseObserver.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Commands\Ledgers\CreateLedgerCommand;
|
||||
use App\Models\Expense;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ExpenseObserver
|
||||
{
|
||||
/**
|
||||
* Handle the Expense "created" event.
|
||||
*/
|
||||
public function created(Expense $expense): void
|
||||
{
|
||||
DB::transaction(
|
||||
callback: function () use ($expense) {
|
||||
$branch = $expense->branch;
|
||||
//check if client is vatable
|
||||
if ($branch->isClientVatable) {
|
||||
// create a ledgers for vatable
|
||||
$data = [
|
||||
'transaction_id' => $expense->transaction_id,
|
||||
];
|
||||
|
||||
$payload = new CreateLedgerCommand(data: $data);
|
||||
} else {
|
||||
// create a lkedgers for non vatable
|
||||
}
|
||||
|
||||
//create cash transaction
|
||||
},
|
||||
attempts: 2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Expense "updated" event.
|
||||
*/
|
||||
public function updated(Expense $expense): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Expense "deleted" event.
|
||||
*/
|
||||
public function deleted(Expense $expense): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Expense "restored" event.
|
||||
*/
|
||||
public function restored(Expense $expense): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Expense "force deleted" event.
|
||||
*/
|
||||
public function forceDeleted(Expense $expense): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
108
app/Policies/BranchPolicy.php
Normal file
108
app/Policies/BranchPolicy.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class BranchPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('view_any_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Branch $branch): bool
|
||||
{
|
||||
return $user->can('view_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->can('create_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Branch $branch): bool
|
||||
{
|
||||
return $user->can('update_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Branch $branch): bool
|
||||
{
|
||||
return $user->can('delete_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk delete.
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('delete_any_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete.
|
||||
*/
|
||||
public function forceDelete(User $user, Branch $branch): bool
|
||||
{
|
||||
return $user->can('force_delete_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently bulk delete.
|
||||
*/
|
||||
public function forceDeleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('force_delete_any_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore.
|
||||
*/
|
||||
public function restore(User $user, Branch $branch): bool
|
||||
{
|
||||
return $user->can('restore_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk restore.
|
||||
*/
|
||||
public function restoreAny(User $user): bool
|
||||
{
|
||||
return $user->can('restore_any_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can replicate.
|
||||
*/
|
||||
public function replicate(User $user, Branch $branch): bool
|
||||
{
|
||||
return $user->can('replicate_branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can reorder.
|
||||
*/
|
||||
public function reorder(User $user): bool
|
||||
{
|
||||
return $user->can('reorder_branch');
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Client;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ClientPolicy
|
||||
|
||||
108
app/Policies/ExpensePolicy.php
Normal file
108
app/Policies/ExpensePolicy.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ExpensePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('view_any_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Expense $expense): bool
|
||||
{
|
||||
return $user->can('view_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->can('create_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Expense $expense): bool
|
||||
{
|
||||
return $user->can('update_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Expense $expense): bool
|
||||
{
|
||||
return $user->can('delete_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk delete.
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('delete_any_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete.
|
||||
*/
|
||||
public function forceDelete(User $user, Expense $expense): bool
|
||||
{
|
||||
return $user->can('force_delete_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently bulk delete.
|
||||
*/
|
||||
public function forceDeleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('force_delete_any_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore.
|
||||
*/
|
||||
public function restore(User $user, Expense $expense): bool
|
||||
{
|
||||
return $user->can('restore_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk restore.
|
||||
*/
|
||||
public function restoreAny(User $user): bool
|
||||
{
|
||||
return $user->can('restore_any_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can replicate.
|
||||
*/
|
||||
public function replicate(User $user, Expense $expense): bool
|
||||
{
|
||||
return $user->can('replicate_expense');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can reorder.
|
||||
*/
|
||||
public function reorder(User $user): bool
|
||||
{
|
||||
return $user->can('reorder_expense');
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class RolePolicy
|
||||
{
|
||||
|
||||
108
app/Policies/SalePolicy.php
Normal file
108
app/Policies/SalePolicy.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class SalePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('view_any_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Sale $sale): bool
|
||||
{
|
||||
return $user->can('view_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->can('create_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Sale $sale): bool
|
||||
{
|
||||
return $user->can('update_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Sale $sale): bool
|
||||
{
|
||||
return $user->can('delete_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk delete.
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('delete_any_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete.
|
||||
*/
|
||||
public function forceDelete(User $user, Sale $sale): bool
|
||||
{
|
||||
return $user->can('force_delete_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently bulk delete.
|
||||
*/
|
||||
public function forceDeleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('force_delete_any_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore.
|
||||
*/
|
||||
public function restore(User $user, Sale $sale): bool
|
||||
{
|
||||
return $user->can('restore_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk restore.
|
||||
*/
|
||||
public function restoreAny(User $user): bool
|
||||
{
|
||||
return $user->can('restore_any_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can replicate.
|
||||
*/
|
||||
public function replicate(User $user, Sale $sale): bool
|
||||
{
|
||||
return $user->can('replicate_sale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can reorder.
|
||||
*/
|
||||
public function reorder(User $user): bool
|
||||
{
|
||||
return $user->can('reorder_sale');
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Transmittal;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class TransmittalPolicy
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class UserPolicy
|
||||
@@ -12,9 +11,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
@@ -23,9 +19,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function view(User $user): bool
|
||||
{
|
||||
@@ -34,9 +27,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
@@ -45,9 +35,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user): bool
|
||||
{
|
||||
@@ -56,9 +43,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(User $user): bool
|
||||
{
|
||||
@@ -67,9 +51,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk delete.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
@@ -78,9 +59,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function forceDelete(User $user): bool
|
||||
{
|
||||
@@ -89,9 +67,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently bulk delete.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function forceDeleteAny(User $user): bool
|
||||
{
|
||||
@@ -100,9 +75,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function restore(User $user): bool
|
||||
{
|
||||
@@ -111,9 +83,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk restore.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function restoreAny(User $user): bool
|
||||
{
|
||||
@@ -122,9 +91,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk restore.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function replicate(User $user): bool
|
||||
{
|
||||
@@ -133,9 +99,6 @@ class UserPolicy
|
||||
|
||||
/**
|
||||
* Determine whether the user can reorder.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function reorder(User $user): bool
|
||||
{
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Policies\RolePolicy;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -19,6 +22,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
Gate::policy(Role::class, RolePolicy::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\Filament\AdminPanelProvider::class,
|
||||
App\Providers\HorizonServiceProvider::class,
|
||||
App\Providers\VoltServiceProvider::class,
|
||||
];
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"awcodes/filament-table-repeater": "^3.0",
|
||||
"bezhansalleh/filament-shield": "^3.2",
|
||||
"filament/filament": "^3.2",
|
||||
"laravel/framework": "^11.9",
|
||||
|
||||
601
composer.lock
generated
601
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -30,10 +31,9 @@ return new class () extends Migration {
|
||||
$table->decimal('payable_withholding_tax')->nullable();
|
||||
$table->decimal('creditable_withholding_tax')->nullable();
|
||||
|
||||
$table->foreignId('expense_id')->nullable()->constrained()->onDelete('cascade');
|
||||
$table->foreignId('sale_id')->nullable()->constrained()->onDelete('cascade');
|
||||
$table->morphs('transactionable');
|
||||
|
||||
$table->foreignId('branch_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('client_id')->constrained()->onDelete('cascade');
|
||||
$table->date('happened_on');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
@@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -12,7 +13,7 @@ return new class () extends Migration {
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('transmittal', function (Blueprint $table) {
|
||||
Schema::create('transmittals', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('series');
|
||||
$table->foreignId('client_id')->constrained();
|
||||
|
||||
@@ -14,8 +14,8 @@ return new class extends Migration
|
||||
public function up()
|
||||
{
|
||||
Schema::table('transactions', function (Blueprint $table) {
|
||||
$table->boolean('with_discount')->after('client_id')->nullable();
|
||||
$table->decimal('discount')->after('client_id')->nullable();
|
||||
$table->boolean('with_discount')->nullable();
|
||||
$table->decimal('discount')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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('transactionables', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('transaction_id');
|
||||
$table->unsignedBigInteger('transactionable_id');
|
||||
$table->string('transactionable_type');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('transactionables');
|
||||
}
|
||||
};
|
||||
68
database/seeders/ShieldSeeder.php
Normal file
68
database/seeders/ShieldSeeder.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use BezhanSalleh\FilamentShield\Support\Utils;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\PermissionRegistrar;
|
||||
|
||||
class ShieldSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
app()[PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
$rolesWithPermissions = '[{"name":"super_admin","guard_name":"web","permissions":[]}]';
|
||||
$directPermissions = '[]';
|
||||
|
||||
static::makeRolesWithPermissions($rolesWithPermissions);
|
||||
static::makeDirectPermissions($directPermissions);
|
||||
|
||||
$this->command->info('Shield Seeding Completed.');
|
||||
}
|
||||
|
||||
protected static function makeRolesWithPermissions(string $rolesWithPermissions): void
|
||||
{
|
||||
if (! blank($rolePlusPermissions = json_decode($rolesWithPermissions, true))) {
|
||||
/** @var Model $roleModel */
|
||||
$roleModel = Utils::getRoleModel();
|
||||
/** @var Model $permissionModel */
|
||||
$permissionModel = Utils::getPermissionModel();
|
||||
|
||||
foreach ($rolePlusPermissions as $rolePlusPermission) {
|
||||
$role = $roleModel::firstOrCreate([
|
||||
'name' => $rolePlusPermission['name'],
|
||||
'guard_name' => $rolePlusPermission['guard_name'],
|
||||
]);
|
||||
|
||||
if (! blank($rolePlusPermission['permissions'])) {
|
||||
$permissionModels = collect($rolePlusPermission['permissions'])
|
||||
->map(fn ($permission) => $permissionModel::firstOrCreate([
|
||||
'name' => $permission,
|
||||
'guard_name' => $rolePlusPermission['guard_name'],
|
||||
]))
|
||||
->all();
|
||||
|
||||
$role->syncPermissions($permissionModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function makeDirectPermissions(string $directPermissions): void
|
||||
{
|
||||
if (! blank($permissions = json_decode($directPermissions, true))) {
|
||||
/** @var Model $permissionModel */
|
||||
$permissionModel = Utils::getPermissionModel();
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
if ($permissionModel::whereName($permission)->doesntExist()) {
|
||||
$permissionModel::create([
|
||||
'name' => $permission['name'],
|
||||
'guard_name' => $permission['guard_name'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
docker-compose.yml
Normal file
58
docker-compose.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
services:
|
||||
laravel.test:
|
||||
build:
|
||||
context: ./vendor/laravel/sail/runtimes/8.3
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
WWWGROUP: '${WWWGROUP}'
|
||||
image: sail-8.3/app
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
ports:
|
||||
- '${APP_PORT:-80}:80'
|
||||
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
|
||||
environment:
|
||||
WWWUSER: '${WWWUSER}'
|
||||
LARAVEL_SAIL: 1
|
||||
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
|
||||
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
|
||||
IGNITION_LOCAL_SITES_PATH: '${PWD}'
|
||||
SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=frankenphp --host=0.0.0.0 --admin-port=2019 --port=80"
|
||||
XDG_CONFIG_HOME: /var/www/html/config
|
||||
XDG_DATA_HOME: /var/www/html/data
|
||||
volumes:
|
||||
- '.:/var/www/html'
|
||||
networks:
|
||||
- sail
|
||||
depends_on:
|
||||
- mysql
|
||||
mysql:
|
||||
image: 'mysql/mysql-server:8.0'
|
||||
ports:
|
||||
- '${FORWARD_DB_PORT:-3306}:3306'
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
|
||||
MYSQL_ROOT_HOST: '%'
|
||||
MYSQL_DATABASE: '${DB_DATABASE}'
|
||||
MYSQL_USER: '${DB_USERNAME}'
|
||||
MYSQL_PASSWORD: '${DB_PASSWORD}'
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: 1
|
||||
volumes:
|
||||
- 'sail-mysql:/var/lib/mysql'
|
||||
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
|
||||
networks:
|
||||
- sail
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- mysqladmin
|
||||
- ping
|
||||
- '-p${DB_PASSWORD}'
|
||||
retries: 3
|
||||
timeout: 5s
|
||||
networks:
|
||||
sail:
|
||||
driver: bridge
|
||||
volumes:
|
||||
sail-mysql:
|
||||
driver: local
|
||||
62
package-lock.json
generated
62
package-lock.json
generated
@@ -6,13 +6,13 @@
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"@tailwindcss/typography": "^0.5.14",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.6.4",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.40",
|
||||
"postcss": "^8.4.41",
|
||||
"postcss-nesting": "^12.1.5",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"tailwindcss": "^3.4.9",
|
||||
"vite": "^5.0"
|
||||
}
|
||||
},
|
||||
@@ -771,9 +771,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography": {
|
||||
"version": "0.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz",
|
||||
"integrity": "sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==",
|
||||
"version": "0.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.14.tgz",
|
||||
"integrity": "sha512-ZvOCjUbsJBjL9CxQBn+VEnFpouzuKhxh2dH8xMIWHILL+HfOYtlAkWcyoon8LlzE53d2Yo6YO6pahKKNW3q1YQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash.castarray": "^4.4.0",
|
||||
@@ -860,9 +860,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.19",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
|
||||
"integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
|
||||
"version": "10.4.20",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
|
||||
"integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -879,11 +879,11 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.0",
|
||||
"caniuse-lite": "^1.0.30001599",
|
||||
"browserslist": "^4.23.3",
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"fraction.js": "^4.3.7",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.0",
|
||||
"picocolors": "^1.0.1",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -947,9 +947,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.23.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz",
|
||||
"integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
|
||||
"version": "4.23.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
|
||||
"integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -966,9 +966,9 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001640",
|
||||
"electron-to-chromium": "^1.4.820",
|
||||
"node-releases": "^2.0.14",
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"electron-to-chromium": "^1.5.4",
|
||||
"node-releases": "^2.0.18",
|
||||
"update-browserslist-db": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -988,9 +988,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001643",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz",
|
||||
"integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==",
|
||||
"version": "1.0.30001651",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz",
|
||||
"integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -1136,9 +1136,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.1.tgz",
|
||||
"integrity": "sha512-FKbOCOQ5QRB3VlIbl1LZQefWIYwszlBloaXcY2rbfpu9ioJnNh3TK03YtIDKDo3WKBi8u+YV4+Fn2CkEozgf4w==",
|
||||
"version": "1.5.6",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz",
|
||||
"integrity": "sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
@@ -1748,9 +1748,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.40",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz",
|
||||
"integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==",
|
||||
"version": "8.4.41",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
|
||||
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2234,9 +2234,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz",
|
||||
"integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==",
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz",
|
||||
"integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"@tailwindcss/typography": "^0.5.14",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.6.4",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.40",
|
||||
"postcss": "^8.4.41",
|
||||
"postcss-nesting": "^12.1.5",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"tailwindcss": "^3.4.9",
|
||||
"vite": "^5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
|
||||
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
|
||||
<env name="DB_DATABASE" value="testing"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="PULSE_ENABLED" value="false"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
function r({state:i}){return{state:i,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(t,e)=>{let s=o=>o===null?0:Array.isArray(o)?o.length:typeof o!="object"?0:Object.keys(o).length;s(t)===0&&s(e)===0||this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows:function(t){let e=Alpine.raw(this.rows),s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.rows=e,this.updateState()},updateRows:function(){if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{r as default};
|
||||
function r({state:o}){return{state:o,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(t,e)=>{let s=i=>i===null?0:Array.isArray(i)?i.length:typeof i!="object"?0:Object.keys(i).length;s(t)===0&&s(e)===0||this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows:function(t){let e=Alpine.raw(this.rows);this.rows=[];let s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.$nextTick(()=>{this.rows=e,this.updateState()})},updateRows:function(){if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{r as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
function t({initialHeight:e}){return{init:function(){this.render()},render:function(){this.$el.scrollHeight>0&&(this.$el.style.height=e+"rem",this.$el.style.height=this.$el.scrollHeight+"px")}}}export{t as default};
|
||||
function r({initialHeight:t,shouldAutosize:i,state:s}){return{state:s,wrapperEl:null,init:function(){this.wrapperEl=this.$el.parentNode,this.setInitialHeight(),i?this.$watch("state",()=>{this.resize()}):this.setUpResizeObserver()},setInitialHeight:function(){this.$el.scrollHeight<=0||(this.wrapperEl.style.height=t+"rem")},resize:function(){if(this.setInitialHeight(),this.$el.scrollHeight<=0)return;let e=this.$el.scrollHeight+"px";this.wrapperEl.style.height!==e&&(this.wrapperEl.style.height=e)},setUpResizeObserver:function(){new ResizeObserver(()=>{this.wrapperEl.style.height=this.$el.style.height}).observe(this.$el)}}}export{r as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
function c(){return{collapsedGroups:[],isLoading:!1,selectedRecords:[],shouldCheckUniqueSelection:!0,init:function(){this.$wire.$on("deselectAllTableRecords",()=>this.deselectAllRecords()),this.$watch("selectedRecords",()=>{if(!this.shouldCheckUniqueSelection){this.shouldCheckUniqueSelection=!0;return}this.selectedRecords=[...new Set(this.selectedRecords)],this.shouldCheckUniqueSelection=!1})},mountAction:function(e,s=null){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableAction(e,s)},mountBulkAction:function(e){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableBulkAction(e)},toggleSelectRecordsOnPage:function(){let e=this.getRecordsOnPage();if(this.areRecordsSelected(e)){this.deselectRecords(e);return}this.selectRecords(e)},toggleSelectRecordsInGroup:async function(e){if(this.isLoading=!0,this.areRecordsSelected(this.getRecordsInGroupOnPage(e))){this.deselectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e));return}this.selectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e)),this.isLoading=!1},getRecordsInGroupOnPage:function(e){let s=[];for(let t of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])t.dataset.group===e&&s.push(t.value);return s},getRecordsOnPage:function(){let e=[];for(let s of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])e.push(s.value);return e},selectRecords:function(e){for(let s of e)this.isRecordSelected(s)||this.selectedRecords.push(s)},deselectRecords:function(e){for(let s of e){let t=this.selectedRecords.indexOf(s);t!==-1&&this.selectedRecords.splice(t,1)}},selectAllRecords:async function(){this.isLoading=!0,this.selectedRecords=await this.$wire.getAllSelectableTableRecordKeys(),this.isLoading=!1},deselectAllRecords:function(){this.selectedRecords=[]},isRecordSelected:function(e){return this.selectedRecords.includes(e)},areRecordsSelected:function(e){return e.every(s=>this.isRecordSelected(s))},toggleCollapseGroup:function(e){if(this.isGroupCollapsed(e)){this.collapsedGroups.splice(this.collapsedGroups.indexOf(e),1);return}this.collapsedGroups.push(e)},isGroupCollapsed:function(e){return this.collapsedGroups.includes(e)},resetCollapsedGroups:function(){this.collapsedGroups=[]}}}export{c as default};
|
||||
function n(){return{checkboxClickController:null,collapsedGroups:[],isLoading:!1,selectedRecords:[],shouldCheckUniqueSelection:!0,lastCheckedRecord:null,livewireId:null,init:function(){this.livewireId=this.$root.closest("[wire\\:id]").attributes["wire:id"].value,this.$wire.$on("deselectAllTableRecords",()=>this.deselectAllRecords()),this.$watch("selectedRecords",()=>{if(!this.shouldCheckUniqueSelection){this.shouldCheckUniqueSelection=!0;return}this.selectedRecords=[...new Set(this.selectedRecords)],this.shouldCheckUniqueSelection=!1}),this.$nextTick(()=>this.watchForCheckboxClicks()),Livewire.hook("element.init",({component:e})=>{e.id===this.livewireId&&this.watchForCheckboxClicks()})},mountAction:function(e,t=null){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableAction(e,t)},mountBulkAction:function(e){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableBulkAction(e)},toggleSelectRecordsOnPage:function(){let e=this.getRecordsOnPage();if(this.areRecordsSelected(e)){this.deselectRecords(e);return}this.selectRecords(e)},toggleSelectRecordsInGroup:async function(e){if(this.isLoading=!0,this.areRecordsSelected(this.getRecordsInGroupOnPage(e))){this.deselectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e));return}this.selectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e)),this.isLoading=!1},getRecordsInGroupOnPage:function(e){let t=[];for(let s of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])s.dataset.group===e&&t.push(s.value);return t},getRecordsOnPage:function(){let e=[];for(let t of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])e.push(t.value);return e},selectRecords:function(e){for(let t of e)this.isRecordSelected(t)||this.selectedRecords.push(t)},deselectRecords:function(e){for(let t of e){let s=this.selectedRecords.indexOf(t);s!==-1&&this.selectedRecords.splice(s,1)}},selectAllRecords:async function(){this.isLoading=!0,this.selectedRecords=await this.$wire.getAllSelectableTableRecordKeys(),this.isLoading=!1},deselectAllRecords:function(){this.selectedRecords=[]},isRecordSelected:function(e){return this.selectedRecords.includes(e)},areRecordsSelected:function(e){return e.every(t=>this.isRecordSelected(t))},toggleCollapseGroup:function(e){if(this.isGroupCollapsed(e)){this.collapsedGroups.splice(this.collapsedGroups.indexOf(e),1);return}this.collapsedGroups.push(e)},isGroupCollapsed:function(e){return this.collapsedGroups.includes(e)},resetCollapsedGroups:function(){this.collapsedGroups=[]},watchForCheckboxClicks:function(){this.checkboxClickController&&this.checkboxClickController.abort(),this.checkboxClickController=new AbortController;let{signal:e}=this.checkboxClickController;this.$root?.addEventListener("click",t=>t.target?.matches(".fi-ta-record-checkbox")&&this.handleCheckboxClick(t,t.target),{signal:e})},handleCheckboxClick:function(e,t){if(!this.lastChecked){this.lastChecked=t;return}if(e.shiftKey){let s=Array.from(this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[]);if(!s.includes(this.lastChecked)){this.lastChecked=t;return}let o=s.indexOf(this.lastChecked),r=s.indexOf(t),l=[o,r].sort((i,d)=>i-d),c=[];for(let i=l[0];i<=l[1];i++)s[i].checked=t.checked,c.push(s[i].value);t.checked?this.selectRecords(c):this.deselectRecords(c)}this.lastChecked=t}}}export{n as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,5 +6,6 @@ export default {
|
||||
'./app/Filament/**/*.php',
|
||||
'./resources/views/filament/**/*.blade.php',
|
||||
'./vendor/filament/**/*.blade.php',
|
||||
'./vendor/awcodes/filament-table-repeater/resources/**/*.blade.php'
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
@import '/vendor/filament/filament/resources/css/theme.css';
|
||||
@import '/vendor/awcodes/filament-table-repeater/resources/css/plugin.css';
|
||||
|
||||
@config 'tailwind.config.js';
|
||||
|
||||
.fi-btn , .fi-input-wrp, .fi-tabs, .fi-sidebar-item-button, .fi-section {
|
||||
.fi-btn, .fi-input-wrp, .fi-tabs, .fi-sidebar-item-button, .fi-section {
|
||||
@apply rounded-sm !important;
|
||||
}
|
||||
|
||||
@@ -10,7 +11,7 @@
|
||||
@apply mx-0 rounded-sm ring-0 shadow !important;
|
||||
}
|
||||
|
||||
.fi-resource-relation-managers , .fi-ta {
|
||||
.fi-resource-relation-managers, .fi-ta {
|
||||
@apply gap-y-0 shadow-none bg-none;
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@
|
||||
@apply bg-primary-500 bg-opacity-10 !important;
|
||||
}
|
||||
|
||||
.fi-ta-table> thead > tr {
|
||||
.fi-ta-table > thead > tr {
|
||||
@apply bg-primary-400 bg-opacity-40 !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Transmittal;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::view('/', 'welcome');
|
||||
Route::redirect('/', '/admin');
|
||||
|
||||
Route::view('dashboard', 'dashboard')
|
||||
->middleware(['auth', 'verified'])
|
||||
@@ -12,10 +13,9 @@ Route::view('profile', 'profile')
|
||||
->middleware(['auth'])
|
||||
->name('profile');
|
||||
|
||||
|
||||
Route::get('preview-transmittal',function () {
|
||||
return view('transmittal.export.transmittal-export-table')->with(['transmittals' => \App\Models\Transmittal::withCount(['files','notes','remarks'])->with(['files' => function($files) {
|
||||
$files->withCount(['notes','remarks']);
|
||||
Route::get('preview-transmittal', function () {
|
||||
return view('transmittal.export.transmittal-export-table')->with(['transmittals' => Transmittal::withCount(['files', 'notes', 'remarks'])->with(['files' => function ($files) {
|
||||
$files->withCount(['notes', 'remarks']);
|
||||
}])->get()]);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user