点“关闭任务”,就会达到你要的效果:链接失效,预占释放。
This commit is contained in:
@@ -73,14 +73,17 @@ export async function upsertOrderFromWebhook(event) {
|
||||
rawPayloadJson: JSON.stringify(event.rawPayload),
|
||||
paidAt: event.paidAt,
|
||||
}
|
||||
const mergedPayload = mergeWebhookOrderState(existing, basePayload)
|
||||
|
||||
const order = existing
|
||||
? await updateOrder(existing.id, {
|
||||
...basePayload,
|
||||
...mergedPayload,
|
||||
updatedAt: now,
|
||||
})
|
||||
: await createOrder({
|
||||
...basePayload,
|
||||
...mergedPayload,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
@@ -147,3 +150,90 @@ export async function upsertOrderFromWebhook(event) {
|
||||
messageDeliveries,
|
||||
}
|
||||
}
|
||||
|
||||
const ORDER_STATUS_PRIORITY = {
|
||||
created: 0,
|
||||
paid: 1,
|
||||
closed: 2,
|
||||
refunded: 3,
|
||||
}
|
||||
|
||||
const PAY_STATUS_PRIORITY = {
|
||||
unpaid: 0,
|
||||
failed: 0,
|
||||
paid: 1,
|
||||
refunded: 2,
|
||||
}
|
||||
|
||||
export function mergeWebhookOrderState(existing, incoming) {
|
||||
const orderStatus = chooseHigherPriorityStatus(
|
||||
normalizeStateValue(existing?.order_status ?? existing?.orderStatus),
|
||||
normalizeStateValue(incoming?.orderStatus ?? incoming?.order_status),
|
||||
ORDER_STATUS_PRIORITY,
|
||||
) || normalizeStateValue(incoming?.orderStatus ?? incoming?.order_status) || 'created'
|
||||
|
||||
const payStatus = chooseHigherPriorityStatus(
|
||||
normalizeStateValue(existing?.pay_status ?? existing?.payStatus),
|
||||
normalizeStateValue(incoming?.payStatus ?? incoming?.pay_status),
|
||||
PAY_STATUS_PRIORITY,
|
||||
) || normalizeStateValue(incoming?.payStatus ?? incoming?.pay_status) || 'unpaid'
|
||||
|
||||
return {
|
||||
orderStatus,
|
||||
payStatus,
|
||||
paidAt: resolveMergedPaidAt({
|
||||
existingPaidAt: existing?.paid_at ?? existing?.paidAt ?? null,
|
||||
incomingPaidAt: incoming?.paidAt ?? incoming?.paid_at ?? null,
|
||||
payStatus,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
function chooseHigherPriorityStatus(existingValue, incomingValue, priorityMap) {
|
||||
const existingPriority = resolveStatusPriority(existingValue, priorityMap)
|
||||
const incomingPriority = resolveStatusPriority(incomingValue, priorityMap)
|
||||
|
||||
if (incomingPriority > existingPriority) {
|
||||
return incomingValue
|
||||
}
|
||||
|
||||
if (existingPriority >= incomingPriority) {
|
||||
return existingValue
|
||||
}
|
||||
|
||||
return incomingValue || existingValue
|
||||
}
|
||||
|
||||
function resolveStatusPriority(value, priorityMap) {
|
||||
return Number(priorityMap[normalizeStateValue(value)] ?? -1)
|
||||
}
|
||||
|
||||
function normalizeStateValue(value) {
|
||||
return String(value || '').trim().toLowerCase()
|
||||
}
|
||||
|
||||
function resolveMergedPaidAt({ existingPaidAt, incomingPaidAt, payStatus }) {
|
||||
if (!['paid', 'refunded'].includes(normalizeStateValue(payStatus))) {
|
||||
return null
|
||||
}
|
||||
|
||||
const existingTime = parseDateValue(existingPaidAt)
|
||||
const incomingTime = parseDateValue(incomingPaidAt)
|
||||
|
||||
if (existingTime && incomingTime) {
|
||||
return existingTime <= incomingTime ? existingPaidAt : incomingPaidAt
|
||||
}
|
||||
|
||||
return existingPaidAt || incomingPaidAt || null
|
||||
}
|
||||
|
||||
function parseDateValue(value) {
|
||||
const text = String(value || '').trim()
|
||||
|
||||
if (!text) {
|
||||
return null
|
||||
}
|
||||
|
||||
const timestamp = Date.parse(text)
|
||||
return Number.isFinite(timestamp) ? timestamp : null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import { mergeWebhookOrderState } from './order-service.js'
|
||||
|
||||
test('mergeWebhookOrderState keeps paid state when a late trade_create webhook arrives', () => {
|
||||
const merged = mergeWebhookOrderState(
|
||||
{
|
||||
order_status: 'paid',
|
||||
pay_status: 'paid',
|
||||
paid_at: '2026-04-14T10:06:10.000Z',
|
||||
},
|
||||
{
|
||||
orderStatus: 'created',
|
||||
payStatus: 'unpaid',
|
||||
paidAt: null,
|
||||
},
|
||||
)
|
||||
|
||||
assert.equal(merged.orderStatus, 'paid')
|
||||
assert.equal(merged.payStatus, 'paid')
|
||||
assert.equal(merged.paidAt, '2026-04-14T10:06:10.000Z')
|
||||
})
|
||||
|
||||
test('mergeWebhookOrderState upgrades unpaid orders when payment webhook arrives later', () => {
|
||||
const merged = mergeWebhookOrderState(
|
||||
{
|
||||
order_status: 'created',
|
||||
pay_status: 'unpaid',
|
||||
paid_at: null,
|
||||
},
|
||||
{
|
||||
orderStatus: 'paid',
|
||||
payStatus: 'paid',
|
||||
paidAt: '2026-04-14T10:06:12.000Z',
|
||||
},
|
||||
)
|
||||
|
||||
assert.equal(merged.orderStatus, 'paid')
|
||||
assert.equal(merged.payStatus, 'paid')
|
||||
assert.equal(merged.paidAt, '2026-04-14T10:06:12.000Z')
|
||||
})
|
||||
|
||||
test('mergeWebhookOrderState preserves refunded status over older paid webhook', () => {
|
||||
const merged = mergeWebhookOrderState(
|
||||
{
|
||||
order_status: 'refunded',
|
||||
pay_status: 'refunded',
|
||||
paid_at: '2026-04-14T10:06:10.000Z',
|
||||
},
|
||||
{
|
||||
orderStatus: 'paid',
|
||||
payStatus: 'paid',
|
||||
paidAt: '2026-04-14T10:06:09.000Z',
|
||||
},
|
||||
)
|
||||
|
||||
assert.equal(merged.orderStatus, 'refunded')
|
||||
assert.equal(merged.payStatus, 'refunded')
|
||||
assert.equal(merged.paidAt, '2026-04-14T10:06:09.000Z')
|
||||
})
|
||||
Reference in New Issue
Block a user