完整流程-调试
This commit is contained in:
@@ -41,6 +41,7 @@ export async function syncDeliveryTasksForOrder(order, orderItems) {
|
||||
const requirements = await listFulfillmentProfileRequirements(profile.profile_id || profile.id)
|
||||
const primaryRequirement = requirements.find((requirement) => requirement.is_required !== false) || requirements[0] || null
|
||||
const quantity = Math.max(1, Number(item.quantity || 1))
|
||||
const fulfillmentConfig = parseJsonObject(profile.config_json)
|
||||
|
||||
for (let index = 0; index < quantity; index += 1) {
|
||||
const createdAt = nowIso()
|
||||
@@ -84,6 +85,58 @@ export async function syncDeliveryTasksForOrder(order, orderItems) {
|
||||
credentialType: String(primaryRequirement.credential_type || primaryRequirement.credentialType || 'tencent_code'),
|
||||
}
|
||||
: null,
|
||||
kuaishouCloudFulfillment: isKuaishouCloudExecutor(profile.executor_key)
|
||||
? {
|
||||
flowType: 'kuaishou_cloud_fulfillment',
|
||||
configId: String(fulfillmentConfig.configId || '').trim(),
|
||||
internalSkuCode: item.sku_code,
|
||||
internalSkuName: item.sku_name,
|
||||
ticket: {
|
||||
code: '',
|
||||
capturedAt: null,
|
||||
capturedBy: null,
|
||||
},
|
||||
binding: {
|
||||
prepareStatus: 'pending',
|
||||
cloudSourceKey: String(fulfillmentConfig.cloudtentacles?.cloudSourceKey || 'default').trim() || 'default',
|
||||
skuId: Number(fulfillmentConfig.cloudtentacles?.skuId || 0) || 0,
|
||||
skuName: String(fulfillmentConfig.cloudtentacles?.skuName || '').trim(),
|
||||
vnKey: String(fulfillmentConfig.cloudtentacles?.vnKey || '').trim(),
|
||||
vnId: 0,
|
||||
vnPhone: '',
|
||||
bindUrl: '',
|
||||
bindPreparedAt: null,
|
||||
},
|
||||
purchase: {
|
||||
autoBuyEnabled: fulfillmentConfig.cloudtentacles?.autoBuyEnabled !== false,
|
||||
minAssetReserve: Number(fulfillmentConfig.cloudtentacles?.minAssetReserve || 0) || 0,
|
||||
usedKnapsack: false,
|
||||
purchaseTriggered: false,
|
||||
assetBefore: 0,
|
||||
assetAfter: 0,
|
||||
purchaseAt: null,
|
||||
},
|
||||
dispatch: {
|
||||
status: 'pending',
|
||||
dispatchAt: null,
|
||||
dispatchBy: null,
|
||||
sendType: 0,
|
||||
note: '',
|
||||
},
|
||||
returnNumber: {
|
||||
status: 'pending',
|
||||
returnedAt: null,
|
||||
returnedBy: null,
|
||||
autoReturnEnabled: fulfillmentConfig.cloudtentacles?.autoReturnNumberAfterDispatch === true,
|
||||
},
|
||||
consume: {
|
||||
status: 'pending',
|
||||
shopId: String(fulfillmentConfig.kuaishouConsume?.shopId || '').trim(),
|
||||
autoConsumeEnabled: fulfillmentConfig.kuaishouConsume?.autoConsumeAfterDispatch === true,
|
||||
},
|
||||
notes: String(fulfillmentConfig.notes || '').trim(),
|
||||
}
|
||||
: null,
|
||||
}),
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
@@ -114,6 +167,27 @@ async function preparePaidTask(task) {
|
||||
return task
|
||||
}
|
||||
|
||||
if (isKuaishouCloudExecutor(task.executor_key)) {
|
||||
if ([
|
||||
'pending_binding_prepare',
|
||||
'waiting_binding',
|
||||
'dispatched_pending_return',
|
||||
'completed',
|
||||
'manual_review',
|
||||
'failed',
|
||||
].includes(String(task.task_status || '').trim())) {
|
||||
return task
|
||||
}
|
||||
|
||||
return updateTask(task.id, {
|
||||
task_status: 'pending_binding_prepare',
|
||||
inventory_status: 'not_required',
|
||||
user_action_status: 'pending',
|
||||
last_error: task.last_error || '等待准备绑定资源',
|
||||
updated_at: now,
|
||||
})
|
||||
}
|
||||
|
||||
if (!task.requires_claim || String(task.executor_key || '').trim() === 'manual_dispatch') {
|
||||
return updateTask(task.id, {
|
||||
task_status: 'manual_review',
|
||||
@@ -182,6 +256,10 @@ function resolvePaidTaskStatus(profile) {
|
||||
return 'paid'
|
||||
}
|
||||
|
||||
if (isKuaishouCloudExecutor(profile?.executor_key)) {
|
||||
return 'pending_binding_prepare'
|
||||
}
|
||||
|
||||
if (String(profile?.executor_key || '').trim() === 'manual_dispatch') {
|
||||
return 'manual_review'
|
||||
}
|
||||
@@ -206,3 +284,24 @@ function parseTaskContext(task) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function parseJsonObject(value) {
|
||||
if (!value) {
|
||||
return {}
|
||||
}
|
||||
|
||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||
return value
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(String(value || '{}'))
|
||||
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function isKuaishouCloudExecutor(value) {
|
||||
return String(value || '').trim() === 'kuaishou_ct_assisted'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import { PROJECT_ROOT } from '../../config/runtime.js'
|
||||
|
||||
const KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'kuaishou-cloud-fulfillment.json')
|
||||
|
||||
export function getKuaishouCloudFulfillmentFilePath() {
|
||||
return KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH
|
||||
}
|
||||
|
||||
export function getKuaishouCloudFulfillmentConfig() {
|
||||
return loadKuaishouCloudFulfillmentConfigFromFile()
|
||||
}
|
||||
|
||||
export function saveKuaishouCloudFulfillmentConfig(rawValue) {
|
||||
const normalized = normalizeKuaishouCloudFulfillmentConfig(rawValue)
|
||||
fs.mkdirSync(path.dirname(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH), { recursive: true })
|
||||
fs.writeFileSync(
|
||||
KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH,
|
||||
`${JSON.stringify(normalized, null, 2)}\n`,
|
||||
'utf8',
|
||||
)
|
||||
return normalized
|
||||
}
|
||||
|
||||
export function mapKuaishouCloudFulfillmentItemsToBindings(config = {}) {
|
||||
const items = Array.isArray(config.items) ? config.items : []
|
||||
|
||||
return items
|
||||
.filter((item) => item && item.enabled !== false)
|
||||
.map((item) => ({
|
||||
provider: String(item.provider || 'khhao').trim() || 'khhao',
|
||||
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',
|
||||
skuId: normalizePositiveInteger(item.cloudSkuId),
|
||||
skuName: String(item.cloudSkuName || '').trim(),
|
||||
vnKey: String(item.vnKey || '').trim(),
|
||||
autoBuyEnabled: item.autoBuyEnabled !== false,
|
||||
minAssetReserve: normalizeNonNegativeInteger(item.minAssetReserve, 0),
|
||||
autoReturnNumberAfterDispatch: item.autoReturnNumberAfterDispatch === true,
|
||||
},
|
||||
kuaishouConsume: {
|
||||
shopId: String(item.kuaishouConsumeShopId || '').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() {
|
||||
if (!fs.existsSync(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH)) {
|
||||
return normalizeKuaishouCloudFulfillmentConfig({})
|
||||
}
|
||||
|
||||
try {
|
||||
const rawText = fs.readFileSync(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH, 'utf8')
|
||||
const parsed = JSON.parse(rawText)
|
||||
return normalizeKuaishouCloudFulfillmentConfig(parsed)
|
||||
} catch {
|
||||
return 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 vnKey = String(rawValue.vnKey || '').trim()
|
||||
const externalSkuCode = String(rawValue.externalSkuCode || '').trim()
|
||||
const externalItemId = String(rawValue.externalItemId || '').trim()
|
||||
const externalSkuName = String(rawValue.externalSkuName || '').trim()
|
||||
|
||||
if (!internalSkuCode) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!cloudSkuId || !vnKey) {
|
||||
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 || 'khhao').trim() || 'khhao',
|
||||
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',
|
||||
cloudSkuId,
|
||||
cloudSkuName: String(rawValue.cloudSkuName || '').trim(),
|
||||
vnKey,
|
||||
autoBuyEnabled: rawValue.autoBuyEnabled !== false,
|
||||
minAssetReserve: normalizeNonNegativeInteger(rawValue.minAssetReserve, 0),
|
||||
autoReturnNumberAfterDispatch: rawValue.autoReturnNumberAfterDispatch === true,
|
||||
autoConsumeAfterDispatch: rawValue.autoConsumeAfterDispatch === true,
|
||||
kuaishouConsumeShopId: String(rawValue.kuaishouConsumeShopId || '').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]'
|
||||
}
|
||||
Reference in New Issue
Block a user