ifnex/04_Laravel/app/Filament/Resources/ShipmentChecklistResource.php
Kazem Alghasi 02c29db696 feat(core): implement order approval flow, credit system, and import invoicing
Introduce a comprehensive set of commercial features including a multi-step
order approval workflow, customer credit management, and specialized
import service invoicing.

Key changes:
- Implement `pending_approval` and `approved` shipment statuses to allow
  staff verification before customer payment.
- Add a credit system to `User` model with `credit_limit` and `credit_used`
  to manage customer balances and debts.
- Develop a new `importInvoice` PDF generation service following the
  "Sheet ENG Invoice" specification for import services.
- Add Filament resources for managing Audit Logs, Commitment Forms,
  Customer Credits, and Shipment Checklists.
- Implement staff-specific APIs for order approval/rejection and
  customer financial status monitoring.
- Integrate Kavenegar SMS service for mobile verification and notifications.
- Add bulk tracking import functionality via CSV/Excel.
- Update WordPress bridge assets (CSS/JS) to support the new multi-step
  order form UI and updated redirection logic.
- Update deployment configurations and documentation to reflect new
  production domains and feature sets.
2026-09-03 06:04:20 +03:30

197 lines
8.6 KiB
PHP

<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ShipmentChecklistResource\Pages;
use App\Models\ShipmentChecklist;
use App\Enums\ShipmentStatus;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
class ShipmentChecklistResource extends Resource
{
protected static ?string $model = ShipmentChecklist::class;
protected static ?string $navigationIcon = 'heroicon-o-clipboard-document-check';
protected static ?string $navigationGroup = 'مدیریت عملیات';
protected static ?string $navigationLabel = 'چک‌لیست سفارشات';
protected static ?string $modelLabel = 'چک‌لیست سفارش';
protected static ?string $pluralModelLabel = 'چک‌لیست سفارشات';
protected static ?int $navigationSort = 15;
public static function form(Form $form): Form
{
return $form->schema([
Forms\Components\Section::make('اطلاعات سفارش')
->schema([
Forms\Components\Select::make('shipment_id')
->label('سفارش')
->relationship('shipment', 'awb_no')
->searchable()
->required()
->getOptionLabelFromRecordUsing(fn ($record) => "{$record->awb_no} - {$record->status->label()}"),
Forms\Components\Select::make('user_id')
->label('کارمند')
->relationship('user', 'name')
->searchable()
->required(),
])->columns(2),
Forms\Components\Section::make('اطلاعات چک‌لیست')
->schema([
Forms\Components\Select::make('status')
->label('وضعیت فعلی')
->options(collect(ShipmentStatus::cases())->mapWithKeys(fn ($status) => [$status->value => $status->label()])->toArray())
->required(),
Forms\Components\Toggle::make('is_completed')
->label('تکمیل شده')
->default(false),
Forms\Components\Textarea::make('notes')
->label('یادداشت‌ها')
->rows(3),
Forms\Components\DateTimePicker::make('completed_at')
->label('زمان تکمیل')
->disabled(),
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('شناسه')
->sortable(),
Tables\Columns\TextColumn::make('shipment.awb_no')
->label('شماره سفارش')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('user.name')
->label('کارمند')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('status')
->label('وضعیت')
->formatStateUsing(fn ($state) => match($state) {
'pending_approval' => 'در انتظار تأیید',
'approved' => 'تأیید شده',
'pending_payment' => 'در انتظار پرداخت',
'paid' => 'پرداخت شده',
'processed' => 'در حال پردازش',
'picked_up' => 'جمع‌آوری شده',
'in_transit' => 'در حال ارسال',
'out_for_delivery' => 'آماده تحویل',
'delivered' => 'تحویل شده',
'cancelled' => 'لغو شده',
default => $state,
})
->badge()
->color(fn ($state) => match($state) {
'pending_approval' => 'warning',
'approved' => 'info',
'pending_payment' => 'warning',
'paid' => 'success',
'processed' => 'info',
'picked_up' => 'info',
'in_transit' => 'primary',
'out_for_delivery' => 'success',
'delivered' => 'success',
'cancelled' => 'danger',
default => 'gray',
}),
Tables\Columns\IconColumn::make('is_completed')
->label('تکمیل')
->boolean(),
Tables\Columns\TextColumn::make('notes')
->label('یادداشت')
->limit(50)
->wrap(),
Tables\Columns\TextColumn::make('created_at')
->label('تاریخ ایجاد')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('completed_at')
->label('زمان تکمیل')
->dateTime()
->sortable(),
])
->filters([
Tables\Filters\SelectFilter::make('is_completed')
->label('وضعیت تکمیل')
->options([
'completed' => 'تکمیل شده',
'pending' => 'در انتظار',
])
->query(function ($query, $filter) {
match ($filter->getState()) {
'completed' => $query->where('is_completed', true),
'pending' => $query->where('is_completed', false),
};
}),
Tables\Filters\SelectFilter::make('status')
->label('وضعیت سفارش')
->options(collect(ShipmentStatus::cases())->mapWithKeys(fn ($status) => [$status->value => $status->label()])->toArray()),
Tables\Filters\SelectFilter::make('user_id')
->label('کارمند')
->relationship('user', 'name')
->searchable(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('complete')
->label('تکمیل')
->icon('heroicon-o-check-circle')
->color('success')
->requiresConfirmation()
->modalHeading('تأیید تکمیل')
->modalDescription('آیا از تکمیل این چک‌لیست اطمینان دارید؟')
->action(fn ($record) => $record->complete())
->visible(fn ($record) => !$record->is_completed),
Tables\Actions\Action::make('add_note')
->label('افزودن یادداشت')
->icon('heroicon-o-chat-bubble-bottom-center-text')
->color('info')
->form([
Forms\Components\Textarea::make('note')
->label('یادداشت جدید')
->required(),
])
->action(function ($record, array $data): void {
$existingNotes = $record->notes ? $record->notes . "\n\n" : '';
$record->update([
'notes' => $existingNotes . "[" . now()->format('Y-m-d H:i') . "] " . $data['note'],
]);
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [];
}
public static function getPages(): array
{
return [
'index' => Pages\ListShipmentChecklists::route('/'),
'create' => Pages\CreateShipmentChecklist::route('/create'),
'edit' => Pages\EditShipmentChecklist::route('/{record}/edit'),
];
}
public static function getNavigationBadge(): ?string
{
return static::getModel()::where('is_completed', false)->count();
}
}