107 lines
3.3 KiB
TypeScript
107 lines
3.3 KiB
TypeScript
import { upsertOrderFromSource } from '../order/order-service.js'
|
|
import { logIntegration } from '../../utils/logger.js'
|
|
import { parseAmountToFen } from '../../utils/money.js'
|
|
import {
|
|
buildOpen91SourceEvent,
|
|
upsertOpen91PendingOrder,
|
|
} from '../platforms/ninetyone/order-service.js'
|
|
import { notifyOpen91PendingConfig } from '../notification/domain-notifications.js'
|
|
import {
|
|
assertOpen91Config,
|
|
OPEN_91_COST_EXCEED_FAIL_CODE,
|
|
OPEN_91_DEFAULT_FAIL_CODE,
|
|
} from './config.js'
|
|
import {
|
|
assertOpen91CreatePayload,
|
|
assertOpen91Timestamp,
|
|
normalizeOpen91CreatePayload,
|
|
} from './payload.js'
|
|
import { assertOpen91Signature } from './crypto.js'
|
|
import {
|
|
buildOpen91OrderCost,
|
|
buildOpen91OutTradeNo,
|
|
buildOpen91SuccessResponse,
|
|
} from './response.js'
|
|
|
|
export async function createOpen91Order(payload = {}, { requestId = '' } = {}) {
|
|
const config = assertOpen91Config()
|
|
const normalized = normalizeOpen91CreatePayload(payload)
|
|
|
|
assertOpen91CreatePayload(normalized, config)
|
|
assertOpen91Timestamp(normalized.timestamp, config.timestampToleranceSeconds)
|
|
assertOpen91Signature(payload, config)
|
|
|
|
if (normalized.maxAmount) {
|
|
const maxAmountFen = parseAmountToFen(normalized.maxAmount)
|
|
if (maxAmountFen < 0) {
|
|
return buildOpen91SuccessResponse({
|
|
orderNo: normalized.orderNo,
|
|
outTradeNo: '',
|
|
orderStatus: 30,
|
|
failCode: OPEN_91_COST_EXCEED_FAIL_CODE,
|
|
failReason: '订单成本超出可接受范围',
|
|
})
|
|
}
|
|
}
|
|
|
|
const sourceEvent = buildOpen91SourceEvent(normalized, config)
|
|
const result = await upsertOrderFromSource(sourceEvent, {
|
|
sourceLabel: 'open91',
|
|
})
|
|
|
|
logIntegration('[open-91/create]', '91卡券下单已处理', {
|
|
requestId,
|
|
orderNo: normalized.orderNo,
|
|
productNo: normalized.productNo,
|
|
buyNum: normalized.buyNum,
|
|
ignored: Boolean(result.ignored),
|
|
ignoreReason: result.ignoreReason || '',
|
|
orderId: result.order?.id || null,
|
|
taskCount: Array.isArray(result.tasks) ? result.tasks.length : 0,
|
|
})
|
|
|
|
if (result.ignored) {
|
|
const pending = await upsertOpen91PendingOrder(normalized, config)
|
|
logIntegration('[open-91/create]', '91卡券订单已进入待补全队列', {
|
|
requestId,
|
|
orderNo: normalized.orderNo,
|
|
productNo: normalized.productNo,
|
|
orderId: pending.order?.id || null,
|
|
})
|
|
|
|
await notifyOpen91PendingConfig({
|
|
order: pending.order,
|
|
orderNo: normalized.orderNo,
|
|
productNo: normalized.productNo,
|
|
buyNum: normalized.buyNum,
|
|
reason: result.ignoreReason || '未命中履约配置',
|
|
})
|
|
|
|
return buildOpen91SuccessResponse({
|
|
orderNo: normalized.orderNo,
|
|
outTradeNo: buildOpen91OutTradeNo(pending.order),
|
|
orderStatus: 10,
|
|
orderCost: buildOpen91OrderCost(0),
|
|
cards: '',
|
|
})
|
|
}
|
|
|
|
if (!result.order || !Array.isArray(result.tasks) || result.tasks.length === 0) {
|
|
return buildOpen91SuccessResponse({
|
|
orderNo: normalized.orderNo,
|
|
outTradeNo: '',
|
|
orderStatus: 30,
|
|
failCode: OPEN_91_DEFAULT_FAIL_CODE,
|
|
failReason: '商品未配置或订单无法履约',
|
|
})
|
|
}
|
|
|
|
return buildOpen91SuccessResponse({
|
|
orderNo: normalized.orderNo,
|
|
outTradeNo: buildOpen91OutTradeNo(result.order),
|
|
orderStatus: 10,
|
|
orderCost: buildOpen91OrderCost(0),
|
|
cards: '',
|
|
})
|
|
}
|