[FEAT] 銷售訂單管理:補齊欄位、即時搜尋、篩選與來源自動判定
This commit is contained in:
@@ -87,19 +87,7 @@ class SyncOrderAction
|
||||
|
||||
// --- 執行寫入交易 ---
|
||||
$result = DB::transaction(function () use ($data, $items, $resolvedProducts) {
|
||||
// 1. 建立訂單
|
||||
$order = SalesOrder::create([
|
||||
'external_order_id' => $data['external_order_id'],
|
||||
'status' => 'completed',
|
||||
'payment_method' => $data['payment_method'] ?? 'cash',
|
||||
'total_amount' => 0,
|
||||
'sold_at' => $data['sold_at'] ?? now(),
|
||||
'raw_payload' => $data,
|
||||
'source' => $data['source'] ?? 'pos',
|
||||
'source_label' => $data['source_label'] ?? null,
|
||||
]);
|
||||
|
||||
// 2. 查找倉庫
|
||||
// 1. 查找倉庫(提前至建立訂單前,以便判定來源)
|
||||
$warehouseCode = $data['warehouse_code'];
|
||||
$warehouses = $this->inventoryService->getWarehousesByCodes([$warehouseCode]);
|
||||
|
||||
@@ -108,7 +96,25 @@ class SyncOrderAction
|
||||
'warehouse_code' => ["Warehouse with code {$warehouseCode} not found."]
|
||||
]);
|
||||
}
|
||||
$warehouseId = $warehouses->first()->id;
|
||||
$warehouse = $warehouses->first();
|
||||
$warehouseId = $warehouse->id;
|
||||
|
||||
// 2. 自動判定來源:若是販賣機倉庫則標記為 vending,其餘為 pos
|
||||
$source = ($warehouse->type === \App\Enums\WarehouseType::VENDING) ? 'vending' : 'pos';
|
||||
|
||||
// 3. 建立訂單
|
||||
$order = SalesOrder::create([
|
||||
'external_order_id' => $data['external_order_id'],
|
||||
'name' => $data['name'],
|
||||
'status' => 'completed',
|
||||
'payment_method' => $data['payment_method'] ?? 'cash',
|
||||
'total_amount' => $data['total_amount'],
|
||||
'total_qty' => $data['total_qty'],
|
||||
'sold_at' => $data['sold_at'] ?? now(),
|
||||
'raw_payload' => $data,
|
||||
'source' => $source,
|
||||
'source_label' => $data['source_label'] ?? null,
|
||||
]);
|
||||
|
||||
$totalAmount = 0;
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ class SalesOrderController extends Controller
|
||||
|
||||
// 搜尋篩選 (外部訂單號)
|
||||
if ($request->filled('search')) {
|
||||
$query->where('external_order_id', 'like', '%' . $request->search . '%');
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('external_order_id', 'like', '%' . $request->search . '%')
|
||||
->orWhere('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
}
|
||||
|
||||
// 來源篩選
|
||||
@@ -26,6 +29,11 @@ class SalesOrderController extends Controller
|
||||
$query->where('source', $request->source);
|
||||
}
|
||||
|
||||
// 付款方式篩選
|
||||
if ($request->filled('payment_method')) {
|
||||
$query->where('payment_method', $request->payment_method);
|
||||
}
|
||||
|
||||
// 排序
|
||||
$query->orderBy('sold_at', 'desc');
|
||||
|
||||
@@ -40,7 +48,7 @@ class SalesOrderController extends Controller
|
||||
|
||||
return Inertia::render('Integration/SalesOrders/Index', [
|
||||
'orders' => $orders,
|
||||
'filters' => $request->only(['search', 'per_page', 'source']),
|
||||
'filters' => $request->only(['search', 'per_page', 'source', 'status', 'payment_method']),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@ class SalesOrder extends Model
|
||||
|
||||
protected $fillable = [
|
||||
'external_order_id',
|
||||
'name',
|
||||
'status',
|
||||
'payment_method',
|
||||
'total_amount',
|
||||
'total_qty',
|
||||
'sold_at',
|
||||
'raw_payload',
|
||||
'source',
|
||||
@@ -24,6 +26,7 @@ class SalesOrder extends Model
|
||||
'sold_at' => 'datetime',
|
||||
'raw_payload' => 'array',
|
||||
'total_amount' => 'decimal:4',
|
||||
'total_qty' => 'decimal:4',
|
||||
];
|
||||
|
||||
public function items(): HasMany
|
||||
|
||||
@@ -23,8 +23,11 @@ class SyncOrderRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'external_order_id' => 'required|string',
|
||||
'name' => 'required|string|max:255',
|
||||
'warehouse_code' => 'required|string',
|
||||
'payment_method' => 'nullable|string|in:cash,credit_card,line_pay,ecpay,transfer,other',
|
||||
'total_amount' => 'required|numeric|min:0',
|
||||
'total_qty' => 'required|numeric|min:0',
|
||||
'sold_at' => 'nullable|date',
|
||||
'items' => 'required|array|min:1',
|
||||
'items.*.product_id' => 'required|integer',
|
||||
|
||||
@@ -190,10 +190,10 @@ class ProductService implements ProductServiceInterface
|
||||
{
|
||||
$product = null;
|
||||
if (!empty($barcode)) {
|
||||
$product = Product::query()->where('barcode', $barcode)->first();
|
||||
$product = Product::where('barcode', $barcode)->first();
|
||||
}
|
||||
if (!$product && !empty($code)) {
|
||||
$product = Product::query()->where('code', $code)->first();
|
||||
$product = Product::where('code', $code)->first();
|
||||
}
|
||||
return $product;
|
||||
}
|
||||
@@ -207,7 +207,6 @@ class ProductService implements ProductServiceInterface
|
||||
*/
|
||||
public function searchProducts(array $filters, int $perPage = 50)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Product::query()
|
||||
->with(['category', 'baseUnit'])
|
||||
->where('is_active', true);
|
||||
@@ -226,12 +225,16 @@ class ProductService implements ProductServiceInterface
|
||||
$query->where('external_pos_id', $filters['external_pos_id']);
|
||||
}
|
||||
|
||||
// 3. 分類過濾
|
||||
// 3. 分類過濾 (優先使用 ID,若傳入字串則按名稱)
|
||||
if (!empty($filters['category'])) {
|
||||
$categoryName = $filters['category'];
|
||||
$query->whereHas('category', function ($q) use ($categoryName) {
|
||||
$q->where('name', $categoryName);
|
||||
});
|
||||
$categoryVal = $filters['category'];
|
||||
if (is_numeric($categoryVal)) {
|
||||
$query->where('category_id', $categoryVal);
|
||||
} else {
|
||||
$query->whereHas('category', function ($q) use ($categoryVal) {
|
||||
$q->where('name', $categoryVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 增量同步 (Updated After)
|
||||
|
||||
Reference in New Issue
Block a user