支持91商品携带店铺编号

This commit is contained in:
yml
2026-05-27 13:30:47 +08:00
parent c1f3a48634
commit 64b663a8f6
7 changed files with 173 additions and 56 deletions
@@ -184,6 +184,8 @@ test('syncDeliveryTasksForOrderWithDeps creates kuaishou cloud task from cloudte
assert.equal(context.kuaishouCloudFulfillment.binding.skuId, 28)
assert.equal(context.kuaishouCloudFulfillment.binding.skuName, '套装-浪漫天命')
assert.deepEqual(context.kuaishouCloudFulfillment.binding.cloudSourceKeys, ['account-a', 'account-b'])
assert.equal(context.kuaishouCloudFulfillment.consume.shopId, 'shop-1')
assert.equal(context.kuaishouCloudFulfillment.consume.shopName, '测试店铺')
assert.deepEqual(context.kuaishouCloudFulfillment.deliveryItems, [
{
cloudSkuId: 28,
@@ -225,7 +225,7 @@ export async function syncDeliveryTasksForOrderWithDeps(
},
consume: {
status: 'pending',
shopId: String(kuaishouConsumeConfig.shopId || kuaishouShopConfig.shopId || '').trim(),
shopId: String(kuaishouConsumeConfig.shopId || kuaishouShopConfig.shopId || order.shop_id || '').trim(),
shopName: String(kuaishouConsumeConfig.shopName || kuaishouShopConfig.kshopName || order.shop_name || '').trim(),
autoConsumeEnabled: kuaishouConsumeConfig.autoConsumeAfterDispatch === true,
consumedAt: null,
@@ -1,7 +1,10 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { buildOpen91SourceEvent } from './order-service.js'
import {
buildOpen91SourceEvent,
parseOpen91ProductNo,
} from './order-service.js'
test('buildOpen91SourceEvent maps 91 productNo into source item identities', () => {
const event = buildOpen91SourceEvent({
@@ -29,3 +32,39 @@ test('buildOpen91SourceEvent maps 91 productNo into source item identities', ()
assert.equal(event.items[0].quantity, 2)
assert.equal(event.items[0].snapshot.productNo, 'KS-CLOUD-SKU-001')
})
test('parseOpen91ProductNo splits product name and kuaishou shop id by four dashes', () => {
assert.deepEqual(
parseOpen91ProductNo('测试-关联商品1----3676797936'),
{
rawProductNo: '测试-关联商品1----3676797936',
productName: '测试-关联商品1',
shopId: '3676797936',
},
)
})
test('buildOpen91SourceEvent uses productNo suffix as order shop id', () => {
const event = buildOpen91SourceEvent({
orderNo: 'P91KS202605130002',
productNo: '测试-关联商品1----3676797936',
buyNum: 1,
maxAmount: '0.01',
timestamp: 1778670308,
version: '1.0',
sign: 'SIGN',
}, {
shopId: '91kaquan',
shopName: '91卡券',
})
assert.equal(event.shopId, '3676797936')
assert.equal(event.items[0].externalItemId, '测试-关联商品1----3676797936')
assert.equal(event.items[0].externalSkuCode, '测试-关联商品1----3676797936')
assert.equal(event.items[0].externalSkuName, '测试-关联商品1')
assert.equal(event.items[0].skuCode, '测试-关联商品1')
assert.equal(event.items[0].skuName, '测试-关联商品1')
assert.equal(event.items[0].snapshot.productNo, '测试-关联商品1----3676797936')
assert.equal(event.items[0].snapshot.productName, '测试-关联商品1')
assert.equal(event.items[0].snapshot.shopId, '3676797936')
})
@@ -12,6 +12,7 @@ import { buildOpen91OutTradeNo } from '../../open-91/response.js'
import { createHttpError } from '../../../utils/http.js'
import { parseAmountToFen } from '../../../utils/money.js'
import { nowIso } from '../../../utils/time.js'
import { findKuaishouEticketShopConfig } from '../kuaishou-eticket/source-config-service.js'
import type { OrderItemRow, OrderRow } from '../../../types/repository/rows.js'
export const OPEN_91_PENDING_CONFIG_STATUS = 'pending_config'
@@ -21,14 +22,19 @@ type JsonObject = Record<string, any>
export function buildOpen91SourceEvent(payload: JsonObject = {}, config: JsonObject = {}) {
const normalized = normalizeOpen91CreatePayload(payload)
const productNo = normalized.productNo
const productInfo = parseOpen91ProductNo(normalized.productNo)
const productNo = productInfo.rawProductNo
const productName = productInfo.productName
const shopId = productInfo.shopId || String(config.shopId || OPEN_91_PROVIDER).trim() || OPEN_91_PROVIDER
const shopConfig = productInfo.shopId ? findKuaishouEticketShopConfig(productInfo.shopId) : null
const shopName = String(shopConfig?.kshopName || config.shopName || '91卡券').trim() || '91卡券'
const maxAmountFen = parseAmountToFen(normalized.maxAmount)
return {
provider: OPEN_91_PROVIDER,
platform: OPEN_91_PLATFORM,
shopId: String(config.shopId || OPEN_91_PROVIDER).trim() || OPEN_91_PROVIDER,
shopName: String(config.shopName || '91卡券').trim() || '91卡券',
shopId,
shopName,
platformOrderId: normalized.orderNo,
orderStatus: 'paid',
payStatus: 'paid',
@@ -48,25 +54,29 @@ export function buildOpen91SourceEvent(payload: JsonObject = {}, config: JsonObj
itemId: productNo,
externalItemId: productNo,
externalSkuCode: productNo,
externalSkuName: productNo,
skuCode: productNo,
skuName: productNo,
externalSkuName: productName,
skuCode: productName,
skuName: productName,
quantity: normalized.buyNum,
spec: {
source: OPEN_91_PROVIDER,
orderNo: normalized.orderNo,
productNo,
productName,
shopId: productInfo.shopId,
maxAmount: normalized.maxAmount,
},
snapshot: {
source: OPEN_91_PROVIDER,
orderNo: normalized.orderNo,
productNo,
productName,
shopId: productInfo.shopId,
maxAmount: normalized.maxAmount,
maxAmountFen,
externalItemId: productNo,
externalSkuCode: productNo,
externalSkuName: productNo,
externalSkuName: productName,
callbackUrl: normalized.callbackUrl,
},
},
@@ -74,6 +84,37 @@ export function buildOpen91SourceEvent(payload: JsonObject = {}, config: JsonObj
}
}
export function parseOpen91ProductNo(value: unknown) {
const rawProductNo = String(value || '').trim()
const delimiter = '----'
const delimiterIndex = rawProductNo.lastIndexOf(delimiter)
if (delimiterIndex <= 0) {
return {
rawProductNo,
productName: rawProductNo,
shopId: '',
}
}
const productName = rawProductNo.slice(0, delimiterIndex).trim()
const shopId = rawProductNo.slice(delimiterIndex + delimiter.length).trim()
if (!productName || !shopId) {
return {
rawProductNo,
productName: rawProductNo,
shopId: '',
}
}
return {
rawProductNo,
productName,
shopId,
}
}
export async function upsertOpen91PendingOrder(payload: JsonObject = {}, config: JsonObject = {}) {
const event = buildOpen91SourceEvent(payload, config)
const now = nowIso()