Files
order_site/apps/backend/src/services/order/kuaishou-cloud-fulfillment-config-service.ts
T

216 lines
7.0 KiB
TypeScript

import path from "node:path";
import { PROJECT_ROOT } from "../../config/runtime.js";
import { readJsonFile, writeJsonFile } from "../../utils/json-file-store.js";
import { resolveKuaishouEticketShopConfig } from "../platforms/kuaishou-eticket/source-config-service.js";
const KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH = path.join(
PROJECT_ROOT,
"data",
"kuaishou-cloud-fulfillment.json"
);
type JsonObject = Record<string, any>;
export function getKuaishouCloudFulfillmentFilePath() {
return KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH;
}
export function getKuaishouCloudFulfillmentConfig() {
return loadKuaishouCloudFulfillmentConfigFromFile();
}
export function saveKuaishouCloudFulfillmentConfig(rawValue) {
return writeJsonFile(
KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH,
rawValue,
normalizeKuaishouCloudFulfillmentConfig
);
}
export function mapKuaishouCloudFulfillmentItemsToBindings(config: JsonObject = {}) {
const items = Array.isArray(config.items) ? config.items : [];
return items
.filter((item) => item && item.enabled !== false)
.map((item) => ({
provider: String(item.provider || "91kaquan").trim() || "91kaquan",
platform: String(item.platform || "kuaishou").trim() || "kuaishou",
shopId: String(item.shopId || "").trim(),
skuCode: String(item.internalSkuCode || "").trim(),
skuName: String(item.internalSkuName || "").trim(),
profileKey: "kuaishou_ct_assisted",
enabled: item.enabled !== false,
priority: normalizePriority(item.priority),
config: {
flowType: "kuaishou_cloud_fulfillment",
configId: String(item.id || "").trim(),
cloudtentacles: {
cloudSourceKey:
String(item.cloudSourceKey || "default").trim() || "default",
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
? item.cloudSourceKeyFallbacks
: [],
skuId: normalizePositiveInteger(item.cloudSkuId),
skuName: String(item.cloudSkuName || "").trim(),
vnKey: "1",
autoBuyEnabled: item.autoBuyEnabled !== false,
minAssetReserve: normalizeNonNegativeInteger(item.minAssetReserve, 0),
autoReturnNumberAfterDispatch:
item.autoReturnNumberAfterDispatch === true,
},
kuaishouConsume: {
shopId: String(item.kuaishouConsumeShopId || "").trim(),
shopName: String(item.kuaishouConsumeShopName || "").trim(),
autoConsumeAfterDispatch: item.autoConsumeAfterDispatch === true,
},
notes: String(item.notes || "").trim(),
},
match: {
externalSkuCode: String(item.externalSkuCode || "").trim(),
externalItemId: String(item.externalItemId || "").trim(),
externalSkuName: String(item.externalSkuName || "").trim(),
config: {
resolvedSkuName: String(
item.resolvedSkuName || item.internalSkuName || ""
).trim(),
},
},
}))
.filter(
(item) =>
item.skuCode &&
(item.match.externalSkuCode ||
item.match.externalItemId ||
item.match.externalSkuName)
);
}
function loadKuaishouCloudFulfillmentConfigFromFile() {
return readJsonFile(
KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH,
() => normalizeKuaishouCloudFulfillmentConfig({}),
normalizeKuaishouCloudFulfillmentConfig
);
}
function normalizeKuaishouCloudFulfillmentConfig(rawValue) {
const source = isPlainObject(rawValue) ? rawValue : {};
return {
enabled: source.enabled !== false,
items: Array.isArray(source.items)
? source.items
.map((item) => normalizeKuaishouCloudFulfillmentItem(item))
.filter(Boolean)
: [],
};
}
function normalizeKuaishouCloudFulfillmentItem(rawValue) {
if (!isPlainObject(rawValue)) {
return null;
}
const internalSkuCode = String(rawValue.internalSkuCode || "").trim();
const cloudSkuId = normalizePositiveInteger(rawValue.cloudSkuId);
const externalSkuCode = String(rawValue.externalSkuCode || "").trim();
const externalItemId = String(rawValue.externalItemId || "").trim();
const externalSkuName = String(rawValue.externalSkuName || "").trim();
const kuaishouConsumeShopId = String(
rawValue.kuaishouConsumeShopId || ""
).trim();
const kuaishouConsumeShopName = String(
rawValue.kuaishouConsumeShopName || ""
).trim();
const kuaishouShopConfig = resolveKuaishouEticketShopConfig({
shopId: kuaishouConsumeShopId,
shopName: kuaishouConsumeShopName,
});
if (!internalSkuCode) {
return null;
}
if (!cloudSkuId) {
return null;
}
if (!externalSkuCode && !externalItemId && !externalSkuName) {
return null;
}
return {
id: String(rawValue.id || internalSkuCode).trim() || internalSkuCode,
enabled: rawValue.enabled !== false,
priority: normalizePriority(rawValue.priority),
provider: String(rawValue.provider || "91kaquan").trim() || "91kaquan",
platform: String(rawValue.platform || "kuaishou").trim() || "kuaishou",
shopId: String(rawValue.shopId || "").trim(),
internalSkuCode,
internalSkuName:
String(rawValue.internalSkuName || "").trim() || internalSkuCode,
externalSkuCode,
externalItemId,
externalSkuName,
resolvedSkuName: String(
rawValue.resolvedSkuName || rawValue.internalSkuName || ""
).trim(),
cloudSourceKey:
String(rawValue.cloudSourceKey || "default").trim() || "default",
cloudSourceKeyFallbacks: normalizeStringArray(
rawValue.cloudSourceKeyFallbacks
),
cloudSkuId,
cloudSkuName: String(rawValue.cloudSkuName || "").trim(),
vnKey: "1",
autoBuyEnabled: rawValue.autoBuyEnabled !== false,
minAssetReserve: normalizeNonNegativeInteger(rawValue.minAssetReserve, 0),
autoReturnNumberAfterDispatch:
rawValue.autoReturnNumberAfterDispatch === true,
autoConsumeAfterDispatch: rawValue.autoConsumeAfterDispatch === true,
kuaishouConsumeShopId: String(
kuaishouShopConfig?.shopId || kuaishouConsumeShopId
).trim(),
kuaishouConsumeShopName: String(
kuaishouShopConfig?.kshopName || kuaishouConsumeShopName
).trim(),
notes: String(rawValue.notes || "").trim(),
};
}
function normalizePositiveInteger(value) {
const parsed = Number(value);
return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
}
function normalizeNonNegativeInteger(value, fallback) {
const parsed = Number(value);
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
}
function normalizePriority(value) {
const parsed = Number(value);
if (!Number.isFinite(parsed)) {
return 100;
}
return Math.max(1, Math.round(parsed));
}
function isPlainObject(value) {
return Object.prototype.toString.call(value) === "[object Object]";
}
function normalizeStringArray(value) {
if (Array.isArray(value)) {
return value.map((v) => String(v || "").trim()).filter(Boolean);
}
// 兼容旧格式:字符串用逗号分隔
if (typeof value === "string") {
return value
.split(",")
.map((v) => v.trim())
.filter(Boolean);
}
return [];
}