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.
This commit is contained in:
parent
e9a0c731c2
commit
157ce1bdd4
@ -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 [
|
||||
|
||||
@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
29
04_Laravel/app/Models/ShipmentPackage.php
Normal file
29
04_Laravel/app/Models/ShipmentPackage.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ShipmentPackage extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'shipment_id', 'package_no', 'weight', 'volumetric_weight',
|
||||
'chargeable_weight', 'dimensions', 'declared_value', 'content_description',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'weight' => 'decimal:2',
|
||||
'volumetric_weight' => 'decimal:2',
|
||||
'chargeable_weight' => 'decimal:2',
|
||||
'declared_value' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
public function shipment(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Shipment::class);
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
<?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('shipment_packages', function (Blueprint $table) {
|
||||
$table->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');
|
||||
}
|
||||
};
|
||||
@ -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.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@if($shipment->relationLoaded('packages') && $shipment->packages->count() > 1)
|
||||
<div class="section">
|
||||
<div class="section-title">PACKAGES ({{ $shipment->packages->count() }})</div>
|
||||
<table style="width:100%; font-size:10px; border-collapse:collapse; margin-top:6px;">
|
||||
<thead>
|
||||
<tr style="background-color:#f37021; color:#fff;">
|
||||
<th style="border:1px solid #ddd; padding:3px;">#</th>
|
||||
<th style="border:1px solid #ddd; padding:3px;">Weight (kg)</th>
|
||||
<th style="border:1px solid #ddd; padding:3px;">Vol. Wt (kg)</th>
|
||||
<th style="border:1px solid #ddd; padding:3px;">Chg. Wt (kg)</th>
|
||||
<th style="border:1px solid #ddd; padding:3px;">Dimensions</th>
|
||||
<th style="border:1px solid #ddd; padding:3px;">Value (USD)</th>
|
||||
<th style="border:1px solid #ddd; padding:3px;">Content</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($shipment->packages as $pkg)
|
||||
<tr>
|
||||
<td style="border:1px solid #ddd; padding:3px; text-align:center;">{{ $pkg->package_no }}</td>
|
||||
<td style="border:1px solid #ddd; padding:3px;">{{ number_format($pkg->weight, 2) }}</td>
|
||||
<td style="border:1px solid #ddd; padding:3px;">{{ number_format($pkg->volumetric_weight, 2) }}</td>
|
||||
<td style="border:1px solid #ddd; padding:3px;">{{ number_format($pkg->chargeable_weight, 2) }}</td>
|
||||
<td style="border:1px solid #ddd; padding:3px;">{{ $pkg->dimensions }}</td>
|
||||
<td style="border:1px solid #ddd; padding:3px;">{{ number_format($pkg->declared_value, 2) }}</td>
|
||||
<td style="border:1px solid #ddd; padding:3px;">{{ $pkg->content_description }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="signature">
|
||||
<div class="signature-box">
|
||||
Shipper Name & Signature<br>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user