feat: 完成進貨單自動拋轉應付帳款流程與AP介面優化
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 1m8s
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:
85
app/Modules/Finance/Services/AccountPayableService.php
Normal file
85
app/Modules/Finance/Services/AccountPayableService.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Finance\Services;
|
||||
|
||||
use App\Modules\Finance\Models\AccountPayable;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Modules\Inventory\Contracts\GoodsReceiptServiceInterface;
|
||||
|
||||
class AccountPayableService
|
||||
{
|
||||
protected GoodsReceiptServiceInterface $goodsReceiptService;
|
||||
|
||||
public function __construct(GoodsReceiptServiceInterface $goodsReceiptService)
|
||||
{
|
||||
$this->goodsReceiptService = $goodsReceiptService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根據進貨單建立應付帳款
|
||||
*
|
||||
* @param int $goodsReceiptId
|
||||
* @param int $userId 執行操作的使用者 ID
|
||||
* @return AccountPayable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function createFromGoodsReceipt(int $goodsReceiptId, int $userId): AccountPayable
|
||||
{
|
||||
// 透過 Contract 取得 Inventory 模組的資料,避免直接依賴 Model
|
||||
$receiptData = $this->goodsReceiptService->getGoodsReceiptData($goodsReceiptId);
|
||||
|
||||
if (!$receiptData) {
|
||||
throw new \Exception("找不到對應的進貨單資料 (ID: {$goodsReceiptId})");
|
||||
}
|
||||
|
||||
// 檢查是否已經建立過(密等性)
|
||||
$existingAp = AccountPayable::where('source_document_type', 'goods_receipt')
|
||||
->where('source_document_id', $goodsReceiptId)
|
||||
->first();
|
||||
|
||||
if ($existingAp) {
|
||||
return $existingAp;
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($receiptData, $userId) {
|
||||
$ap = AccountPayable::create([
|
||||
'vendor_id' => $receiptData['vendor_id'],
|
||||
'source_document_type' => 'goods_receipt',
|
||||
'source_document_id' => $receiptData['id'],
|
||||
'document_number' => $this->generateApNumber(),
|
||||
'total_amount' => collect($receiptData['items'] ?? [])->sum('total_amount'),
|
||||
'tax_amount' => 0, // 假設後續會實作稅額計算,目前預設為 0
|
||||
'status' => AccountPayable::STATUS_PENDING,
|
||||
// 設定應付日期,預設為進貨後 30 天 (可依據供應商設定調整)
|
||||
'due_date' => now()->addDays(30)->toDateString(),
|
||||
'created_by' => $userId,
|
||||
'remarks' => "由進貨單 {$receiptData['code']} 自動生成",
|
||||
]);
|
||||
|
||||
return $ap;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 產生應付帳款單號
|
||||
*/
|
||||
protected function generateApNumber(): string
|
||||
{
|
||||
$prefix = 'AP-' . date('Ymd') . '-';
|
||||
$lastPrefix = "{$prefix}%";
|
||||
|
||||
$latest = AccountPayable::where('document_number', 'like', $lastPrefix)
|
||||
->orderBy('document_number', 'desc')
|
||||
->first();
|
||||
|
||||
if (!$latest) {
|
||||
return $prefix . '01';
|
||||
}
|
||||
|
||||
$parts = explode('-', $latest->document_number);
|
||||
$lastNumber = intval(end($parts));
|
||||
$newNumber = str_pad((string)($lastNumber + 1), 2, '0', STR_PAD_LEFT);
|
||||
|
||||
return $prefix . $newNumber;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user