点“关闭任务”,就会达到你要的效果:链接失效,预占释放。

This commit is contained in:
yml
2026-04-14 18:29:25 +08:00
parent 813c733860
commit 215f8bb710
6 changed files with 351 additions and 6 deletions
@@ -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')
})