feat: 修正庫存與撥補單邏輯並整合文件
1. 修復倉庫統計數據加總與樣式。 2. 修正可用庫存計算邏輯(排除不可銷售倉庫)。 3. 撥補單商品列表加入批號與效期顯示。 4. 修正撥補單儲存邏輯以支援精確批號轉移。 5. 整合 FEATURES.md 至 README.md。
This commit is contained in:
104
app/Modules/Finance/Services/FinanceService.php
Normal file
104
app/Modules/Finance/Services/FinanceService.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Finance\Services;
|
||||
|
||||
use App\Modules\Finance\Contracts\FinanceServiceInterface;
|
||||
use App\Modules\Finance\Models\UtilityFee;
|
||||
use App\Modules\Procurement\Contracts\ProcurementServiceInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class FinanceService implements FinanceServiceInterface
|
||||
{
|
||||
protected $procurementService;
|
||||
|
||||
public function __construct(ProcurementServiceInterface $procurementService)
|
||||
{
|
||||
$this->procurementService = $procurementService;
|
||||
}
|
||||
|
||||
public function getAccountingReportData(string $start, string $end): array
|
||||
{
|
||||
// 1. 獲取採購單資料
|
||||
$purchaseOrders = $this->procurementService->getPurchaseOrdersByDate($start, $end)
|
||||
->map(function ($po) {
|
||||
return [
|
||||
'id' => 'PO-' . $po->id,
|
||||
'date' => Carbon::parse($po->created_at)->timezone(config('app.timezone'))->toDateString(),
|
||||
'source' => '採購單',
|
||||
'category' => '進貨支出',
|
||||
'item' => $po->vendor->name ?? '未知廠商',
|
||||
'reference' => $po->code,
|
||||
'invoice_number' => $po->invoice_number,
|
||||
'amount' => (float)$po->grand_total,
|
||||
];
|
||||
});
|
||||
|
||||
// 2. 獲取公共事業費 (注意:目前資料表欄位為 transaction_date)
|
||||
$utilityFees = UtilityFee::whereBetween('transaction_date', [$start, $end])
|
||||
->get()
|
||||
->map(function ($fee) {
|
||||
return [
|
||||
'id' => 'UF-' . $fee->id,
|
||||
'date' => $fee->transaction_date->format('Y-m-d'),
|
||||
'source' => '公共事業費',
|
||||
'category' => $fee->category,
|
||||
'item' => $fee->description ?: $fee->category,
|
||||
'reference' => '-',
|
||||
'invoice_number' => $fee->invoice_number,
|
||||
'amount' => (float)$fee->amount,
|
||||
];
|
||||
});
|
||||
|
||||
$allRecords = $purchaseOrders->concat($utilityFees)
|
||||
->sortByDesc('date')
|
||||
->values();
|
||||
|
||||
return [
|
||||
'records' => $allRecords,
|
||||
'summary' => [
|
||||
'total_amount' => $allRecords->sum('amount'),
|
||||
'purchase_total' => $purchaseOrders->sum('amount'),
|
||||
'utility_total' => $utilityFees->sum('amount'),
|
||||
'record_count' => $allRecords->count(),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function getUtilityFees(array $filters)
|
||||
{
|
||||
$query = UtilityFee::query();
|
||||
|
||||
if (!empty($filters['search'])) {
|
||||
$search = $filters['search'];
|
||||
$query->where(function($q) use ($search) {
|
||||
$q->where('category', 'like', "%{$search}%")
|
||||
->orWhere('invoice_number', 'like', "%{$search}%")
|
||||
->orWhere('description', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
if (!empty($filters['category']) && $filters['category'] !== 'all') {
|
||||
$query->where('category', $filters['category']);
|
||||
}
|
||||
|
||||
if (!empty($filters['date_start'])) {
|
||||
$query->where('transaction_date', '>=', $filters['date_start']);
|
||||
}
|
||||
|
||||
if (!empty($filters['date_end'])) {
|
||||
$query->where('transaction_date', '<=', $filters['date_end']);
|
||||
}
|
||||
|
||||
$sortField = $filters['sort_field'] ?? 'created_at';
|
||||
$sortDirection = $filters['sort_direction'] ?? 'desc';
|
||||
$query->orderBy($sortField, $sortDirection);
|
||||
|
||||
return $query->paginate($filters['per_page'] ?? 10);
|
||||
}
|
||||
|
||||
public function getUniqueCategories(): Collection
|
||||
{
|
||||
return UtilityFee::distinct()->pluck('category');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user