2025-12-30 15:03:19 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 採購單相關工具函式
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import type { PurchaseOrderItem } from "@/types/purchase-order";
|
|
|
|
|
|
import { PRICE_ALERT_THRESHOLD } from "@/constants/purchase-order";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 格式化金額
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function formatCurrency(amount: number): string {
|
|
|
|
|
|
return `$${amount.toLocaleString()}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 計算項目小計
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function calculateSubtotal(quantity: number, unitPrice: number): number {
|
|
|
|
|
|
return quantity * unitPrice;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 計算總金額
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function calculateTotalAmount(items: PurchaseOrderItem[]): number {
|
|
|
|
|
|
return items.reduce((sum, item) => sum + Number(item.subtotal || 0), 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 檢查價格是否警示(超過閾值)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function isPriceAlert(currentPrice: number, previousPrice?: number): boolean {
|
|
|
|
|
|
if (!previousPrice || previousPrice === 0) return false;
|
|
|
|
|
|
const increase = ((currentPrice - previousPrice) / previousPrice) * 100;
|
|
|
|
|
|
return increase > PRICE_ALERT_THRESHOLD;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 計算價格漲幅百分比
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function calculatePriceIncrease(currentPrice: number, previousPrice?: number): number {
|
|
|
|
|
|
if (!previousPrice || previousPrice === 0) return 0;
|
|
|
|
|
|
return ((currentPrice - previousPrice) / previousPrice) * 100;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 生成採購單編號
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function generatePONumber(): string {
|
|
|
|
|
|
const year = new Date().getFullYear();
|
|
|
|
|
|
const sequence = (Date.now() % 100000).toString().padStart(5, "0");
|
|
|
|
|
|
return `PO${year}${sequence}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 取得今天日期(YYYY-MM-DD 格式)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getTodayDate(): string {
|
|
|
|
|
|
return new Date().toISOString().split("T")[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 驗證採購單表單
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function validatePurchaseOrder(
|
|
|
|
|
|
supplierId: string,
|
|
|
|
|
|
expectedDate: string,
|
|
|
|
|
|
items: PurchaseOrderItem[]
|
|
|
|
|
|
): boolean {
|
|
|
|
|
|
return !!(
|
|
|
|
|
|
supplierId &&
|
|
|
|
|
|
expectedDate &&
|
|
|
|
|
|
items.length > 0 &&
|
|
|
|
|
|
items.some((item) => item.quantity > 0)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-06 15:45:13 +08:00
|
|
|
|
* 過濾有效項目(數量和單價都必須大於 0)
|
2025-12-30 15:03:19 +08:00
|
|
|
|
*/
|
|
|
|
|
|
export function filterValidItems(items: PurchaseOrderItem[]): PurchaseOrderItem[] {
|
2026-01-06 15:45:13 +08:00
|
|
|
|
return items.filter((item) => item.quantity > 0 && item.unitPrice > 0);
|
2025-12-30 15:03:19 +08:00
|
|
|
|
}
|