schema([ Forms\Components\Section::make('Route & Status') ->schema([ Forms\Components\TextInput::make('awb_no') ->required() ->unique(ignoreRecord: true) ->label('AWB No.'), Forms\Components\Select::make('direction') ->options([ 'export' => 'Export', 'import' => 'Import' ]) ->required(), Forms\Components\Select::make('type') ->options([ 'DOC_NORMAL' => 'Doc Normal', 'DOC_ECONOMY' => 'Doc Economy', 'PARCEL' => 'Parcel', ]) ->required() ->live(), Forms\Components\Select::make('status') ->options(collect(ShipmentStatus::cases())->mapWithKeys(fn ($case) => [ $case->value => $case->label(), ])) ->default('processed') ->required(), Forms\Components\TextInput::make('reason_for_export') ->nullable() ->label('Reason for Export'), Forms\Components\Select::make('from_country_id') ->relationship('fromCountry', 'name') ->searchable() ->preload() ->label('From Country'), Forms\Components\Select::make('to_country_id') ->relationship('toCountry', 'name') ->searchable() ->preload() ->label('To Country'), Forms\Components\TextInput::make('forwarder') ->nullable() ->label('Forwarder'), ])->columns(3), Forms\Components\Section::make('Weight & Dimensions') ->schema([ Forms\Components\TextInput::make('weight') ->numeric() ->nullable() ->suffix('kg') ->label('Weight'), Forms\Components\TextInput::make('volumetric_weight') ->numeric() ->nullable() ->suffix('kg') ->label('Volumetric Weight'), Forms\Components\TextInput::make('chargeable_weight') ->numeric() ->nullable() ->suffix('kg') ->label('Chargeable Weight'), Forms\Components\TextInput::make('dimensions') ->nullable() ->label('Dimensions (WxLxH)'), Forms\Components\TextInput::make('declared_value') ->numeric() ->nullable() ->prefix('USD') ->label('Declared Value'), Forms\Components\TextInput::make('content_description') ->nullable() ->label('Content Description'), Forms\Components\TextInput::make('reason_for_export') ->nullable() ->label('Reason for Export'), ])->columns(4), Forms\Components\Section::make('Financial Info') ->schema([ Forms\Components\TextInput::make('shipping_price') ->numeric() ->nullable() ->prefix('درهم') ->label('Shipping Price'), Forms\Components\TextInput::make('extra_service') ->numeric() ->default(0) ->prefix('درهم') ->label('Extra Service'), Forms\Components\TextInput::make('packing_cost') ->numeric() ->default(0) ->prefix('ریال') ->label('Packing Cost'), Forms\Components\TextInput::make('domestic_pickup') ->numeric() ->default(0) ->prefix('ریال') ->label('Domestic Pickup'), Forms\Components\TextInput::make('domestic_delivery') ->numeric() ->default(0) ->prefix('ریال') ->label('Domestic Delivery'), Forms\Components\TextInput::make('warehousing_cost') ->numeric() ->default(0) ->prefix('ریال') ->label('Warehousing Cost'), Forms\Components\TextInput::make('vat_amount') ->numeric() ->default(0) ->prefix('ریال') ->label('VAT Amount'), Forms\Components\TextInput::make('discount') ->numeric() ->default(0) ->prefix('ریال') ->label('Discount'), Forms\Components\TextInput::make('total_fee') ->numeric() ->nullable() ->prefix('ریال') ->label('Total Fee'), Forms\Components\TextInput::make('net_dirham') ->numeric() ->nullable() ->prefix('درهم') ->label('Net Dirham'), Forms\Components\TextInput::make('net_rial') ->numeric() ->nullable() ->prefix('ریال') ->label('Net Rial'), Forms\Components\TextInput::make('cod_amount') ->numeric() ->default(0) ->prefix('AED') ->label('Cash on Delivery'), ])->columns(4), Forms\Components\Section::make('Sender Info') ->schema([ Forms\Components\TextInput::make('sender_name') ->nullable() ->label('Name'), Forms\Components\TextInput::make('sender_company') ->nullable() ->label('Company'), Forms\Components\TextInput::make('sender_phone') ->tel() ->nullable() ->label('Phone'), Forms\Components\TextInput::make('sender_email') ->email() ->nullable() ->label('Email'), Forms\Components\TextInput::make('sender_address') ->nullable() ->label('Address'), Forms\Components\TextInput::make('sender_city') ->nullable() ->label('City'), Forms\Components\TextInput::make('sender_state') ->nullable() ->label('State/Province'), Forms\Components\TextInput::make('sender_zip') ->nullable() ->label('ZIP'), Forms\Components\TextInput::make('sender_id_number') ->nullable() ->label('ID Number'), ])->columns(4), Forms\Components\Section::make('Receiver Info') ->schema([ Forms\Components\TextInput::make('receiver_name') ->nullable() ->label('Name'), Forms\Components\TextInput::make('receiver_company') ->nullable() ->label('Company'), Forms\Components\TextInput::make('receiver_phone') ->tel() ->nullable() ->label('Phone'), Forms\Components\TextInput::make('receiver_email') ->email() ->nullable() ->label('Email'), Forms\Components\TextInput::make('receiver_address') ->nullable() ->label('Address'), Forms\Components\TextInput::make('receiver_city') ->nullable() ->label('City'), Forms\Components\TextInput::make('receiver_state') ->nullable() ->label('State/Province'), Forms\Components\TextInput::make('receiver_zip') ->nullable() ->label('ZIP'), Forms\Components\TextInput::make('receiver_id_number') ->nullable() ->label('ID Number'), ])->columns(4), Forms\Components\Section::make('Customs Items') ->schema([ Forms\Components\Repeater::make('items') ->relationship() ->schema([ Forms\Components\TextInput::make('row_number') ->required() ->numeric() ->minValue(1) ->maxValue(9) ->label('Row'), Forms\Components\TextInput::make('description') ->required() ->columnSpan(2) ->label('Description'), Forms\Components\TextInput::make('hs_code') ->required() ->label('HS Code'), Forms\Components\TextInput::make('quantity') ->required() ->numeric() ->label('Qty'), Forms\Components\TextInput::make('unit_price') ->required() ->numeric() ->prefix('USD') ->label('Unit Price'), Forms\Components\TextInput::make('total_usd') ->required() ->numeric() ->prefix('USD') ->label('Total'), ]) ->columns(6) ->maxItems(9) ->defaultItems(1) ->reorderable() ->label('Items'), ]), Forms\Components\Section::make('Customer Notes')->schema([ Forms\Components\Textarea::make('customer_notes')->nullable()->rows(3)->label('Customer Notes'), ]), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('awb_no') ->searchable() ->label('AWB No.') ->sortable(), Tables\Columns\TextColumn::make('direction') ->badge() ->color(fn (\App\Enums\ShipmentDirection $state): string => match ($state->value) { 'import' => 'success', 'export' => 'info', default => 'gray', }) ->label('Direction'), Tables\Columns\TextColumn::make('type') ->badge() ->label('Type'), Tables\Columns\TextColumn::make('status') ->badge() ->color(fn (ShipmentStatus $state): string => $state->color()) ->formatStateUsing(fn (ShipmentStatus $state): string => $state->label()) ->searchable() ->label('Status'), Tables\Columns\TextColumn::make('sender_name') ->searchable() ->toggleable() ->label('Sender'), Tables\Columns\TextColumn::make('receiver_name') ->searchable() ->toggleable() ->label('Receiver'), Tables\Columns\TextColumn::make('total_fee') ->money('IRR') ->sortable() ->label('Total Fee'), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ Tables\Filters\SelectFilter::make('status') ->options(collect(ShipmentStatus::cases())->mapWithKeys(fn ($case) => [ $case->value => $case->label(), ])), Tables\Filters\SelectFilter::make('type') ->options([ 'DOC_NORMAL' => 'Doc Normal', 'DOC_ECONOMY' => 'Doc Economy', 'PARCEL' => 'Parcel', ]), Tables\Filters\SelectFilter::make('direction') ->options([ 'export' => 'Export', 'import' => 'Import' ]), ]) ->actions([ Tables\Actions\ViewAction::make(), Tables\Actions\EditAction::make(), ]) ->headerActions([ Action::make('exportCsv') ->label('خروجی CSV') ->icon('heroicon-o-arrow-down-tray') ->color('success') ->action(function () { return response()->streamDownload(function () { $csv = fopen('php://output', 'w'); // BOM برای پشتیبانی از فارسی در Excel fwrite($csv, "\xEF\xBB\xBF"); // Header fputcsv($csv, [ 'AWB No', 'Direction', 'Type', 'Status', 'From Country', 'To Country', 'Weight (kg)', 'Chargeable Weight (kg)', 'Shipping Price (AED)', 'Extra Service (AED)', 'Packing Cost (IRR)', 'Total Fee (IRR)', 'Net Rial (IRR)', 'Sender Name', 'Sender Phone', 'Receiver Name', 'Receiver Phone', 'Created At' ]); // Data Shipment::query() ->with(['fromCountry', 'toCountry']) ->orderBy('created_at', 'desc') ->chunk(500, function ($shipments) use ($csv) { foreach ($shipments as $s) { fputcsv($csv, [ $s->awb_no, $s->direction?->value ?? '', $s->type?->value ?? '', $s->status?->value ?? '', $s->fromCountry?->name ?? '', $s->toCountry?->name ?? '', $s->weight, $s->chargeable_weight, $s->shipping_price, $s->extra_service, $s->packing_cost, $s->total_fee, $s->net_rial, $s->sender_name, $s->sender_phone, $s->receiver_name, $s->receiver_phone, $s->created_at?->format('Y-m-d H:i'), ]); } }); fclose($csv); }, 'shipments_' . now()->format('Y-m-d_H-i') . '.csv', [ 'Content-Type' => 'text/csv; charset=UTF-8', ]); }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ RelationManagers\CarrierMappingsRelationManager::class, RelationManagers\TrackingEventsRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListShipments::route('/'), 'create' => Pages\CreateShipment::route('/create'), 'view' => Pages\ViewShipment::route('/{record}'), 'edit' => Pages\EditShipment::route('/{record}/edit'), ]; } }