Files
star-erp/app/Modules/Sales/Controllers/SalesImportController.php

153 lines
5.6 KiB
PHP
Raw Normal View History

<?php
namespace App\Modules\Sales\Controllers;
use App\Http\Controllers\Controller;
use App\Modules\Sales\Models\SalesImportBatch;
use App\Modules\Sales\Imports\SalesImport;
use App\Modules\Inventory\Services\InventoryService; // Assuming this exists or we need to use ProductService
use Illuminate\Http\Request;
use Inertia\Inertia;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\DB;
class SalesImportController extends Controller
{
public function index(Request $request)
{
$perPage = $request->input('per_page', 10);
$batches = SalesImportBatch::with('importer')
->orderByDesc('created_at')
->paginate($perPage)
->withQueryString();
return Inertia::render('Sales/Import/Index', [
'batches' => $batches,
'filters' => [
'per_page' => $perPage,
],
]);
}
public function template()
{
return Excel::download(new \App\Modules\Sales\Exports\SalesImportTemplateExport, 'sales_import_template.xlsx');
}
public function store(Request $request)
{
$request->validate([
'file' => 'required|file|mimes:xlsx,xls,csv,zip',
]);
DB::transaction(function () use ($request) {
$batch = SalesImportBatch::create([
'import_date' => now(),
'imported_by' => auth()->id(),
'status' => 'pending',
'tenant_id' => tenant('id'), // If tenant context requires it, but usually automatic
]);
Excel::import(new SalesImport($batch), $request->file('file'));
});
return redirect()->route('sales-imports.index')->with('success', '匯入成功,請確認內容。');
}
public function show(Request $request, SalesImportBatch $import)
{
$import->load(['items', 'importer']);
$perPage = $request->input('per_page', 10);
return Inertia::render('Sales/Import/Show', [
'import' => $import,
'items' => $import->items()->with(['product', 'warehouse'])->paginate($perPage)->withQueryString(),
'filters' => [
'per_page' => $perPage,
],
]);
}
public function confirm(SalesImportBatch $import, InventoryService $inventoryService)
{
if ($import->status !== 'pending') {
return back()->with('error', '此批次無法確認。');
}
DB::transaction(function () use ($import, $inventoryService) {
// 1. Prepare Aggregation
$aggregatedDeductions = []; // Key: "warehouse_id:product_id:slot"
// Pre-load necessary warehouses for matching
$machineIds = $import->items->pluck('machine_id')->filter()->unique();
$warehouses = \App\Modules\Inventory\Models\Warehouse::whereIn('code', $machineIds)->get()->keyBy('code');
foreach ($import->items as $item) {
// Only process shipped items with a valid product
if ($item->product_id && $item->original_status === '已出貨') {
// Resolve Warehouse from Machine ID
$warehouse = $warehouses->get($item->machine_id);
// Skip if machine_id is empty or warehouse not found
if (!$warehouse) {
continue;
}
// Aggregation Key includes Slot (貨道)
$slot = $item->slot ?: '';
$key = "{$warehouse->id}:{$item->product_id}:{$slot}";
if (!isset($aggregatedDeductions[$key])) {
$aggregatedDeductions[$key] = [
'warehouse_id' => $warehouse->id,
'product_id' => $item->product_id,
'slot' => $slot,
'quantity' => 0,
'details' => []
];
}
$aggregatedDeductions[$key]['quantity'] += $item->quantity;
$aggregatedDeductions[$key]['details'][] = $item->transaction_serial;
}
}
// 2. Execute Aggregated Deductions
foreach ($aggregatedDeductions as $deduction) {
// Construct a descriptive reason
$serialCount = count($deduction['details']);
$reason = "銷售出貨彙總 (批號: {$import->id}, 貨道: {$deduction['slot']}, 共 {$serialCount} 筆交易)";
$inventoryService->decreaseStock(
$deduction['product_id'],
$deduction['warehouse_id'],
$deduction['quantity'],
$reason,
true, // Force deduction
$deduction['slot'] // Location/Slot
);
}
// 3. Update Batch Status
$import->update([
'status' => 'confirmed',
'confirmed_at' => now(),
]);
});
return redirect()->route('sales-imports.index')->with('success', '已彙總(含貨道)並扣除庫存。');
}
public function destroy(SalesImportBatch $import)
{
if ($import->status !== 'pending') {
return back()->with('error', '只能刪除待確認的批次。');
}
$import->delete();
return redirect()->route('sales-imports.index')->with('success', '已刪除匯入批次。');
}
}