feat: 完成進貨單自動拋轉應付帳款流程與AP介面優化
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 1m8s

1. 新增 AccountPayable (應付帳款) 模組,包含 Migration、Model、Service 與 Controller
2. 修改 GoodsReceipt (進貨單) 流程,在確認進貨時自動產生對應的應付帳款單 (AP-YYYYMMDD-XX)
3. 實作應付帳款詳細頁面 (Show.tsx),包含發票登記與標記付款功能
4. 修正應付帳款 Show 頁面的排版,將發票資訊套用標準的綠色背景區塊,並調整按鈕位置
5. 更新相關的 Service Provider 與 Routes
This commit is contained in:
2026-02-24 16:46:55 +08:00
parent aaa93a921e
commit 455f945296
33 changed files with 1708 additions and 186 deletions

View File

@@ -0,0 +1,124 @@
<?php
namespace App\Modules\Finance\Controllers;
use App\Http\Controllers\Controller;
use App\Modules\Finance\Models\AccountPayable;
use Illuminate\Http\Request;
use Inertia\Inertia;
class AccountPayableController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$query = AccountPayable::with(['vendor', 'creator']);
// 關鍵字搜尋 (單號、供應商名稱)
if ($request->filled('search')) {
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('document_number', 'like', "%{$search}%")
->orWhereHas('vendor', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
});
});
}
// 狀態過濾
if ($request->filled('status') && $request->status !== 'all') {
$query->where('status', $request->status);
}
// 供應商過濾
if ($request->filled('vendor_id') && $request->vendor_id !== 'all') {
$query->where('vendor_id', $request->vendor_id);
}
// 日期區間過濾
if ($request->filled('date_start')) {
$query->where('due_date', '>=', $request->date_start);
}
if ($request->filled('date_end')) {
$query->where('due_date', '<=', $request->date_end);
}
$perPage = $request->input('per_page', 10);
$payables = $query->latest()->paginate($perPage)->withQueryString();
$vendors = \App\Modules\Procurement\Models\Vendor::select('id', 'name')->get();
return Inertia::render('AccountPayable/Index', [
'payables' => $payables,
'filters' => $request->all(['search', 'status', 'vendor_id', 'date_start', 'date_end', 'per_page']),
'vendors' => $vendors,
]);
}
/**
* Display the specified resource.
*/
public function show(AccountPayable $accountPayable)
{
$accountPayable->load(['vendor', 'creator']);
// 嘗試加載來源單據資訊 (目前支援 goods_receipt)
$sourceDocumentCode = null;
if ($accountPayable->source_document_type === 'goods_receipt') {
$receipt = \App\Modules\Inventory\Models\GoodsReceipt::find($accountPayable->source_document_id);
if ($receipt) {
$sourceDocumentCode = $receipt->code;
}
}
return Inertia::render('AccountPayable/Show', [
// 將 model 轉換成 array 加入額外資訊
'payable' => array_merge($accountPayable->toArray(), ['source_document_code' => $sourceDocumentCode]),
]);
}
/**
* 更新發票資訊
*/
public function updateInvoice(Request $request, AccountPayable $accountPayable)
{
$validated = $request->validate([
'invoice_number' => 'nullable|string|max:50',
'invoice_date' => 'nullable|date',
]);
$accountPayable->update([
'invoice_number' => $validated['invoice_number'],
'invoice_date' => $validated['invoice_date'],
]);
return back()->with('success', '發票資訊已更新');
}
/**
* 標記已付款
*/
public function pay(Request $request, AccountPayable $accountPayable)
{
$validated = $request->validate([
'payment_method' => 'required|string|max:50',
'paid_at' => 'required|date',
'payment_note' => 'nullable|string|max:255',
]);
if ($accountPayable->status === AccountPayable::STATUS_PAID) {
return back()->with('error', '該帳款已經標記為已付款');
}
$accountPayable->update([
'status' => AccountPayable::STATUS_PAID,
'payment_method' => $validated['payment_method'],
'paid_at' => $validated['paid_at'],
'payment_note' => $validated['payment_note'],
]);
return back()->with('success', '帳款已成功標記為已付款');
}
}