*/ use HasFactory; use \Illuminate\Database\Eloquent\SoftDeletes; use \Spatie\Activitylog\Traits\LogsActivity; protected $fillable = [ 'warehouse_id', 'product_id', 'quantity', 'location', 'unit_cost', 'total_value', // 批號追溯欄位 'batch_number', 'box_number', 'origin_country', 'arrival_date', 'expiry_date', 'source_purchase_order_id', 'quality_status', 'quality_remark', ]; protected $casts = [ 'arrival_date' => 'date:Y-m-d', 'expiry_date' => 'date:Y-m-d', 'unit_cost' => 'decimal:4', 'total_value' => 'decimal:4', ]; /** * 用於活動記錄的暫時屬性(例如 "補貨 #123")。 * 此屬性不存儲在資料庫欄位中,但用於記錄上下文。 * @var string|null */ public $activityLogReason; public function getActivitylogOptions(): \Spatie\Activitylog\LogOptions { return \Spatie\Activitylog\LogOptions::defaults() ->logAll() ->logOnlyDirty() ->dontSubmitEmptyLogs(); } public function tapActivity(\Spatie\Activitylog\Contracts\Activity $activity, string $eventName) { $properties = $activity->properties; $attributes = $properties['attributes'] ?? []; $snapshot = $properties['snapshot'] ?? []; // 始終對名稱進行快照以便於上下文顯示,即使 ID 未更改 // $this 指的是 Inventory 模型實例 $snapshot['warehouse_name'] = $this->warehouse ? $this->warehouse->name : ($snapshot['warehouse_name'] ?? null); $snapshot['product_name'] = $this->product ? $this->product->name : ($snapshot['product_name'] ?? null); // 如果已設定原因,則進行捕捉 if ($this->activityLogReason) { $attributes['_reason'] = $this->activityLogReason; } $properties['attributes'] = $attributes; $properties['snapshot'] = $snapshot; $activity->properties = $properties; } public function warehouse(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Warehouse::class); } public function product(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Product::class); } public function transactions(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(InventoryTransaction::class); } public function lastOutgoingTransaction() { return $this->hasOne(InventoryTransaction::class)->ofMany([ 'actual_time' => 'max', 'id' => 'max', ], function ($query) { $query->where('quantity', '<', 0); }); } public function lastIncomingTransaction() { return $this->hasOne(InventoryTransaction::class)->ofMany([ 'actual_time' => 'max', 'id' => 'max', ], function ($query) { $query->where('quantity', '>', 0); }); } /** * 產生批號 * 格式:{商品代號}-{來源國家}-{入庫日期}-{批次流水號} */ public static function generateBatchNumber(string $productCode, string $originCountry, string $arrivalDate): string { $dateFormatted = date('Ymd', strtotime($arrivalDate)); $prefix = "{$productCode}-{$originCountry}-{$dateFormatted}-"; // 加入 withTrashed() 確保流水號不會撞到已刪除的紀錄 $lastBatch = static::withTrashed() ->where('batch_number', 'like', "{$prefix}%") ->orderByDesc('batch_number') ->first(); if ($lastBatch) { $lastNumber = (int) substr($lastBatch->batch_number, -2); $nextNumber = str_pad($lastNumber + 1, 2, '0', STR_PAD_LEFT); } else { $nextNumber = '01'; } return $prefix . $nextNumber; } }