快手发码数据接入发单平台工单侧
- 新增 sync-work-orders-from-send-code 服务:91 先到则回填 shopId/补建工单/凭证回填 material_json;91 未到则兜底建单建工单 - order-service 与 ninetyone order-service 改用 findLatestOrderByPlatformOrderId,放宽 shopId 查重避免重复建单 - work-order-repo 新增 listWorkOrdersByPlatformOrderId 供兜底查重 - send-code-service 挂接同步逻辑并吞错,不影响发码主流程 - ProductRulesPanel 新增店铺列 - .gitignore 忽略 send_code/ 与 .reasonix/
This commit is contained in:
@@ -28,3 +28,5 @@ apps/backend/data/logs
|
|||||||
.ace-tool
|
.ace-tool
|
||||||
.claude
|
.claude
|
||||||
.snow
|
.snow
|
||||||
|
send_code/
|
||||||
|
.reasonix/
|
||||||
|
|||||||
@@ -568,6 +568,18 @@ export async function listPendingMaterialWorkOrdersByPlatformOrderId(
|
|||||||
return result.rows
|
return result.rows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function listWorkOrdersByPlatformOrderId(
|
||||||
|
platformOrderId: string,
|
||||||
|
): Promise<WorkOrderRow[]> {
|
||||||
|
const result = await query<WorkOrderRow>(
|
||||||
|
`${WORK_ORDER_SELECT}
|
||||||
|
WHERE wo.platform_order_id = $1
|
||||||
|
ORDER BY wo.id ASC`,
|
||||||
|
[String(platformOrderId || '').trim()],
|
||||||
|
)
|
||||||
|
return result.rows
|
||||||
|
}
|
||||||
|
|
||||||
export async function listWorkOrders({
|
export async function listWorkOrders({
|
||||||
page = 1,
|
page = 1,
|
||||||
pageSize = 20,
|
pageSize = 20,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
createOrder,
|
createOrder,
|
||||||
findOrderByPlatformOrderId,
|
findLatestOrderByPlatformOrderId,
|
||||||
updateOrder,
|
updateOrder,
|
||||||
} from '../../repositories/order-repo.js'
|
} from '../../repositories/order-repo.js'
|
||||||
import { replaceOrderItems } from '../../repositories/order-item-repo.js'
|
import { replaceOrderItems } from '../../repositories/order-item-repo.js'
|
||||||
@@ -94,10 +94,9 @@ export async function upsertOrderFromSource(
|
|||||||
{ sourceLabel = 'source' }: UpsertOrderSourceOptions = {},
|
{ sourceLabel = 'source' }: UpsertOrderSourceOptions = {},
|
||||||
): Promise<UpsertOrderResult> {
|
): Promise<UpsertOrderResult> {
|
||||||
const now = nowIso()
|
const now = nowIso()
|
||||||
const existing = await findOrderByPlatformOrderId({
|
const existing = await findLatestOrderByPlatformOrderId({
|
||||||
provider: event.provider,
|
provider: event.provider,
|
||||||
platform: event.platform,
|
platform: event.platform,
|
||||||
shopId: event.shopId,
|
|
||||||
platformOrderId: event.platformOrderId,
|
platformOrderId: event.platformOrderId,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -146,8 +145,8 @@ export async function upsertOrderFromSource(
|
|||||||
const basePayload = {
|
const basePayload = {
|
||||||
provider: event.provider,
|
provider: event.provider,
|
||||||
platform: event.platform,
|
platform: event.platform,
|
||||||
shopId: event.shopId,
|
shopId: String(existing?.shop_id || event.shopId || '').trim(),
|
||||||
shopName: event.shopName,
|
shopName: String(existing?.shop_name || event.shopName || '').trim(),
|
||||||
platformOrderId: event.platformOrderId,
|
platformOrderId: event.platformOrderId,
|
||||||
orderStatus: event.orderStatus,
|
orderStatus: event.orderStatus,
|
||||||
payStatus: event.payStatus,
|
payStatus: event.payStatus,
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ import {
|
|||||||
} from '../../../repositories/kuaishou-industry-voucher-repo.js'
|
} from '../../../repositories/kuaishou-industry-voucher-repo.js'
|
||||||
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER } from '../../open-91/config.js'
|
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER } from '../../open-91/config.js'
|
||||||
import { retryOpen91Order } from '../ninetyone/order-service.js'
|
import { retryOpen91Order } from '../ninetyone/order-service.js'
|
||||||
|
import { syncWorkOrdersFromKuaishouSendCode } from '../../worker-platform/sync-work-orders-from-send-code.js'
|
||||||
import { normalizeTimestampIso } from '../../../utils/time.js'
|
import { normalizeTimestampIso } from '../../../utils/time.js'
|
||||||
import { logIntegration } from '../../../utils/logger.js'
|
import { logWarn, logIntegration } from '../../../utils/logger.js'
|
||||||
import {
|
import {
|
||||||
getKuaishouIndustryConfig,
|
getKuaishouIndustryConfig,
|
||||||
assertMatchingAppKey,
|
assertMatchingAppKey,
|
||||||
@@ -119,6 +120,24 @@ export async function handleSendCode(rawBody: JsonObject = {}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await syncWorkOrdersFromKuaishouSendCode({
|
||||||
|
oid: normalizedOid,
|
||||||
|
sellerId: params.sellerId,
|
||||||
|
itemId: params.itemId,
|
||||||
|
itemTitle: params.itemTitle,
|
||||||
|
skuId: params.skuId,
|
||||||
|
num: params.num,
|
||||||
|
paymentFen: resolveSendCodePaymentFen(params.ext),
|
||||||
|
rawParams: params,
|
||||||
|
vouchers,
|
||||||
|
now,
|
||||||
|
}).catch((error) => {
|
||||||
|
logWarn('[kuaishou-industry/send-code]', '发单平台工单同步失败,不影响发码主流程', {
|
||||||
|
oid: normalizedOid,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
scheduleKuaishouIndustrySendCallbackRetry(normalizedOid, SEND_CALLBACK_INITIAL_DELAY_MS, {
|
scheduleKuaishouIndustrySendCallbackRetry(normalizedOid, SEND_CALLBACK_INITIAL_DELAY_MS, {
|
||||||
source: 'send_code_accepted',
|
source: 'send_code_accepted',
|
||||||
})
|
})
|
||||||
@@ -671,6 +690,17 @@ function normalizePositiveInteger(value: unknown): number {
|
|||||||
return Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : 0
|
return Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveSendCodePaymentFen(ext: unknown): number {
|
||||||
|
const parsed = parseJsonObject(ext)
|
||||||
|
return normalizePositiveInteger(
|
||||||
|
parsed.payment
|
||||||
|
?? parsed.totalGoodsValue
|
||||||
|
?? parsed.goodsValue
|
||||||
|
?? parsed.payAmount
|
||||||
|
?? parsed.amount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function parseJsonObject(value: unknown): JsonObject {
|
function parseJsonObject(value: unknown): JsonObject {
|
||||||
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||||
return value as JsonObject
|
return value as JsonObject
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { query } from '../../../db/client.js'
|
import { query } from '../../../db/client.js'
|
||||||
import {
|
import {
|
||||||
createOrder,
|
createOrder,
|
||||||
findOrderByPlatformOrderId,
|
findLatestOrderByPlatformOrderId,
|
||||||
getOrderById,
|
getOrderById,
|
||||||
updateOrder,
|
updateOrder,
|
||||||
} from '../../../repositories/order-repo.js'
|
} from '../../../repositories/order-repo.js'
|
||||||
@@ -122,10 +122,9 @@ export function parseOpen91ProductNo(value: unknown) {
|
|||||||
export async function upsertOpen91PendingOrder(payload: JsonObject = {}, config: JsonObject = {}) {
|
export async function upsertOpen91PendingOrder(payload: JsonObject = {}, config: JsonObject = {}) {
|
||||||
const event = buildOpen91SourceEvent(payload, config)
|
const event = buildOpen91SourceEvent(payload, config)
|
||||||
const now = nowIso()
|
const now = nowIso()
|
||||||
const existing = await findOrderByPlatformOrderId({
|
const existing = await findLatestOrderByPlatformOrderId({
|
||||||
provider: event.provider,
|
provider: event.provider,
|
||||||
platform: event.platform,
|
platform: event.platform,
|
||||||
shopId: event.shopId,
|
|
||||||
platformOrderId: event.platformOrderId,
|
platformOrderId: event.platformOrderId,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -137,8 +136,8 @@ export async function upsertOpen91PendingOrder(payload: JsonObject = {}, config:
|
|||||||
const orderPayload = {
|
const orderPayload = {
|
||||||
provider: event.provider,
|
provider: event.provider,
|
||||||
platform: event.platform,
|
platform: event.platform,
|
||||||
shopId: event.shopId,
|
shopId: String(existing?.shop_id || event.shopId || '').trim(),
|
||||||
shopName: event.shopName,
|
shopName: String(existing?.shop_name || event.shopName || '').trim(),
|
||||||
platformOrderId: event.platformOrderId,
|
platformOrderId: event.platformOrderId,
|
||||||
orderStatus: OPEN_91_PENDING_CONFIG_STATUS,
|
orderStatus: OPEN_91_PENDING_CONFIG_STATUS,
|
||||||
payStatus: 'paid',
|
payStatus: 'paid',
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
/**
|
||||||
|
* 快手 send-code 数据接入发单平台(工单侧)。
|
||||||
|
*
|
||||||
|
* 定位:91 回调是订单骨架权威源,快手 send-code 是数据补全源与兜底源。
|
||||||
|
* - 订单已存在(91 先到):回填 shop_id(91 的 productNo 无店铺后缀时)、
|
||||||
|
* 补建缺失工单、把凭证信息回填已建工单 material_json
|
||||||
|
* - 订单不存在(91 未到/缺失):用快手数据兜底建单 + 建工单 + 凭证回填
|
||||||
|
*
|
||||||
|
* 幂等依据:orders 唯一键 provider+platform+shop_id+platform_order_id
|
||||||
|
* (由 91 侧查重逻辑保证同 oid 单条记录)、work_orders.order_item_id 唯一索引、
|
||||||
|
* listWorkOrdersByPlatformOrderId 查重。
|
||||||
|
*
|
||||||
|
* 本服务只写 orders / order_items / work_orders,不触碰
|
||||||
|
* upsertOrderFromSource / syncDeliveryTasksForOrder / readiness / 回调链路。
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
createOrder,
|
||||||
|
findLatestOrderByPlatformOrderId,
|
||||||
|
updateOrder,
|
||||||
|
} from '../../repositories/order-repo.js'
|
||||||
|
import { listOrderItemsByOrderId, replaceOrderItems } from '../../repositories/order-item-repo.js'
|
||||||
|
import {
|
||||||
|
listWorkOrdersByPlatformOrderId,
|
||||||
|
updateWorkOrder,
|
||||||
|
} from '../../repositories/worker-platform/work-order-repo.js'
|
||||||
|
import { syncWorkerOrdersForSourceOrder } from './admin-service.js'
|
||||||
|
import { createWorkOrderEvent } from '../../repositories/worker-platform/work-order-repo.js'
|
||||||
|
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER } from '../open-91/config.js'
|
||||||
|
import { asJsonObject, type JsonObject } from '../../types/json.js'
|
||||||
|
import type { OrderUpdateInput } from '../../types/repository/inputs.js'
|
||||||
|
import type {
|
||||||
|
KuaishouIndustryVoucherRow,
|
||||||
|
OrderRow,
|
||||||
|
} from '../../types/repository/rows.js'
|
||||||
|
|
||||||
|
const KUAISHOU_SEND_CODE_SOURCE = 'kuaishou_send_code'
|
||||||
|
const KUAISHOU_SEND_CODE_ORDER_STATUS = 'paid'
|
||||||
|
|
||||||
|
export type SyncWorkOrdersFromSendCodeInput = {
|
||||||
|
oid: string
|
||||||
|
sellerId: string
|
||||||
|
itemId: string
|
||||||
|
itemTitle: string
|
||||||
|
skuId: string
|
||||||
|
num: number
|
||||||
|
paymentFen: number
|
||||||
|
rawParams: JsonObject
|
||||||
|
vouchers: KuaishouIndustryVoucherRow[]
|
||||||
|
now: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SyncWorkOrdersFromSendCodeResult = {
|
||||||
|
order: OrderRow | null
|
||||||
|
orderId: number | null
|
||||||
|
workOrderIds: number[]
|
||||||
|
createdWorkOrderCount: number
|
||||||
|
backfilledVoucherCount: number
|
||||||
|
skipped: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function syncWorkOrdersFromKuaishouSendCode(
|
||||||
|
input: SyncWorkOrdersFromSendCodeInput,
|
||||||
|
): Promise<SyncWorkOrdersFromSendCodeResult> {
|
||||||
|
const normalizedOid = String(input.oid || '').trim()
|
||||||
|
const skipped: string[] = []
|
||||||
|
|
||||||
|
if (!normalizedOid) {
|
||||||
|
return {
|
||||||
|
order: null,
|
||||||
|
orderId: null,
|
||||||
|
workOrderIds: [],
|
||||||
|
createdWorkOrderCount: 0,
|
||||||
|
backfilledVoucherCount: 0,
|
||||||
|
skipped: ['missing_oid'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let order = await findLatestOrderByPlatformOrderId({
|
||||||
|
provider: OPEN_91_PROVIDER,
|
||||||
|
platform: OPEN_91_PLATFORM,
|
||||||
|
platformOrderId: normalizedOid,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (order) {
|
||||||
|
const orderResult = await backfillOrderShopId(order, input)
|
||||||
|
order = orderResult.order
|
||||||
|
if (orderResult.skipped) {
|
||||||
|
skipped.push(orderResult.skipped)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const created = await createFallbackOrder(input)
|
||||||
|
if (created.order) {
|
||||||
|
order = created.order
|
||||||
|
} else {
|
||||||
|
skipped.push(created.reason || 'order_create_failed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const workOrderIds: number[] = []
|
||||||
|
let createdWorkOrderCount = 0
|
||||||
|
|
||||||
|
if (order) {
|
||||||
|
const orderItems = await listOrderItemsByOrderId(order.id)
|
||||||
|
|
||||||
|
const syncResult = await syncWorkerOrdersForSourceOrder(order, orderItems, {
|
||||||
|
source: KUAISHOU_SEND_CODE_SOURCE,
|
||||||
|
autoOnly: true,
|
||||||
|
})
|
||||||
|
createdWorkOrderCount = syncResult.createdCount
|
||||||
|
for (const item of syncResult.skipped) {
|
||||||
|
skipped.push(`work_order:${item.reason}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const backfilled = await backfillVouchersToWorkOrders(normalizedOid, input.vouchers, input.now)
|
||||||
|
for (const workOrderId of backfilled.workOrderIds) {
|
||||||
|
workOrderIds.push(workOrderId)
|
||||||
|
}
|
||||||
|
if (backfilled.skipped) {
|
||||||
|
skipped.push(backfilled.skipped)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
order,
|
||||||
|
orderId: order?.id ?? null,
|
||||||
|
workOrderIds,
|
||||||
|
createdWorkOrderCount,
|
||||||
|
backfilledVoucherCount: backfilled.count,
|
||||||
|
skipped,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function backfillOrderShopId(
|
||||||
|
order: OrderRow,
|
||||||
|
input: SyncWorkOrdersFromSendCodeInput,
|
||||||
|
): Promise<{ order: OrderRow; skipped?: string }> {
|
||||||
|
const sellerId = String(input.sellerId || '').trim()
|
||||||
|
const currentShopId = String(order.shop_id || '').trim()
|
||||||
|
|
||||||
|
if (!sellerId || currentShopId === sellerId) {
|
||||||
|
return { order }
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPlaceholderShopId = !currentShopId || currentShopId === OPEN_91_PROVIDER
|
||||||
|
|
||||||
|
if (!isPlaceholderShopId) {
|
||||||
|
return { order, skipped: `shop_id_conflict:${currentShopId}` }
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = await updateOrder(order.id, {
|
||||||
|
...buildOrderUpdateBase(order),
|
||||||
|
shopId: sellerId,
|
||||||
|
updatedAt: input.now,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
order: updated || order,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildOrderUpdateBase(order: OrderRow): Omit<OrderUpdateInput, 'updatedAt'> {
|
||||||
|
return {
|
||||||
|
provider: String(order.provider || ''),
|
||||||
|
platform: String(order.platform || ''),
|
||||||
|
shopId: String(order.shop_id || ''),
|
||||||
|
shopName: String(order.shop_name || ''),
|
||||||
|
platformOrderId: String(order.platform_order_id || ''),
|
||||||
|
orderStatus: String(order.order_status || ''),
|
||||||
|
payStatus: String(order.pay_status || ''),
|
||||||
|
buyerId: String(order.buyer_id || ''),
|
||||||
|
buyerName: String(order.buyer_name || ''),
|
||||||
|
receiverContact: String(order.receiver_contact || ''),
|
||||||
|
totalAmount: Number(order.total_amount) || 0,
|
||||||
|
currency: String(order.currency || 'CNY'),
|
||||||
|
rawPayloadJson: order.raw_payload_json || '{}',
|
||||||
|
paidAt: order.paid_at || null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createFallbackOrder(input: SyncWorkOrdersFromSendCodeInput): Promise<{
|
||||||
|
order: OrderRow | null
|
||||||
|
reason?: string
|
||||||
|
}> {
|
||||||
|
const now = input.now
|
||||||
|
const sellerId = String(input.sellerId || '').trim()
|
||||||
|
const itemId = String(input.itemId || '').trim()
|
||||||
|
const itemTitle = String(input.itemTitle || '').trim()
|
||||||
|
const num = Math.max(1, Number(input.num) || 1)
|
||||||
|
const paymentFen = Math.max(0, Number(input.paymentFen) || 0)
|
||||||
|
|
||||||
|
if (!itemId && !itemTitle) {
|
||||||
|
return { order: null, reason: 'order_item_missing' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = await createOrder({
|
||||||
|
provider: OPEN_91_PROVIDER,
|
||||||
|
platform: OPEN_91_PLATFORM,
|
||||||
|
shopId: sellerId,
|
||||||
|
shopName: sellerId ? `快手店铺-${sellerId}` : '',
|
||||||
|
platformOrderId: input.oid,
|
||||||
|
orderStatus: KUAISHOU_SEND_CODE_ORDER_STATUS,
|
||||||
|
payStatus: 'paid',
|
||||||
|
buyerId: '',
|
||||||
|
buyerName: '',
|
||||||
|
receiverContact: '',
|
||||||
|
totalAmount: paymentFen,
|
||||||
|
currency: 'CNY',
|
||||||
|
rawPayloadJson: {
|
||||||
|
source: KUAISHOU_SEND_CODE_SOURCE,
|
||||||
|
receivedAt: now,
|
||||||
|
body: input.rawParams,
|
||||||
|
},
|
||||||
|
paidAt: now,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!order) {
|
||||||
|
return { order: null, reason: 'order_create_failed' }
|
||||||
|
}
|
||||||
|
|
||||||
|
await replaceOrderItems(order.id, [
|
||||||
|
{
|
||||||
|
skuCode: itemId,
|
||||||
|
skuName: itemTitle,
|
||||||
|
quantity: num,
|
||||||
|
specJson: JSON.stringify({
|
||||||
|
sellerId,
|
||||||
|
skuId: String(input.skuId || '').trim(),
|
||||||
|
paymentFen,
|
||||||
|
source: KUAISHOU_SEND_CODE_SOURCE,
|
||||||
|
}),
|
||||||
|
itemSnapshotJson: JSON.stringify({
|
||||||
|
source: KUAISHOU_SEND_CODE_SOURCE,
|
||||||
|
params: input.rawParams,
|
||||||
|
}),
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
return { order }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function backfillVouchersToWorkOrders(
|
||||||
|
oid: string,
|
||||||
|
vouchers: KuaishouIndustryVoucherRow[],
|
||||||
|
now: string,
|
||||||
|
): Promise<{ workOrderIds: number[]; count: number; skipped?: string }> {
|
||||||
|
const workOrders = await listWorkOrdersByPlatformOrderId(oid)
|
||||||
|
if (workOrders.length === 0) {
|
||||||
|
return { workOrderIds: [], count: 0, skipped: 'work_order_not_found' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const voucherItems = vouchers.map((voucher) => ({
|
||||||
|
voucherCode: String(voucher.voucher_code || ''),
|
||||||
|
token: String(voucher.token || ''),
|
||||||
|
eticketType: String(voucher.eticket_type || ''),
|
||||||
|
status: String(voucher.status || ''),
|
||||||
|
validStartTime: Number(voucher.valid_start_time) || 0,
|
||||||
|
validEndTime: Number(voucher.valid_end_time) || 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const workOrderIds: number[] = []
|
||||||
|
let count = 0
|
||||||
|
|
||||||
|
for (const workOrder of workOrders) {
|
||||||
|
const material = asJsonObject(safeParseJson(workOrder.material_json))
|
||||||
|
const existing = Array.isArray(material.kuaishouIndustryVoucher)
|
||||||
|
? (material.kuaishouIndustryVoucher as unknown[])
|
||||||
|
: []
|
||||||
|
const existingCodes = new Set(
|
||||||
|
existing.map((item) =>
|
||||||
|
String((item as JsonObject)?.voucherCode || (item as JsonObject)?.code || ''),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
const merged = [
|
||||||
|
...existing,
|
||||||
|
...voucherItems.filter((item) => !existingCodes.has(item.voucherCode)),
|
||||||
|
]
|
||||||
|
|
||||||
|
material.kuaishouIndustryVoucher = merged
|
||||||
|
|
||||||
|
const updated = await updateWorkOrder(workOrder.id, {
|
||||||
|
material_json: JSON.stringify(material),
|
||||||
|
updated_at: now,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!updated) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
await createWorkOrderEvent({
|
||||||
|
workOrderId: workOrder.id,
|
||||||
|
actorType: 'system',
|
||||||
|
actorId: KUAISHOU_SEND_CODE_SOURCE,
|
||||||
|
eventType: 'voucher_backfilled',
|
||||||
|
fromStatus: workOrder.status,
|
||||||
|
toStatus: workOrder.status,
|
||||||
|
payloadJson: JSON.stringify({
|
||||||
|
oid,
|
||||||
|
voucherCount: voucherItems.length,
|
||||||
|
}),
|
||||||
|
now,
|
||||||
|
})
|
||||||
|
|
||||||
|
workOrderIds.push(Number(workOrder.id))
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return { workOrderIds, count }
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeParseJson(value: unknown): JsonObject {
|
||||||
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||||
|
return value as JsonObject
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(String(value || '{}'))
|
||||||
|
return asJsonObject(parsed)
|
||||||
|
} catch {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -173,6 +173,18 @@ export default function ProductRulesPanel() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '店铺',
|
||||||
|
width: 120,
|
||||||
|
render: (_, row) => {
|
||||||
|
const shopId = String(row.shopId || '')
|
||||||
|
return shopId ? (
|
||||||
|
<Tag color="geekblue">{shopId}</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag>通配</Tag>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'SKU',
|
title: 'SKU',
|
||||||
dataIndex: 'skuCode',
|
dataIndex: 'skuCode',
|
||||||
|
|||||||
Reference in New Issue
Block a user