fix(order): enforce versioned platform commands and submissions
This commit is contained in:
@@ -221,7 +221,7 @@ async function merchantBeforeApprovalModule() {
|
||||
|
||||
await apiStep('order-before-approval', 'submit is blocked before approval', {
|
||||
method: 'POST', path: `/api/merchant/v1/orders/first-leg/${orderId}/submit`, token: merchantToken,
|
||||
headers: { 'Idempotency-Key': newIdempotencyKey('pre-approval-submit') },
|
||||
...orderMutationCommand(await ownedOrderSnapshot('order-before-approval', 'freeze pre-approval submit version', orderId), {}, newIdempotencyKey('pre-approval-submit')),
|
||||
}, ({ json, status }) => {
|
||||
assertEqual(status, 200, 'HTTP status')
|
||||
assertEqual(String(json?.code), 'A0403', 'business code')
|
||||
@@ -1118,7 +1118,7 @@ async function orderLifecycleModule() {
|
||||
report.resources.orderIds.push(draft.json.data)
|
||||
await softApiStep('order-validation', `${testCase.name} is rejected on submit`, {
|
||||
method: 'POST', path: `/api/merchant/v1/orders/first-leg/${draft.json.data}/submit`, token: merchantToken,
|
||||
headers: { 'Idempotency-Key': newIdempotencyKey('incomplete-submit') },
|
||||
...orderMutationCommand(await ownedOrderSnapshot('order-validation', 'freeze incomplete submit version', draft.json.data), {}, newIdempotencyKey('incomplete-submit')),
|
||||
}, ({ json, status }) => {
|
||||
assertEqual(status, 200, 'HTTP status')
|
||||
assertEqual(String(json?.code), 'A0422', 'business code')
|
||||
@@ -1269,15 +1269,29 @@ async function orderLifecycleModule() {
|
||||
}, ({ json }) => ({ total: json.data?.total, orderId, status: 'DRAFT' }))
|
||||
|
||||
const submitKey = newIdempotencyKey('approved-submit')
|
||||
const submitBefore = await ownedOrderSnapshot('order-lifecycle', 'freeze submission page version', orderId)
|
||||
const submitCommand = orderMutationCommand(submitBefore, {}, submitKey)
|
||||
recordOrderMutationRequest('initial lifecycle submit', {method:'POST',path:`/api/merchant/v1/orders/first-leg/${orderId}/submit`,...submitCommand}, submitBefore)
|
||||
await apiStep('order-lifecycle', 'submit order', {
|
||||
method: 'POST', path: `/api/merchant/v1/orders/first-leg/${orderId}/submit`, token: merchantToken,
|
||||
headers: { 'Idempotency-Key': submitKey },
|
||||
...submitCommand,
|
||||
}, ({ json }) => requireSuccess(json), () => ({ orderId }))
|
||||
|
||||
const submittedBeforeReplay = await ownedOrderSnapshot('order-lifecycle', 'freeze successful submission facts', orderId)
|
||||
await apiStep('order-lifecycle', 'submit order idempotent replay', {
|
||||
method: 'POST', path: `/api/merchant/v1/orders/first-leg/${orderId}/submit`, token: merchantToken,
|
||||
headers: { 'Idempotency-Key': submitKey },
|
||||
...submitCommand,
|
||||
}, ({ json }) => requireSuccess(json), () => ({ orderId, replayed: true }))
|
||||
await ownedOrderSnapshot('order-lifecycle', 'submit replay keeps version and history unchanged', orderId, submittedBeforeReplay)
|
||||
const submitPath = `/api/merchant/v1/orders/first-leg/${orderId}/submit`
|
||||
await rejectOrderMutation('submit same key different version conflicts', orderId, {
|
||||
method: 'POST', path: submitPath, token: merchantToken, headers: submitCommand.headers,
|
||||
body: { expectedVersion: submittedBeforeReplay.order.version },
|
||||
}, ['A0409'])
|
||||
await rejectOrderMutation('submit new key cannot submit already submitted order', orderId, {
|
||||
method: 'POST', path: submitPath, token: merchantToken,
|
||||
...orderMutationCommand(submittedBeforeReplay, {}, newIdempotencyKey('new-key-submit')),
|
||||
}, ['A0409'])
|
||||
|
||||
await apiStep('order-lifecycle', 'submitted status is persisted', {
|
||||
method: 'GET', path: `/api/merchant/v1/orders/first-leg/${orderId}`, token: merchantToken,
|
||||
@@ -1392,7 +1406,7 @@ async function orderLifecycleModule() {
|
||||
}, ({ json }) => ({ orderId: cancelOrderId, rejectionCode: json.code, message: json.message }))
|
||||
await softApiStep('order-boundary', 'cancelled order cannot be submitted', {
|
||||
method: 'POST', path: `/api/merchant/v1/orders/first-leg/${cancelOrderId}/submit`, token: merchantToken,
|
||||
headers: { 'Idempotency-Key': newIdempotencyKey('cancelled-submit') },
|
||||
...orderMutationCommand(await ownedOrderSnapshot('order-boundary', 'freeze cancelled submit version', cancelOrderId), {}, newIdempotencyKey('cancelled-submit')),
|
||||
}, ({ json, status }) => {
|
||||
assertEqual(status, 200, 'HTTP status')
|
||||
assertEqual(String(json?.code), 'A0409', 'business code')
|
||||
@@ -2290,7 +2304,8 @@ async function orderMutationEvidenceModule() {
|
||||
...orderMutationCommand(cancelled, { reason }, newIdempotencyKey('new-key-repeat-cancel')),
|
||||
}, ['A0409'])
|
||||
await rejectOrderMutation('cancelled draft cannot be submitted', id, {
|
||||
method: 'POST', path: `${base}/${id}/submit`, token: merchantToken, headers: { 'Idempotency-Key': newIdempotencyKey('cancelled-submit-proof') },
|
||||
method: 'POST', path: `${base}/${id}/submit`, token: merchantToken,
|
||||
...orderMutationCommand(cancelled, {}, newIdempotencyKey('cancelled-submit-proof')),
|
||||
}, ['A0409'])
|
||||
report.orderMutationLimitations = [
|
||||
'Requires deployed Merchant edit/cancel versioned idempotent protocol; local contracts do not prove TEST deployment.',
|
||||
|
||||
Reference in New Issue
Block a user