This commit is contained in:
DDD1542
2026-04-07 11:52:13 +09:00
parent 00b388c3ab
commit 77d5b52265
4 changed files with 1183 additions and 675 deletions
@@ -127,6 +127,7 @@ export default function SupplierManagementPage() {
const [itemSelectOpen, setItemSelectOpen] = useState(false);
const [itemSearchKeyword, setItemSearchKeyword] = useState("");
const [itemSearchResults, setItemSearchResults] = useState<any[]>([]);
const [itemTotalCount, setItemTotalCount] = useState(0);
const [itemSearchLoading, setItemSearchLoading] = useState(false);
const [itemCheckedIds, setItemCheckedIds] = useState<Set<string>>(new Set());
@@ -817,12 +818,13 @@ export default function SupplierManagementPage() {
autoFilter: true,
});
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
setItemTotalCount(allItems.length);
const existingItemIds = new Set(priceItems.map((p: any) => p.item_id || p.item_number));
const PURCHASE_CODE = "CAT_MMDJB7R4_TO3T";
const PURCHASE_CODES = ["s"]; // 구매관리 카테고리 코드
setItemSearchResults(allItems.filter((item: any) => {
if (existingItemIds.has(item.item_number) || existingItemIds.has(item.id)) return false;
const div = item.division || "";
return div.includes(PURCHASE_CODE) || div.includes("구매");
const divCodes = (item.division || "").split(",").map((c: string) => c.trim());
return divCodes.some((code: string) => PURCHASE_CODES.includes(code));
}));
} catch { /* skip */ } finally { setItemSearchLoading(false); }
};
@@ -911,27 +913,27 @@ export default function SupplierManagementPage() {
[itemKey]: (prev[itemKey] || []).map((r) => {
if (r._id !== rowId) return r;
const updated = { ...r, [field]: value };
if (["base_price", "discount_type", "discount_value", "rounding_unit_value"].includes(field)) {
if (["base_price", "discount_type", "discount_value", "rounding_unit_value", "rounding_type"].includes(field)) {
const bp = Number(updated.base_price) || 0;
const dv = Number(updated.discount_value) || 0;
const dt = updated.discount_type;
let calc = bp;
if (dt === "CAT_MLAMBEC8_URQA") calc = bp * (1 - dv / 100);
else if (dt === "CAT_MLAMBLFM_JTLO") calc = bp - dv;
// 절삭/반올림 적용
// 반올림 유형 + 단위 적용
const rv = updated.rounding_unit_value;
const rt = updated.rounding_type;
const roundOpts = priceCategoryOptions["rounding_unit_value"] || [];
const roundLabel = roundOpts.find((o) => o.code === rv)?.label || "";
if (roundLabel.includes("절삭") || roundLabel.includes("버림") || roundLabel.includes("floor")) {
calc = Math.floor(calc);
} else if (roundLabel.includes("올림") || roundLabel.includes("ceil")) {
calc = Math.ceil(calc);
} else if (roundLabel.includes("반올림") || roundLabel.includes("round")) {
calc = Math.round(calc);
} else if (rv) {
// 단위 값 기반 (예: 10원 단위 절삭)
const unit = Number(rv);
if (!isNaN(unit) && unit > 0) calc = Math.floor(calc / unit) * unit;
const unitOpts = priceCategoryOptions["rounding_type"] || [];
const unitLabel = unitOpts.find((o) => o.code === rt)?.label || "";
const unit = parseInt(unitLabel) || 1; // "10원" → 10, "100원" → 100
if (roundLabel === "반올림") {
calc = Math.round(calc / unit) * unit;
} else if (roundLabel === "절삭") {
calc = Math.floor(calc / unit) * unit;
} else if (roundLabel === "올림") {
calc = Math.ceil(calc / unit) * unit;
}
updated.calculated_price = String(Math.floor(calc));
}
@@ -2370,7 +2372,7 @@ export default function SupplierManagementPage() {
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle> </DialogTitle>
<DialogDescription> .</DialogDescription>
<DialogDescription> . (: {itemTotalCount} / : {itemSearchResults.length}{itemCheckedIds.size > 0 ? ` / 선택: ${itemCheckedIds.size}` : ""})</DialogDescription>
</DialogHeader>
<div className="flex gap-2 mb-3">
<Input
@@ -2616,66 +2618,74 @@ export default function SupplierManagementPage() {
</Select>
</div>
</div>
{/* 기준가/할인/반올림 */}
<div className="flex gap-2 items-center">
<div className="w-[90px]">
<Select
value={price.base_price_type}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "base_price_type", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="기준" /></SelectTrigger>
<SelectContent>
{(priceCategoryOptions["base_price_type"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* 기준유형 + 기준가 */}
<div className="grid grid-cols-[1fr_70px_1fr_85px] gap-2 items-center">
<Select
value={price.base_price_type}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "base_price_type", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="기준유형" /></SelectTrigger>
<SelectContent>
{(priceCategoryOptions["base_price_type"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
<Input
value={price.base_price ? Number(price.base_price).toLocaleString() : ""}
onChange={(e) => {
const raw = e.target.value.replace(/[^\d.-]/g, "");
updatePriceRow(itemKey, price._id, "base_price", raw);
}}
className="h-9 text-[13px] text-right flex-1"
className="h-9 text-[13px] text-right col-span-3"
placeholder="기준가"
/>
<div className="w-[90px]">
<Select
value={price.discount_type}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "discount_type", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="할인" /></SelectTrigger>
<SelectContent>
<SelectItem value="none"></SelectItem>
{(priceCategoryOptions["discount_type"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
{/* 할인 + 반올림 */}
<div className="grid grid-cols-[1fr_70px_1fr_85px] gap-2 items-center">
<Select
value={price.discount_type}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "discount_type", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="할인" /></SelectTrigger>
<SelectContent>
<SelectItem value="none"></SelectItem>
{(priceCategoryOptions["discount_type"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
<Input
value={price.discount_value ? Number(price.discount_value).toLocaleString() : ""}
onChange={(e) => {
const raw = e.target.value.replace(/[^\d.-]/g, "");
updatePriceRow(itemKey, price._id, "discount_value", raw);
}}
className="h-9 text-[13px] text-right w-[60px]"
className="h-9 text-[13px] text-right"
placeholder="0"
/>
<div className="w-[90px]">
<Select
value={price.rounding_unit_value}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "rounding_unit_value", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="반올림" /></SelectTrigger>
<SelectContent>
{(priceCategoryOptions["rounding_unit_value"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Select
value={price.rounding_unit_value}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "rounding_unit_value", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="반올림" /></SelectTrigger>
<SelectContent>
{(priceCategoryOptions["rounding_unit_value"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
<Select
value={price.rounding_type}
onValueChange={(v) => updatePriceRow(itemKey, price._id, "rounding_type", v)}
>
<SelectTrigger className="h-9 text-[13px]"><SelectValue placeholder="단위" /></SelectTrigger>
<SelectContent>
{(priceCategoryOptions["rounding_type"] || []).map((o) => (
<SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* 계산 단가 */}
<div className="flex items-center justify-end gap-1.5 pt-2 border-t">