mivita/dev/app-bak/Models/DhlShipment.php
2025-10-20 17:42:08 +02:00

407 lines
No EOL
15 KiB
PHP

<?php
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\HasOne;
use Illuminate\Support\Carbon;
/**
* DHL Shipment Model
*
* Represents a DHL shipment for a shopping order, including both outbound and return shipments.
*
* @property int $id
* @property int $shopping_order_id
* @property string|null $shipment_number DHL shipment number
* @property string|null $tracking_number DHL tracking number
* @property string $type Type: 'outbound' or 'return'
* @property int|null $related_shipment_id For returns: reference to original shipment
* @property float $weight Package weight in kg
* @property int|null $length Package length in cm
* @property int|null $width Package width in cm
* @property int|null $height Package height in cm
* @property string $product_code DHL product code (e.g., V01PAK)
* @property array|null $services Additional DHL services
* @property string|null $label_path Path to generated label file
* @property string $label_format Label format (PDF or ZPL)
* @property bool $label_printed Whether label has been printed
* @property string $status Shipment status
* @property string|null $tracking_status Current tracking status from DHL
* @property string|null $tracking_details Detailed tracking information (JSON)
* @property Carbon|null $last_tracked_at Last tracking update
* @property string $recipient_name Recipient name
* @property string|null $recipient_company Recipient company
* @property string $recipient_street Recipient street
* @property string $recipient_street_number Recipient street number
* @property string $recipient_postal_code Recipient postal code
* @property string $recipient_city Recipient city
* @property string|null $recipient_state Recipient state
* @property string $recipient_country Recipient country code
* @property string|null $recipient_email Recipient email
* @property string|null $recipient_phone Recipient phone
* @property array|null $api_request_data API request data for debugging
* @property array|null $api_response_data API response data for debugging
* @property string|null $api_errors API error messages
* @property float|null $shipping_cost Shipping cost
* @property string $currency Currency code
* @property string|null $notes Internal notes
* @property array|null $metadata Additional metadata
* @property Carbon|null $shipped_at When the package was shipped
* @property Carbon|null $delivered_at When the package was delivered
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property-read ShoppingOrder $shoppingOrder
* @property-read DhlShipment|null $relatedShipment
* @property-read DhlShipment|null $returnShipment
* @property-read string|null $dimensions
* @property-read string|null $label_url
* @property-read string $recipient_address
* @property-read string $status_label
* @property-read string $type_label
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment active()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment outbound()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment returns()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment trackable()
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereApiErrors($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereApiRequestData($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereApiResponseData($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereCurrency($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereDeliveredAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereHeight($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereLabelFormat($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereLabelPath($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereLabelPrinted($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereLastTrackedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereLength($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereMetadata($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereNotes($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereProductCode($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientCity($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientCompany($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientCountry($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientEmail($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientPhone($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientPostalCode($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientState($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientStreet($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRecipientStreetNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereRelatedShipmentId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereServices($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereShipmentNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereShippedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereShippingCost($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereShoppingOrderId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereStatus($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereTrackingDetails($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereTrackingNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereTrackingStatus($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereType($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereWeight($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|DhlShipment whereWidth($value)
* @mixin \Eloquent
*/
class DhlShipment extends Model
{
use HasFactory;
/**
* The table associated with the model.
*/
protected $table = 'dhl_shipments';
/**
* The attributes that are mass assignable.
*/
protected $fillable = [
'shopping_order_id',
'shipment_number',
'tracking_number',
'type',
'related_shipment_id',
'weight',
'length',
'width',
'height',
'product_code',
'services',
'label_path',
'label_format',
'label_printed',
'status',
'tracking_status',
'tracking_details',
'last_tracked_at',
'recipient_name',
'recipient_company',
'recipient_street',
'recipient_street_number',
'recipient_postal_code',
'recipient_city',
'recipient_state',
'recipient_country',
'recipient_email',
'recipient_phone',
'api_request_data',
'api_response_data',
'api_errors',
'shipping_cost',
'currency',
'notes',
'metadata',
'shipped_at',
'delivered_at',
];
/**
* The attributes that should be cast.
*/
protected $casts = [
'weight' => 'float',
'length' => 'integer',
'width' => 'integer',
'height' => 'integer',
'services' => 'array',
'label_printed' => 'boolean',
'tracking_details' => 'array',
'last_tracked_at' => 'datetime',
'api_request_data' => 'array',
'api_response_data' => 'array',
'shipping_cost' => 'decimal:2',
'metadata' => 'array',
'shipped_at' => 'datetime',
'delivered_at' => 'datetime',
];
/**
* Shipment types
*/
public const TYPE_OUTBOUND = 'outbound';
public const TYPE_RETURN = 'return';
/**
* Shipment statuses
*/
public const STATUS_CREATED = 'created';
public const STATUS_SUBMITTED = 'submitted';
public const STATUS_IN_TRANSIT = 'in_transit';
public const STATUS_DELIVERED = 'delivered';
public const STATUS_RETURNED = 'returned';
public const STATUS_CANCELLED = 'cancelled';
public const STATUS_FAILED = 'failed';
/**
* Get the shopping order that owns the shipment
*/
public function shoppingOrder(): BelongsTo
{
return $this->belongsTo(ShoppingOrder::class, 'shopping_order_id');
}
/**
* Get the related shipment (for returns)
*/
public function relatedShipment(): BelongsTo
{
return $this->belongsTo(DhlShipment::class, 'related_shipment_id');
}
/**
* Get the return shipment (for outbound shipments)
*/
public function returnShipment(): HasOne
{
return $this->hasOne(DhlShipment::class, 'related_shipment_id');
}
/**
* Scope for outbound shipments
*/
public function scopeOutbound($query)
{
return $query->where('type', self::TYPE_OUTBOUND);
}
/**
* Scope for return shipments
*/
public function scopeReturns($query)
{
return $query->where('type', self::TYPE_RETURN);
}
/**
* Scope for active shipments (not cancelled or failed)
*/
public function scopeActive($query)
{
return $query->whereNotIn('status', [self::STATUS_CANCELLED, self::STATUS_FAILED]);
}
/**
* Scope for trackable shipments (have tracking number)
*/
public function scopeTrackable($query)
{
return $query->whereNotNull('tracking_number');
}
/**
* Check if shipment is outbound
*/
public function isOutbound(): bool
{
return $this->type === self::TYPE_OUTBOUND;
}
/**
* Check if shipment is return
*/
public function isReturn(): bool
{
return $this->type === self::TYPE_RETURN;
}
/**
* Check if shipment can be cancelled
*/
public function canBeCancelled(): bool
{
return in_array($this->status, [
self::STATUS_CREATED,
self::STATUS_SUBMITTED,
]);
}
/**
* Check if shipment is delivered
*/
public function isDelivered(): bool
{
return $this->status === self::STATUS_DELIVERED;
}
/**
* Check if shipment has tracking information
*/
public function hasTracking(): bool
{
return !empty($this->tracking_number);
}
/**
* Check if label is available
*/
public function hasLabel(): bool
{
return !empty($this->label_path) && file_exists(storage_path('app/' . $this->label_path));
}
/**
* Get full recipient address as formatted string
*/
public function getRecipientAddressAttribute(): string
{
$address = $this->recipient_name;
if ($this->recipient_company) {
$address .= "\n" . $this->recipient_company;
}
$address .= "\n" . $this->recipient_street . ' ' . $this->recipient_street_number;
$address .= "\n" . $this->recipient_postal_code . ' ' . $this->recipient_city;
if ($this->recipient_state) {
$address .= "\n" . $this->recipient_state;
}
$address .= "\n" . $this->recipient_country;
return $address;
}
/**
* Get package dimensions as formatted string
*/
public function getDimensionsAttribute(): ?string
{
if (!$this->length || !$this->width || !$this->height) {
return null;
}
return $this->length . ' x ' . $this->width . ' x ' . $this->height . ' cm';
}
/**
* Get human-readable status
*/
public function getStatusLabelAttribute(): string
{
return match($this->status) {
self::STATUS_CREATED => 'Erstellt',
self::STATUS_SUBMITTED => 'Übertragen',
self::STATUS_IN_TRANSIT => 'Unterwegs',
self::STATUS_DELIVERED => 'Zugestellt',
self::STATUS_RETURNED => 'Zurückgeschickt',
self::STATUS_CANCELLED => 'Storniert',
self::STATUS_FAILED => 'Fehler',
default => 'Unbekannt',
};
}
/**
* Get human-readable type
*/
public function getTypeLabelAttribute(): string
{
return match($this->type) {
self::TYPE_OUTBOUND => 'Versand',
self::TYPE_RETURN => 'Retoure',
default => 'Unbekannt',
};
}
/**
* Get label file URL for download
*/
public function getLabelUrlAttribute(): ?string
{
if (!$this->hasLabel()) {
return null;
}
return route('admin.dhl.shipments.label', $this->id);
}
/**
* Boot the model
*/
protected static function boot()
{
parent::boot();
static::creating(function ($shipment) {
// Set default values
if (empty($shipment->currency)) {
$shipment->currency = config('dhl.defaults.currency', 'EUR');
}
if (empty($shipment->product_code)) {
$shipment->product_code = config('dhl.defaults.product', 'V01PAK');
}
if (empty($shipment->label_format)) {
$shipment->label_format = config('dhl.labels.format', 'PDF');
}
});
}
}