support split unit for product order
This commit is contained in:
+57
-3
@@ -59,6 +59,44 @@ export function comparePackageQuantity(left: number | string, right: number | st
|
||||
return leftValue < rightValue ? -1 : rightValue < leftValue ? 1 : 0;
|
||||
}
|
||||
|
||||
/** 将当前单位数量精确换算为最多三位小数的基础单位数量。 */
|
||||
export function toPackageBaseQuantity(quantity: number | string, baseQuantityPerUnit: number | string): string | undefined {
|
||||
const quantityParts = toDecimalParts(quantity, 3);
|
||||
const unitParts = toDecimalParts(baseQuantityPerUnit, 6);
|
||||
if (!quantityParts || !unitParts) {
|
||||
return undefined;
|
||||
}
|
||||
return formatDecimal(quantityParts.value * unitParts.value, quantityParts.scale + unitParts.scale, 3);
|
||||
}
|
||||
|
||||
/** 将数量从一个单位精确换算到另一个单位,结果最多保留三位小数。 */
|
||||
export function convertPackageQuantity(quantity: number | string, fromBaseQuantityPerUnit: number | string, toBaseQuantityPerUnit: number | string): string | undefined {
|
||||
const quantityParts = toDecimalParts(quantity, 3);
|
||||
const fromParts = toDecimalParts(fromBaseQuantityPerUnit, 6);
|
||||
const toParts = toDecimalParts(toBaseQuantityPerUnit, 6);
|
||||
if (!quantityParts || !fromParts || !toParts || toParts.value === 0n) {
|
||||
return undefined;
|
||||
}
|
||||
const numerator = quantityParts.value * fromParts.value * 10n ** BigInt(toParts.scale + 3);
|
||||
const denominator = 10n ** BigInt(quantityParts.scale + fromParts.scale) * toParts.value;
|
||||
if (numerator % denominator !== 0n) {
|
||||
return undefined;
|
||||
}
|
||||
return formatDecimal(numerator / denominator, 3, 3);
|
||||
}
|
||||
|
||||
/** 精确相加两个最多三位小数的数量。 */
|
||||
export function addPackageQuantity(left: number | string, right: number | string): string | undefined {
|
||||
const leftParts = toQuantityParts(left);
|
||||
const rightParts = toQuantityParts(right);
|
||||
if (!leftParts || !rightParts) {
|
||||
return undefined;
|
||||
}
|
||||
const scale = Math.max(leftParts.scale, rightParts.scale);
|
||||
const value = leftParts.value * 10n ** BigInt(scale - leftParts.scale) + rightParts.value * 10n ** BigInt(scale - rightParts.scale);
|
||||
return formatDecimal(value, scale, 3);
|
||||
}
|
||||
|
||||
export function getPackageQuantityText(value?: number | string | null): string {
|
||||
if (value === undefined || value === null || value === "") {
|
||||
return "0";
|
||||
@@ -79,13 +117,29 @@ export function getFundStatusText(status?: FundRecordStatus): string {
|
||||
}
|
||||
|
||||
function toQuantityParts(value: number | string): { value: bigint; scale: number } | undefined {
|
||||
const normalized = normalizePackageQuantity(value);
|
||||
if (!normalized) {
|
||||
return toDecimalParts(value, 3);
|
||||
}
|
||||
|
||||
function toDecimalParts(value: number | string, maxScale: number): { value: bigint; scale: number } | undefined {
|
||||
const text = String(value).trim();
|
||||
if (!new RegExp(`^\\d+(?:\\.\\d{1,${maxScale}})?$`).test(text)) {
|
||||
return undefined;
|
||||
}
|
||||
const [integerText, fractionText = ""] = normalized.split(".");
|
||||
const [integerText, fractionText = ""] = text.split(".");
|
||||
return {
|
||||
value: BigInt(`${integerText}${fractionText}`),
|
||||
scale: fractionText.length
|
||||
};
|
||||
}
|
||||
|
||||
function formatDecimal(value: bigint, scale: number, maxScale: number): string | undefined {
|
||||
while (maxScale < scale && value % 10n === 0n) {
|
||||
value /= 10n;
|
||||
scale--;
|
||||
}
|
||||
if (maxScale < scale) {
|
||||
return undefined;
|
||||
}
|
||||
const text = value.toString().padStart(scale + 1, "0");
|
||||
return normalizePackageQuantity(scale ? `${text.slice(0, -scale)}.${text.slice(-scale)}` : text);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user