1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import {
  CONTRACT_KIND,
  QUALITY_TYPE,
} from "./scanOut.constants";
import type { ContractKind, QualityType } from "./scanOut.constants";
 
type AnyRow = Record<string, any>;
 
export function parseOptionalNumber(raw: unknown): number | null {
  if (raw === null || raw === undefined || raw === "") return null;
  const n = Number(String(raw).trim());
  return Number.isNaN(n) ? null : n;
}
 
export function parseRemainingQuantity(row: AnyRow): number | null {
  const remRaw =
    row?.remainingQuantity ??
    row?.remaining_quantity ??
    row?.remainQuantity ??
    row?.remain_quantity;
  return parseOptionalNumber(remRaw);
}
 
export function defaultStockedQuantityFromRow(row: AnyRow): string {
  const rem = parseRemainingQuantity(row);
  if (rem !== null) return String(Math.max(0, rem));
 
  const avail = parseOptionalNumber(row?.availableQuality ?? row?.availableQuantity);
  if (avail !== null) return String(Math.max(0, avail));
 
  const qty = parseOptionalNumber(row?.quantity);
  if (qty !== null) return String(Math.max(0, qty));
 
  return "0";
}
 
/** 根据二维码 JSON 判断销售(XS)/采购(CG) */
export function resolveQrContractKind(scanData: AnyRow): ContractKind {
  const t = scanData?.type;
  const ts =
    t !== null && t !== undefined && t !== "" ? String(t).trim().toUpperCase() : "";
 
  if (ts === "CG" || t === 2 || t === "2") return CONTRACT_KIND.purchase;
  if (ts === "XS" || t === 1 || t === "1") return CONTRACT_KIND.sales;
 
  const pc = scanData?.purchaseContractNumber;
  const sc = scanData?.salesContractNo;
  if (pc != null && String(pc).trim() !== "" && (sc == null || String(sc).trim() === ""))
    return CONTRACT_KIND.purchase;
 
  return CONTRACT_KIND.sales;
}
 
export function resolveListTypeForDetail(contractKind: ContractKind): 1 | 2 {
  return contractKind === CONTRACT_KIND.purchase ? 2 : 1;
}
 
export function resolveContractNo(scanData: AnyRow, contractKind: ContractKind): string {
  const rawNo =
    contractKind === CONTRACT_KIND.purchase
      ? scanData.purchaseContractNumber
      : scanData.salesContractNo;
  return rawNo != null && String(rawNo).trim() !== "" ? String(rawNo).trim() : "";
}
 
export function buildSalesLedgerProductList(recordList: AnyRow[]): AnyRow[] {
  return recordList.map((item: AnyRow) => {
    const n = parseOptionalNumber(item.stockedQuantity);
    const qty = n !== null && !Number.isNaN(n) ? Math.max(0, n) : 0;
    const { stockedQuantity: _sq, ...rest } = item;
    return { ...rest, stockedQuantity: qty };
  });
}
 
export function hasAnyPositiveStockedQty(salesLedgerProductList: AnyRow[]): boolean {
  return salesLedgerProductList.some((p: AnyRow) => Number(p.stockedQuantity) > 0);
}
 
export function resolveSubmitSceneKey(contractKind: ContractKind, qualityType: QualityType): string {
  return `${contractKind}-${qualityType}`;
}
 
export function isQualified(qualityType: QualityType): boolean {
  return qualityType === QUALITY_TYPE.qualified;
}