From 157ce1bdd40fd47e11ca04ef6f6f1460d86ba336 Mon Sep 17 00:00:00 2001 From: Kazem Alghasi Date: Mon, 24 Aug 2026 01:47:45 +0330 Subject: [PATCH] feat(shipment): add multi-package support and AWB integration Introduce a new shipment packages system to allow handling shipments consisting of multiple individual packages. This includes a new ShipmentPackage model, a dedicated database table, and a repeater field in the Filament ShipmentResource for managing package details such as weight, dimensions, and declared value. Additionally, update the AWB PDF generation service and template to include a detailed breakdown of all associated packages when multiple items are present. --- .../Filament/Resources/ShipmentResource.php | 48 ++++++++++++++++++- 04_Laravel/app/Models/Shipment.php | 5 ++ 04_Laravel/app/Models/ShipmentPackage.php | 29 +++++++++++ 04_Laravel/app/Services/PdfService.php | 2 +- ..._200001_create_shipment_packages_table.php | 31 ++++++++++++ 04_Laravel/resources/views/pdfs/awb.blade.php | 34 +++++++++++++ 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 04_Laravel/app/Models/ShipmentPackage.php create mode 100644 04_Laravel/database/migrations/2026_08_24_200001_create_shipment_packages_table.php diff --git a/04_Laravel/app/Filament/Resources/ShipmentResource.php b/04_Laravel/app/Filament/Resources/ShipmentResource.php index a23fff4..e12109d 100644 --- a/04_Laravel/app/Filament/Resources/ShipmentResource.php +++ b/04_Laravel/app/Filament/Resources/ShipmentResource.php @@ -102,6 +102,52 @@ class ShipmentResource extends Resource ->label('Content Description'), ])->columns(4), + + Forms\Components\Section::make('Packages') + ->description('برای محموله‌های چند بسته‌ای، اطلاعات هر بسته را وارد کنید.') + ->schema([ + Forms\Components\Repeater::make('packages') + ->relationship() + ->schema([ + Forms\Components\TextInput::make('package_no') + ->required() + ->numeric() + ->minValue(1) + ->maxValue(99) + ->label('#'), + Forms\Components\TextInput::make('weight') + ->numeric() + ->nullable() + ->suffix('kg') + ->label('Weight'), + Forms\Components\TextInput::make('volumetric_weight') + ->numeric() + ->nullable() + ->suffix('kg') + ->label('Volumetric Wt'), + Forms\Components\TextInput::make('chargeable_weight') + ->numeric() + ->nullable() + ->suffix('kg') + ->label('Chargeable Wt'), + Forms\Components\TextInput::make('dimensions') + ->nullable() + ->label('WxLxH (cm)'), + Forms\Components\TextInput::make('declared_value') + ->numeric() + ->nullable() + ->prefix('USD') + ->label('Value'), + Forms\Components\TextInput::make('content_description') + ->nullable() + ->label('Content'), + ]) + ->columns(4) + ->defaultItems(1) + ->reorderable() + ->label('بسته‌ها'), + ])->collapsible(), + Forms\Components\Section::make('Financial Info') ->schema([ Forms\Components\TextInput::make('shipping_price') @@ -442,7 +488,7 @@ class ShipmentResource extends Resource ShipmentUpdatedNotification::notify($record); } } - + public static function getRelations(): array { return [ diff --git a/04_Laravel/app/Models/Shipment.php b/04_Laravel/app/Models/Shipment.php index ee5fd09..44c6a81 100644 --- a/04_Laravel/app/Models/Shipment.php +++ b/04_Laravel/app/Models/Shipment.php @@ -90,4 +90,9 @@ class Shipment extends Model { return $this->items->sum('total_usd'); } + + public function packages(): HasMany + { + return $this->hasMany(ShipmentPackage::class)->orderBy('package_no'); + } } diff --git a/04_Laravel/app/Models/ShipmentPackage.php b/04_Laravel/app/Models/ShipmentPackage.php new file mode 100644 index 0000000..fb8ef68 --- /dev/null +++ b/04_Laravel/app/Models/ShipmentPackage.php @@ -0,0 +1,29 @@ + 'decimal:2', + 'volumetric_weight' => 'decimal:2', + 'chargeable_weight' => 'decimal:2', + 'declared_value' => 'decimal:2', + ]; + } + + public function shipment(): BelongsTo + { + return $this->belongsTo(Shipment::class); + } +} \ No newline at end of file diff --git a/04_Laravel/app/Services/PdfService.php b/04_Laravel/app/Services/PdfService.php index 533f680..3b6d57c 100644 --- a/04_Laravel/app/Services/PdfService.php +++ b/04_Laravel/app/Services/PdfService.php @@ -12,7 +12,7 @@ class PdfService { public function awb(Shipment $shipment): string { - $shipment->loadMissing(['fromCountry', 'toCountry', 'items']); + $shipment->loadMissing(['fromCountry', 'toCountry', 'items', 'packages']); $data = [ 'shipment' => $shipment, diff --git a/04_Laravel/database/migrations/2026_08_24_200001_create_shipment_packages_table.php b/04_Laravel/database/migrations/2026_08_24_200001_create_shipment_packages_table.php new file mode 100644 index 0000000..585d678 --- /dev/null +++ b/04_Laravel/database/migrations/2026_08_24_200001_create_shipment_packages_table.php @@ -0,0 +1,31 @@ +id(); + $table->foreignId('shipment_id')->constrained()->cascadeOnDelete(); + $table->unsignedSmallInteger('package_no')->default(1); + $table->decimal('weight', 10, 2)->nullable(); + $table->decimal('volumetric_weight', 10, 2)->nullable(); + $table->decimal('chargeable_weight', 10, 2)->nullable(); + $table->string('dimensions', 50)->nullable(); + $table->decimal('declared_value', 12, 2)->nullable()->unsigned(); + $table->string('content_description')->nullable(); + $table->timestamps(); + + $table->unique(['shipment_id', 'package_no']); + }); + } + + public function down(): void + { + Schema::dropIfExists('shipment_packages'); + } +}; \ No newline at end of file diff --git a/04_Laravel/resources/views/pdfs/awb.blade.php b/04_Laravel/resources/views/pdfs/awb.blade.php index 5e9f256..01fb78a 100644 --- a/04_Laravel/resources/views/pdfs/awb.blade.php +++ b/04_Laravel/resources/views/pdfs/awb.blade.php @@ -148,6 +148,40 @@ Please note that: Door-to-door Services is only applicable when the shipment is general cargo. For special cargo, dangerous goods, or items requiring special handling, additional charges may apply. The receiver is responsible for customs clearance and any associated fees. Claims must be filed within 30 days of delivery. Shipper declares that the contents are accurately described and properly packed for transport. + + + @if($shipment->relationLoaded('packages') && $shipment->packages->count() > 1) +
+
PACKAGES ({{ $shipment->packages->count() }})
+ + + + + + + + + + + + + + @foreach($shipment->packages as $pkg) + + + + + + + + + + @endforeach + +
#Weight (kg)Vol. Wt (kg)Chg. Wt (kg)DimensionsValue (USD)Content
{{ $pkg->package_no }}{{ number_format($pkg->weight, 2) }}{{ number_format($pkg->volumetric_weight, 2) }}{{ number_format($pkg->chargeable_weight, 2) }}{{ $pkg->dimensions }}{{ number_format($pkg->declared_value, 2) }}{{ $pkg->content_description }}
+
+ @endif +
Shipper Name & Signature