2025-12-30 15:03:19 +08:00
|
|
|
<?php
|
|
|
|
|
|
2026-01-26 10:37:47 +08:00
|
|
|
namespace App\Modules\Procurement\Controllers;
|
|
|
|
|
|
|
|
|
|
use App\Http\Controllers\Controller;
|
|
|
|
|
use App\Modules\Procurement\Models\Vendor;
|
2026-01-26 14:59:24 +08:00
|
|
|
use App\Modules\Inventory\Contracts\InventoryServiceInterface;
|
2025-12-30 15:03:19 +08:00
|
|
|
use Illuminate\Http\Request;
|
2026-01-26 14:59:24 +08:00
|
|
|
use Inertia\Inertia;
|
|
|
|
|
use Inertia\Response;
|
2025-12-30 15:03:19 +08:00
|
|
|
|
|
|
|
|
class VendorController extends Controller
|
|
|
|
|
{
|
2026-01-26 14:59:24 +08:00
|
|
|
public function __construct(
|
|
|
|
|
protected InventoryServiceInterface $inventoryService
|
|
|
|
|
) {}
|
|
|
|
|
|
2025-12-30 15:03:19 +08:00
|
|
|
/**
|
2026-01-26 14:59:24 +08:00
|
|
|
* 顯示資源列表。
|
2025-12-30 15:03:19 +08:00
|
|
|
*/
|
2026-01-26 14:59:24 +08:00
|
|
|
public function index(Request $request): Response
|
2025-12-30 15:03:19 +08:00
|
|
|
{
|
|
|
|
|
$query = Vendor::query();
|
|
|
|
|
|
|
|
|
|
if ($request->filled('search')) {
|
|
|
|
|
$search = $request->search;
|
|
|
|
|
$query->where(function ($q) use ($search) {
|
|
|
|
|
$q->where('name', 'like', "%{$search}%")
|
|
|
|
|
->orWhere('code', 'like', "%{$search}%")
|
|
|
|
|
->orWhere('tax_id', 'like', "%{$search}%")
|
|
|
|
|
->orWhere('owner', 'like', "%{$search}%")
|
|
|
|
|
->orWhere('contact_name', 'like', "%{$search}%");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$sortField = $request->input('sort_field', 'id');
|
|
|
|
|
$sortDirection = $request->input('sort_direction', 'desc');
|
|
|
|
|
|
|
|
|
|
$allowedSorts = ['id', 'code', 'name', 'owner', 'contact_name', 'phone'];
|
|
|
|
|
if (!in_array($sortField, $allowedSorts)) {
|
|
|
|
|
$sortField = 'id';
|
|
|
|
|
}
|
|
|
|
|
if (!in_array(strtolower($sortDirection), ['asc', 'desc'])) {
|
|
|
|
|
$sortDirection = 'desc';
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 17:09:52 +08:00
|
|
|
$perPage = $request->input('per_page', 10);
|
|
|
|
|
|
2025-12-30 15:03:19 +08:00
|
|
|
$vendors = $query->orderBy($sortField, $sortDirection)
|
2026-01-13 17:09:52 +08:00
|
|
|
->paginate($perPage)
|
2025-12-30 15:03:19 +08:00
|
|
|
->withQueryString();
|
|
|
|
|
|
2026-01-26 14:59:24 +08:00
|
|
|
$vendors->getCollection()->transform(function ($vendor) {
|
|
|
|
|
return (object) [
|
|
|
|
|
'id' => (string) $vendor->id,
|
|
|
|
|
'code' => $vendor->code,
|
|
|
|
|
'name' => $vendor->name,
|
|
|
|
|
'shortName' => $vendor->short_name,
|
|
|
|
|
'taxId' => $vendor->tax_id,
|
|
|
|
|
'owner' => $vendor->owner,
|
|
|
|
|
'contactName' => $vendor->contact_name,
|
|
|
|
|
'phone' => $vendor->phone,
|
|
|
|
|
'tel' => $vendor->tel,
|
|
|
|
|
'email' => $vendor->email,
|
|
|
|
|
'address' => $vendor->address,
|
|
|
|
|
'remark' => $vendor->remark,
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Inertia::render('Vendor/Index', [
|
2025-12-30 15:03:19 +08:00
|
|
|
'vendors' => $vendors,
|
2026-01-13 17:09:52 +08:00
|
|
|
'filters' => $request->only(['search', 'sort_field', 'sort_direction', 'per_page']),
|
2025-12-30 15:03:19 +08:00
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-26 14:59:24 +08:00
|
|
|
* 顯示指定資源。
|
2025-12-30 15:03:19 +08:00
|
|
|
*/
|
2026-01-26 14:59:24 +08:00
|
|
|
public function show(Vendor $vendor): Response
|
2025-12-30 15:03:19 +08:00
|
|
|
{
|
2026-01-27 08:59:45 +08:00
|
|
|
// $vendor->load(['products.baseUnit', 'products.largeUnit']); // REMOVED: Cross-module relation
|
2026-01-26 14:59:24 +08:00
|
|
|
|
2026-01-27 08:59:45 +08:00
|
|
|
// 1. 獲取關聯的 Product IDs 與 Pivot Data
|
|
|
|
|
$pivots = \Illuminate\Support\Facades\DB::table('product_vendor')
|
|
|
|
|
->where('vendor_id', $vendor->id)
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
$productIds = $pivots->pluck('product_id')->toArray();
|
|
|
|
|
|
|
|
|
|
// 2. 透過 Service 獲取 Products
|
|
|
|
|
$products = $this->inventoryService->getProductsByIds($productIds)->keyBy('id');
|
|
|
|
|
|
|
|
|
|
$supplyProducts = $pivots->map(function ($pivot) use ($products) {
|
|
|
|
|
$product = $products->get($pivot->product_id);
|
|
|
|
|
if (!$product) return null;
|
|
|
|
|
|
|
|
|
|
return (object) [
|
|
|
|
|
'id' => (string) $pivot->id,
|
|
|
|
|
'productId' => (string) $product->id,
|
|
|
|
|
'productName' => $product->name,
|
|
|
|
|
'unit' => $product->baseUnit?->name ?? 'N/A',
|
|
|
|
|
'baseUnit' => $product->baseUnit?->name,
|
|
|
|
|
'largeUnit' => $product->largeUnit?->name,
|
|
|
|
|
'conversionRate' => (float) $product->conversion_rate,
|
|
|
|
|
'lastPrice' => (float) $pivot->last_price,
|
|
|
|
|
];
|
|
|
|
|
})->filter()->values();
|
|
|
|
|
|
2026-01-26 14:59:24 +08:00
|
|
|
$formattedVendor = (object) [
|
|
|
|
|
'id' => (string) $vendor->id,
|
|
|
|
|
'code' => $vendor->code,
|
|
|
|
|
'name' => $vendor->name,
|
|
|
|
|
'shortName' => $vendor->short_name,
|
|
|
|
|
'taxId' => $vendor->tax_id,
|
|
|
|
|
'owner' => $vendor->owner,
|
|
|
|
|
'contactName' => $vendor->contact_name,
|
|
|
|
|
'phone' => $vendor->phone,
|
|
|
|
|
'tel' => $vendor->tel,
|
|
|
|
|
'email' => $vendor->email,
|
|
|
|
|
'address' => $vendor->address,
|
|
|
|
|
'remark' => $vendor->remark,
|
2026-01-27 08:59:45 +08:00
|
|
|
'supplyProducts' => $supplyProducts,
|
2026-01-26 14:59:24 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return Inertia::render('Vendor/Show', [
|
|
|
|
|
'vendor' => $formattedVendor,
|
|
|
|
|
'products' => $this->inventoryService->getAllProducts(), // 使用已有的服務獲取所有商品供選取
|
2025-12-30 15:03:19 +08:00
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-26 14:59:24 +08:00
|
|
|
* 將新建立的資源儲存到儲存體中。
|
2025-12-30 15:03:19 +08:00
|
|
|
*/
|
2026-01-26 14:59:24 +08:00
|
|
|
public function store(Request $request)
|
2025-12-30 15:03:19 +08:00
|
|
|
{
|
|
|
|
|
$validated = $request->validate([
|
|
|
|
|
'name' => 'required|string|max:255',
|
|
|
|
|
'short_name' => 'nullable|string|max:255',
|
|
|
|
|
'tax_id' => 'nullable|string|max:8',
|
|
|
|
|
'owner' => 'nullable|string|max:255',
|
|
|
|
|
'contact_name' => 'nullable|string|max:255',
|
|
|
|
|
'tel' => 'nullable|string|max:50',
|
|
|
|
|
'phone' => 'nullable|string|max:50',
|
|
|
|
|
'email' => 'nullable|email|max:255',
|
|
|
|
|
'address' => 'nullable|string',
|
|
|
|
|
'remark' => 'nullable|string',
|
|
|
|
|
]);
|
|
|
|
|
|
2026-01-26 14:59:24 +08:00
|
|
|
// 自動產生代碼
|
2025-12-30 15:03:19 +08:00
|
|
|
$prefix = 'V';
|
|
|
|
|
$lastVendor = Vendor::latest('id')->first();
|
|
|
|
|
$nextId = $lastVendor ? $lastVendor->id + 1 : 1;
|
|
|
|
|
$code = $prefix . str_pad($nextId, 5, '0', STR_PAD_LEFT);
|
|
|
|
|
|
|
|
|
|
$validated['code'] = $code;
|
|
|
|
|
|
|
|
|
|
Vendor::create($validated);
|
|
|
|
|
|
|
|
|
|
return redirect()->back()->with('success', '廠商已建立');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-26 14:59:24 +08:00
|
|
|
* 更新儲存體中的指定資源。
|
2025-12-30 15:03:19 +08:00
|
|
|
*/
|
2026-01-26 14:59:24 +08:00
|
|
|
public function update(Request $request, Vendor $vendor)
|
2025-12-30 15:03:19 +08:00
|
|
|
{
|
|
|
|
|
$validated = $request->validate([
|
|
|
|
|
'name' => 'required|string|max:255',
|
|
|
|
|
'short_name' => 'nullable|string|max:255',
|
|
|
|
|
'tax_id' => 'nullable|string|max:8',
|
|
|
|
|
'owner' => 'nullable|string|max:255',
|
|
|
|
|
'contact_name' => 'nullable|string|max:255',
|
|
|
|
|
'tel' => 'nullable|string|max:50',
|
|
|
|
|
'phone' => 'nullable|string|max:50',
|
|
|
|
|
'email' => 'nullable|email|max:255',
|
|
|
|
|
'address' => 'nullable|string',
|
|
|
|
|
'remark' => 'nullable|string',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$vendor->update($validated);
|
|
|
|
|
|
|
|
|
|
return redirect()->back()->with('success', '廠商資料已更新');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-26 14:59:24 +08:00
|
|
|
* 從儲存體中移除指定資源。
|
2025-12-30 15:03:19 +08:00
|
|
|
*/
|
|
|
|
|
public function destroy(Vendor $vendor)
|
|
|
|
|
{
|
|
|
|
|
$vendor->delete();
|
|
|
|
|
|
|
|
|
|
return redirect()->back()->with('success', '廠商已刪除');
|
|
|
|
|
}
|
|
|
|
|
}
|