feat(M09-D3): 完成商品寄存与安全取出闭环

This commit is contained in:
Codex
2026-08-11 07:39:46 +08:00
parent 1a3ea7bdf0
commit 60264cbd11
28 changed files with 2735 additions and 72 deletions
@@ -0,0 +1,79 @@
import assert from 'node:assert/strict';
import {
ProductStorageError,
ProductStorageService,
productStorageCredentialDigest,
resolveProductStorageRetrieval
} from '../dist/products/product-storage-service.js';
const credential = 'claim_credential_abcdefghijklmnopqrstuvwxyz012345';
const digest = productStorageCredentialDigest(credential);
assert.match(digest, /^[0-9a-f]{64}$/);
assert.equal(digest.includes(credential), false);
assert.equal(productStorageCredentialDigest(credential), digest);
assert.notEqual(productStorageCredentialDigest(`${credential}x`), digest);
assert.deepEqual(resolveProductStorageRetrieval('STORED', 5, 2), {
remainingQuantity: 3, status: 'PARTIALLY_RETRIEVED'
});
assert.deepEqual(resolveProductStorageRetrieval('PARTIALLY_RETRIEVED', 3, 3), {
remainingQuantity: 0, status: 'RETRIEVED'
});
for (const [status, quantity] of [['RETRIEVED', 1], ['EXPIRED', 1], ['CANCELLED', 1]]) {
assert.throws(
() => resolveProductStorageRetrieval(status, 1, quantity),
(error) => error instanceof ProductStorageError
&& error.code === 'PRODUCT_STORAGE_NOT_ACTIVE'
);
}
assert.throws(
() => resolveProductStorageRetrieval('STORED', 2, 3),
(error) => error instanceof ProductStorageError
&& error.code === 'PRODUCT_STORAGE_QUANTITY_EXCEEDED'
);
const manager = {
tenantId: '7', userId: '31',
access: {
roles: ['STORE_ADMIN'], capabilities: ['goods.storage.read', 'goods.storage.manage'],
storeIds: ['11']
},
source: 'MANAGEMENT', traceId: 'm09d3-storage-service',
ip: '127.0.0.1', userAgent: 'storage-service-test'
};
const noSqlPool = {
async execute() { throw new Error('SQL must not run for rejected input'); },
async getConnection() { throw new Error('transaction must not start for rejected input'); }
};
const service = new ProductStorageService(noSqlPool, {
now: () => new Date('2026-08-11T07:00:00.000Z'),
credentialFactory: () => credential
});
await assert.rejects(
() => service.createManual(manager, {
requestId: 'storage-create-duplicate', storeId: '11', memberId: '21',
expiresAt: new Date('2026-08-12T07:00:00.000Z'),
items: [{ skuId: '5', quantity: 1 }, { skuId: '5', quantity: 1 }]
}),
(error) => error instanceof ProductStorageError
&& error.code === 'PRODUCT_STORAGE_ITEMS_INVALID'
);
await assert.rejects(
() => service.createFromOrder({ ...manager, source: 'CUSTOMER', userId: '21' }, {
requestId: 'storage-expiry-invalid', sourceOrderId: '101',
expiresAt: new Date('2026-08-11T07:00:30.000Z')
}),
(error) => error instanceof ProductStorageError
&& error.code === 'PRODUCT_STORAGE_EXPIRY_INVALID'
);
await assert.rejects(
() => service.retrieve({ ...manager, source: 'CUSTOMER', userId: '21' }, '301', {
requestId: 'storage-retrieve-invalid-credential', claimCredential: 'short',
items: [{ storageItemId: '401', quantity: 1 }]
}),
(error) => error instanceof ProductStorageError
&& error.code === 'PRODUCT_STORAGE_CREDENTIAL_INVALID'
);
console.log('PASS: M09-D3 credential hashing, retrieval state transitions and input boundaries work.');