优化履约账号优先级配置
This commit is contained in:
@@ -84,9 +84,8 @@ export function mapKuaishouCloudFulfillmentContext(value: unknown): JsonRecord |
|
||||
},
|
||||
binding: {
|
||||
prepareStatus: String(binding.prepareStatus || 'pending').trim() || 'pending',
|
||||
cloudSourceKey: String(binding.cloudSourceKey || '').trim(),
|
||||
cloudSourceKeyFallbacks: Array.isArray(binding.cloudSourceKeyFallbacks)
|
||||
? binding.cloudSourceKeyFallbacks.map((value: unknown) => String(value || '').trim()).filter(Boolean)
|
||||
cloudSourceKeys: Array.isArray(binding.cloudSourceKeys)
|
||||
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
|
||||
: [],
|
||||
resolvedSourceKey: String(binding.resolvedSourceKey || '').trim(),
|
||||
skuId: Number(binding.skuId || 0) || 0,
|
||||
|
||||
@@ -79,7 +79,7 @@ test('mapAdminKuaishouCloudFulfillmentSource normalizes items and defaults', ()
|
||||
id: ' item-1 ',
|
||||
provider: '',
|
||||
platform: '',
|
||||
cloudSourceKey: '',
|
||||
cloudSourceKeys: [' account_a ', 'account_b'],
|
||||
cloudSkuId: '0',
|
||||
autoConsumeAfterDispatch: true,
|
||||
kuaishouConsumeShopId: ' ks1 ',
|
||||
@@ -103,8 +103,7 @@ test('mapAdminKuaishouCloudFulfillmentSource normalizes items and defaults', ()
|
||||
externalItemId: '',
|
||||
externalSkuName: '',
|
||||
resolvedSkuName: '',
|
||||
cloudSourceKey: 'default',
|
||||
cloudSourceKeyFallbacks: [],
|
||||
cloudSourceKeys: ['account_a', 'account_b'],
|
||||
cloudSkuId: 0,
|
||||
cloudSkuName: '',
|
||||
vnKey: '',
|
||||
|
||||
@@ -75,10 +75,8 @@ export function mapAdminKuaishouCloudFulfillmentItem(item: JsonObject = {}) {
|
||||
externalItemId: String(item.externalItemId || "").trim(),
|
||||
externalSkuName: String(item.externalSkuName || "").trim(),
|
||||
resolvedSkuName: String(item.resolvedSkuName || "").trim(),
|
||||
cloudSourceKey:
|
||||
String(item.cloudSourceKey || "default").trim() || "default",
|
||||
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
|
||||
? item.cloudSourceKeyFallbacks
|
||||
cloudSourceKeys: Array.isArray(item.cloudSourceKeys)
|
||||
? item.cloudSourceKeys
|
||||
.map((value) => String(value || "").trim())
|
||||
.filter(Boolean)
|
||||
: [],
|
||||
|
||||
@@ -75,7 +75,7 @@ export async function prepareAdminTaskKuaishouCloudFulfillment(
|
||||
|
||||
const taskContext = parseTaskContext(task)
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext()
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext(flow.binding.cloudSourceKeys)
|
||||
const [knapsack, skuList] = await Promise.all([
|
||||
getCloudtentaclesKnapsack(cloudContext),
|
||||
listCloudtentaclesSku(cloudContext),
|
||||
@@ -164,6 +164,7 @@ export async function prepareAdminTaskKuaishouCloudFulfillment(
|
||||
...flowWithResolvedBinding,
|
||||
binding: {
|
||||
...flowWithResolvedBinding.binding,
|
||||
resolvedSourceKey: cloudContext.resolvedSourceKey,
|
||||
vnKey: preparedBinding.vnKey,
|
||||
prepareStatus: 'ready',
|
||||
vnId,
|
||||
@@ -250,7 +251,10 @@ export async function dispatchAdminTaskKuaishouCloudFulfillment(
|
||||
|
||||
const taskContext = parseTaskContext(task)
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext()
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
])
|
||||
|
||||
if (!flow.binding.skuId || !flow.binding.vnId || !flow.binding.vnPhone) {
|
||||
throw createHttpError('当前任务还没有准备好绑定资源,请先准备绑定资源', {
|
||||
@@ -364,7 +368,10 @@ export async function refreshAdminTaskKuaishouCloudRoleInfo(
|
||||
})
|
||||
}
|
||||
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext()
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
])
|
||||
const bindInfoResult = await getCloudtentaclesBindInfo({
|
||||
...cloudContext,
|
||||
key: flow.binding.vnKey,
|
||||
@@ -441,7 +448,10 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
|
||||
|
||||
const taskContext = parseTaskContext(task)
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext()
|
||||
const cloudContext = resolvePersistedCloudtentaclesContext([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
])
|
||||
|
||||
if (!flow.binding.vnId || !flow.binding.vnKey) {
|
||||
throw createHttpError('当前任务缺少可退还的虚拟号信息', {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import type { HttpErrorLike } from '../../../utils/http.js'
|
||||
import {
|
||||
resolvePersistedCloudtentaclesContext as resolveFulfillmentPersistedCloudtentaclesContext,
|
||||
resolvePersistedCloudtentaclesContextBySourceKeys,
|
||||
} from '../../fulfillment/kuaishou-cloud/cloudtentacles-context.js'
|
||||
|
||||
export {
|
||||
@@ -23,6 +23,7 @@ export type CloudtentaclesContext = {
|
||||
token: string
|
||||
deviceId: string
|
||||
deviceType: number
|
||||
resolvedSourceKey: string
|
||||
}
|
||||
|
||||
export type CloudSkuLikeItem = {
|
||||
@@ -62,9 +63,9 @@ export type PreparedKuaishouCloudBindResource = {
|
||||
bindUrl: string
|
||||
}
|
||||
|
||||
export function resolvePersistedCloudtentaclesContext(): CloudtentaclesContext {
|
||||
export function resolvePersistedCloudtentaclesContext(sourceKeys: unknown[]): CloudtentaclesContext {
|
||||
try {
|
||||
return resolveFulfillmentPersistedCloudtentaclesContext()
|
||||
return resolvePersistedCloudtentaclesContextBySourceKeys(sourceKeys)
|
||||
} catch (error) {
|
||||
if (isMissingCloudtentaclesTokenError(error)) {
|
||||
throw createHttpError('当前 cloudtentacles 没有可用 token,请先到平台配置完成登录校验', {
|
||||
|
||||
@@ -172,7 +172,10 @@ export function mapClaimKuaishouCloudFulfillment(task: TaskRow, order: OrderRow)
|
||||
},
|
||||
binding: {
|
||||
prepareStatus: String(binding.prepareStatus || 'pending').trim() || 'pending',
|
||||
cloudSourceKey: String(binding.cloudSourceKey || '').trim(),
|
||||
cloudSourceKeys: Array.isArray(binding.cloudSourceKeys)
|
||||
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
|
||||
: [],
|
||||
resolvedSourceKey: String(binding.resolvedSourceKey || '').trim(),
|
||||
skuId: Number(binding.skuId || 0) || 0,
|
||||
skuName: String(binding.skuName || '').trim(),
|
||||
vnKey: String(binding.vnKey || '').trim(),
|
||||
|
||||
@@ -1,56 +1,18 @@
|
||||
import { createHttpError } from "../../../utils/http.js";
|
||||
import {
|
||||
getCloudtentaclesSourceConfig,
|
||||
getCloudtentaclesSourceByKey,
|
||||
} from "../../platforms/cloudtentacles/source-config-service.js";
|
||||
import {
|
||||
getCloudtentaclesSessionState,
|
||||
getCloudtentaclesSessionStateByKey,
|
||||
} from "../../platforms/cloudtentacles/session-state-service.js";
|
||||
import { getCloudtentaclesSourceByKey } from "../../platforms/cloudtentacles/source-config-service.js";
|
||||
import { getCloudtentaclesSessionStateByKey } from "../../platforms/cloudtentacles/session-state-service.js";
|
||||
import { normalizeStringArray } from "./domain.js";
|
||||
|
||||
export function resolvePersistedCloudtentaclesContext(sourceKey = "default") {
|
||||
const source =
|
||||
getCloudtentaclesSourceByKey(sourceKey) || getCloudtentaclesSourceConfig();
|
||||
const session =
|
||||
getCloudtentaclesSessionStateByKey(sourceKey) ||
|
||||
getCloudtentaclesSessionState();
|
||||
const token = String(session.token || "").trim();
|
||||
|
||||
if (!token) {
|
||||
throw createHttpError(
|
||||
"当前 cloudtentacles 没有可用 token,请先到平台配置完成登录校验",
|
||||
{
|
||||
statusCode: 409,
|
||||
errorCode: "kuaishou_cloud_missing_cloud_token",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
baseUrl:
|
||||
String(session.baseUrl || source.baseUrl || "").trim() ||
|
||||
"https://123.207.217.176",
|
||||
token,
|
||||
deviceId: String(session.deviceId || source.deviceId || "-").trim() || "-",
|
||||
deviceType: Number(session.deviceType ?? source.deviceType ?? 0),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 按优先级依次尝试 cloudSourceKey 和 fallbacks 列表中的账号,
|
||||
* 按优先级依次尝试 cloudSourceKeys 列表中的账号,
|
||||
* 找到第一个有可用 token 的账号返回其 context。
|
||||
* 将实际使用的 resolvedSourceKey 也返回,确保后续操作(退号、发货等)
|
||||
* 使用同一个 sourceKey,防止跨账号操作导致数据不一致。
|
||||
*/
|
||||
export function resolvePersistedCloudtentaclesContextWithFallback(
|
||||
primarySourceKey = "default",
|
||||
fallbacks: unknown[] = []
|
||||
export function resolvePersistedCloudtentaclesContextBySourceKeys(
|
||||
sourceKeys: unknown[] = []
|
||||
) {
|
||||
const candidates = [
|
||||
String(primarySourceKey || "default").trim() || "default",
|
||||
...normalizeStringArray(fallbacks),
|
||||
];
|
||||
const candidates = normalizeStringArray(sourceKeys);
|
||||
|
||||
const uniqueCandidates = [...new Set(candidates)];
|
||||
|
||||
@@ -101,7 +63,7 @@ export function resolvePersistedCloudtentaclesContextWithFallback(
|
||||
throw (
|
||||
lastError ||
|
||||
createHttpError(
|
||||
"所有 cloudtentacles 备选账号均不可用,请先到平台配置完成登录校验",
|
||||
"所有 cloudtentacles 账号均不可用,请先到平台配置完成登录校验",
|
||||
{ statusCode: 409, errorCode: "kuaishou_cloud_all_source_keys_exhausted" }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -62,11 +62,7 @@ export function normalizeKuaishouCloudFlow(value: unknown) {
|
||||
binding: {
|
||||
prepareStatus:
|
||||
String(binding.prepareStatus || "pending").trim() || "pending",
|
||||
cloudSourceKey:
|
||||
String(binding.cloudSourceKey || "default").trim() || "default",
|
||||
cloudSourceKeyFallbacks: normalizeStringArray(
|
||||
binding.cloudSourceKeyFallbacks
|
||||
),
|
||||
cloudSourceKeys: normalizeStringArray(binding.cloudSourceKeys),
|
||||
resolvedSourceKey: String(binding.resolvedSourceKey || "").trim(),
|
||||
skuId: Number(binding.skuId || 0) || 0,
|
||||
skuName: String(binding.skuName || "").trim(),
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
resolveKuaishouCloudVnKeyCandidates,
|
||||
} from "./binding-resources.js";
|
||||
import {
|
||||
resolvePersistedCloudtentaclesContextWithFallback,
|
||||
resolvePersistedCloudtentaclesContextBySourceKeys,
|
||||
} from "./cloudtentacles-context.js";
|
||||
import {
|
||||
getTaskClaimExpiresAt,
|
||||
@@ -55,8 +55,7 @@ export {
|
||||
resolveKuaishouCloudBindUrlExpiresAt,
|
||||
} from "./domain.js";
|
||||
export {
|
||||
resolvePersistedCloudtentaclesContext,
|
||||
resolvePersistedCloudtentaclesContextWithFallback,
|
||||
resolvePersistedCloudtentaclesContextBySourceKeys,
|
||||
} from "./cloudtentacles-context.js";
|
||||
|
||||
export async function ensureTaskClaimLink(task: TaskRow) {
|
||||
@@ -135,9 +134,8 @@ export async function prepareKuaishouCloudFulfillmentTask(
|
||||
};
|
||||
}
|
||||
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||
flow.binding.cloudSourceKey || "default",
|
||||
flow.binding.cloudSourceKeyFallbacks || []
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextBySourceKeys(
|
||||
flow.binding.cloudSourceKeys
|
||||
);
|
||||
const [knapsack, skuList] = await Promise.all([
|
||||
getCloudtentaclesKnapsack(cloudContext),
|
||||
@@ -335,12 +333,10 @@ export async function refreshKuaishouCloudTaskBindUrl(
|
||||
});
|
||||
}
|
||||
|
||||
const effectiveSourceKey =
|
||||
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||
effectiveSourceKey,
|
||||
flow.binding.cloudSourceKeyFallbacks || []
|
||||
);
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextBySourceKeys([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
]);
|
||||
const oldVnKey = flow.binding.vnKey;
|
||||
const oldVnId = flow.binding.vnId;
|
||||
const oldVnPhone = flow.binding.vnPhone;
|
||||
@@ -707,12 +703,10 @@ export async function refreshKuaishouCloudTaskRoleInfo(
|
||||
}
|
||||
}
|
||||
|
||||
const effectiveSourceKey =
|
||||
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||
effectiveSourceKey,
|
||||
flow.binding.cloudSourceKeyFallbacks || []
|
||||
);
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextBySourceKeys([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
]);
|
||||
const bindInfoResult = await getCloudtentaclesBindInfo({
|
||||
...cloudContext,
|
||||
key: flow.binding.vnKey,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
normalizeKuaishouCloudFlow,
|
||||
type JsonObject,
|
||||
} from "./domain.js";
|
||||
import { resolvePersistedCloudtentaclesContextWithFallback } from "./cloudtentacles-context.js";
|
||||
import { resolvePersistedCloudtentaclesContextBySourceKeys } from "./cloudtentacles-context.js";
|
||||
import { normalizeActor, parseTaskContext } from "./task-context.js";
|
||||
import type { TaskRow } from "../../../types/repository/rows.js";
|
||||
|
||||
@@ -37,12 +37,10 @@ export async function dispatchKuaishouCloudFulfillmentTask(
|
||||
const now = nowIso();
|
||||
const taskContext = parseTaskContext(task);
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment);
|
||||
const effectiveSourceKey =
|
||||
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||
effectiveSourceKey,
|
||||
flow.binding.cloudSourceKeyFallbacks || []
|
||||
);
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextBySourceKeys([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
]);
|
||||
|
||||
if (!flow.binding.skuId || !flow.binding.vnId || !flow.binding.vnPhone) {
|
||||
throw createHttpError(
|
||||
@@ -178,12 +176,10 @@ export async function returnKuaishouCloudFulfillmentTask(
|
||||
const now = nowIso();
|
||||
const taskContext = parseTaskContext(task);
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment);
|
||||
const effectiveSourceKey =
|
||||
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||
effectiveSourceKey,
|
||||
flow.binding.cloudSourceKeyFallbacks || []
|
||||
);
|
||||
const cloudContext = resolvePersistedCloudtentaclesContextBySourceKeys([
|
||||
flow.binding.resolvedSourceKey,
|
||||
...flow.binding.cloudSourceKeys,
|
||||
]);
|
||||
|
||||
if (!flow.binding.vnId || !flow.binding.vnKey) {
|
||||
throw createHttpError("当前任务缺少可退还的虚拟号信息", {
|
||||
|
||||
@@ -185,7 +185,7 @@ export async function syncDeliveryTasksForOrderWithDeps(
|
||||
},
|
||||
binding: {
|
||||
prepareStatus: 'pending',
|
||||
cloudSourceKey: String(cloudtentaclesConfig.cloudSourceKey || 'default').trim() || 'default',
|
||||
cloudSourceKeys: normalizeStringArray(cloudtentaclesConfig.cloudSourceKeys),
|
||||
skuId: Number(cloudtentaclesConfig.skuId || 0) || 0,
|
||||
skuName: String(cloudtentaclesConfig.skuName || '').trim(),
|
||||
vnKey: '1',
|
||||
@@ -384,6 +384,16 @@ function parseJsonObject(value: unknown): JsonObject {
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeStringArray(value: unknown): string[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return []
|
||||
}
|
||||
|
||||
return Array.from(
|
||||
new Set(value.map((item) => String(item || '').trim()).filter(Boolean)),
|
||||
)
|
||||
}
|
||||
|
||||
function isTaskRow(task: TaskRow | DeliveryTaskRow | null | undefined): task is TaskRow {
|
||||
return Boolean(task && Number(task.id || 0) > 0)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ test('mapKuaishouCloudFulfillmentItemsToBindings maps 91kaquan rules', () => {
|
||||
externalSkuCode: '952',
|
||||
externalItemId: '952',
|
||||
externalSkuName: '测试2',
|
||||
cloudSourceKeys: ['account_a', 'account_b'],
|
||||
cloudSkuId: 28,
|
||||
},
|
||||
],
|
||||
@@ -35,8 +36,7 @@ test('mapKuaishouCloudFulfillmentItemsToBindings maps 91kaquan rules', () => {
|
||||
flowType: 'kuaishou_cloud_fulfillment',
|
||||
configId: '',
|
||||
cloudtentacles: {
|
||||
cloudSourceKey: 'default',
|
||||
cloudSourceKeyFallbacks: [],
|
||||
cloudSourceKeys: ['account_a', 'account_b'],
|
||||
skuId: 28,
|
||||
skuName: '',
|
||||
vnKey: '1',
|
||||
|
||||
@@ -46,11 +46,7 @@ export function mapKuaishouCloudFulfillmentItemsToBindings(config: JsonObject =
|
||||
flowType: "kuaishou_cloud_fulfillment",
|
||||
configId: String(item.id || "").trim(),
|
||||
cloudtentacles: {
|
||||
cloudSourceKey:
|
||||
String(item.cloudSourceKey || "default").trim() || "default",
|
||||
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
|
||||
? item.cloudSourceKeyFallbacks
|
||||
: [],
|
||||
cloudSourceKeys: normalizeStringArray(item.cloudSourceKeys),
|
||||
skuId: normalizePositiveInteger(item.cloudSkuId),
|
||||
skuName: String(item.cloudSkuName || "").trim(),
|
||||
vnKey: "1",
|
||||
@@ -113,6 +109,7 @@ function normalizeKuaishouCloudFulfillmentItem(rawValue: unknown) {
|
||||
|
||||
const internalSkuCode = String(rawValue.internalSkuCode || "").trim();
|
||||
const cloudSkuId = normalizePositiveInteger(rawValue.cloudSkuId);
|
||||
const cloudSourceKeys = normalizeStringArray(rawValue.cloudSourceKeys);
|
||||
const externalSkuCode = String(rawValue.externalSkuCode || "").trim();
|
||||
const externalItemId = String(rawValue.externalItemId || "").trim();
|
||||
const externalSkuName = String(rawValue.externalSkuName || "").trim();
|
||||
@@ -135,6 +132,10 @@ function normalizeKuaishouCloudFulfillmentItem(rawValue: unknown) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cloudSourceKeys.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!externalSkuCode && !externalItemId && !externalSkuName) {
|
||||
return null;
|
||||
}
|
||||
@@ -155,11 +156,7 @@ function normalizeKuaishouCloudFulfillmentItem(rawValue: unknown) {
|
||||
resolvedSkuName: String(
|
||||
rawValue.resolvedSkuName || rawValue.internalSkuName || ""
|
||||
).trim(),
|
||||
cloudSourceKey:
|
||||
String(rawValue.cloudSourceKey || "default").trim() || "default",
|
||||
cloudSourceKeyFallbacks: normalizeStringArray(
|
||||
rawValue.cloudSourceKeyFallbacks
|
||||
),
|
||||
cloudSourceKeys,
|
||||
cloudSkuId,
|
||||
cloudSkuName: String(rawValue.cloudSkuName || "").trim(),
|
||||
vnKey: "1",
|
||||
@@ -204,12 +201,5 @@ function normalizeStringArray(value: unknown) {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((v: unknown) => String(v || "").trim()).filter(Boolean);
|
||||
}
|
||||
// 兼容旧格式:字符串用逗号分隔
|
||||
if (typeof value === "string") {
|
||||
return value
|
||||
.split(",")
|
||||
.map((v: string) => v.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ export type AdminKuaishouCloudFulfillmentItemInput = {
|
||||
externalItemId?: string
|
||||
externalSkuName?: string
|
||||
resolvedSkuName?: string
|
||||
cloudSourceKey?: string
|
||||
cloudSourceKeyFallbacks?: string[]
|
||||
cloudSourceKeys?: string[]
|
||||
cloudSkuId?: number | string
|
||||
cloudSkuName?: string
|
||||
vnKey?: string
|
||||
|
||||
Reference in New Issue
Block a user