Compare commits
9 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
| e949af26b8 | |||
| 1b50c99f36 | |||
| 188cea82c5 | |||
| 1a8f436170 | |||
| 78bb14ff40 | |||
| f8f063e946 | |||
| 7293a9c0fb | |||
| cabd505ff7 | |||
| 57974aeabd |
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"moduleCode": "order",
|
||||
"candidateVersion": "1.0.10-rc.10",
|
||||
"buildRevision": 10,
|
||||
"buildChecksum": "e66f8fffeaaac05d20c00a1367159d84e64de97231f528d493789a369f3ef9f5",
|
||||
"schemaInputChecksum": "9811550dfb225cd89362118cd649590d3d52f9388456aaf5aee082c2399bfc5b",
|
||||
"branchName": "release/1.0.10-rc.10"
|
||||
"candidateVersion": "1.0.0-rc.1",
|
||||
"buildRevision": 1,
|
||||
"buildChecksum": "5cf032fdac2b0403fbcad8b44b326a29141ba556bbbb9710ac9329b5d7c031dd",
|
||||
"schemaInputChecksum": "1b3eec01e5b04880166e20e8e6df70b79f227129ea9165e38cfbb925be3c2d23",
|
||||
"branchName": "release/1.0.0-rc.1"
|
||||
}
|
||||
|
||||
5
bootstrap.js
vendored
5
bootstrap.js
vendored
@@ -11,11 +11,10 @@ function loadGeneratedSaasModule() {
|
||||
return require('./dist/saas/generated').GeneratedSaasModule;
|
||||
}
|
||||
|
||||
async function start(options = {}) {
|
||||
const session = await prepareSaasServiceHost({
|
||||
async function start() {
|
||||
await prepareSaasServiceHost({
|
||||
generated: loadGeneratedSaasModule(),
|
||||
});
|
||||
if (options.verifySession) await options.verifySession(session);
|
||||
requireExactReleaseEnvironment();
|
||||
return Bootstrap.configure({
|
||||
baseDir: path.join(__dirname, 'dist'),
|
||||
|
||||
12
package.json
12
package.json
@@ -10,19 +10,17 @@
|
||||
"build": "rimraf dist && mwtsc --cleanOutDir",
|
||||
"publish": "cool saas-model finalize",
|
||||
"start": "node bootstrap.js",
|
||||
"start:stable": "node start-stable.js",
|
||||
"test:stable": "node --test test/start-stable.test.cjs",
|
||||
"test:business": "node --test test/orders-business-outcome.test.cjs",
|
||||
"start:local": "cross-env NODE_ENV=local SAAS_RUNTIME_BOOTSTRAP_LOCAL_FALLBACK_ENABLED=true node bootstrap.js",
|
||||
"verify:packages": "node scripts/verify-local-packages.cjs",
|
||||
"start:frozen": "node start-frozen.js"
|
||||
"start:frozen": "node start-frozen.js",
|
||||
"start:stable": "node start-stable.js",
|
||||
"test:stable": "node --test test/start-stable.test.cjs"
|
||||
},
|
||||
"coolSaas": {
|
||||
"lifecycle": {
|
||||
"dev": "pnpm run build && pnpm run start:local",
|
||||
"test": "pnpm run typecheck && pnpm run test:stable && pnpm run test:business",
|
||||
"build": "pnpm run build",
|
||||
"artifactDir": "dist"
|
||||
"test": "pnpm run typecheck",
|
||||
"build": "pnpm run build"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -12,7 +12,6 @@ export type OrdersAddInput = {
|
||||
goods_id: string;
|
||||
order_no: string;
|
||||
quantity: number;
|
||||
remark?: string | null;
|
||||
status?: string;
|
||||
unit_price: string;
|
||||
};
|
||||
@@ -23,7 +22,6 @@ export type OrdersAddOutput = {
|
||||
id: string;
|
||||
order_no: string;
|
||||
quantity: number;
|
||||
remark?: string | null;
|
||||
status: string;
|
||||
unit_price: string;
|
||||
};
|
||||
@@ -78,7 +76,6 @@ export type OrdersInfoOutput = {
|
||||
id: string;
|
||||
order_no: string;
|
||||
quantity: number;
|
||||
remark?: string | null;
|
||||
status: string;
|
||||
unit_price: string;
|
||||
};
|
||||
@@ -101,16 +98,15 @@ export type OrdersListInput = {
|
||||
};
|
||||
};
|
||||
|
||||
export type OrdersListOutput = ({
|
||||
export type OrdersListOutput = {
|
||||
amount: string;
|
||||
goods_id: string;
|
||||
id: string;
|
||||
order_no: string;
|
||||
quantity: number;
|
||||
remark?: string | null;
|
||||
status: string;
|
||||
unit_price: string;
|
||||
})[];
|
||||
}[];
|
||||
|
||||
export type OrdersPageInput = {
|
||||
keyword?: string;
|
||||
@@ -132,16 +128,15 @@ export type OrdersPageInput = {
|
||||
};
|
||||
|
||||
export type OrdersPageOutput = {
|
||||
list: ({
|
||||
list: {
|
||||
amount: string;
|
||||
goods_id: string;
|
||||
id: string;
|
||||
order_no: string;
|
||||
quantity: number;
|
||||
remark?: string | null;
|
||||
status: string;
|
||||
unit_price: string;
|
||||
})[];
|
||||
}[];
|
||||
pagination: {
|
||||
page: number;
|
||||
size: number;
|
||||
@@ -155,7 +150,6 @@ export type OrdersUpdateInput = {
|
||||
id: string;
|
||||
order_no?: string;
|
||||
quantity?: number;
|
||||
remark?: string | null;
|
||||
status?: string;
|
||||
unit_price?: string;
|
||||
};
|
||||
@@ -223,13 +217,6 @@ export const Actions = {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -240,7 +227,7 @@ export const Actions = {
|
||||
"amount"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "1a63df8bd8a0a663d853603eac460eb419f44131f9ca1de36c9d91925c03c95f",
|
||||
"inputChecksum": "bbaa3690f78676aeed57b00951cd36a1ae2a82c4afeb86911040fdae86da53c9",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -271,13 +258,6 @@ export const Actions = {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -290,7 +270,7 @@ export const Actions = {
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:add"
|
||||
@@ -304,7 +284,6 @@ export const Actions = {
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -641,13 +620,6 @@ export const Actions = {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -660,7 +632,7 @@ export const Actions = {
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:info"
|
||||
@@ -674,7 +646,6 @@ export const Actions = {
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -804,13 +775,6 @@ export const Actions = {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -824,7 +788,7 @@ export const Actions = {
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "a02a513155bd8cbf6dc15471919a77f076e6225975e07a90285763bd3b481661",
|
||||
"outputChecksum": "040ec4e29e6999ab8ce2e1d9ebe4d4a5b1c09e805c10870401dbb273c9a8c9bc",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:list"
|
||||
@@ -838,7 +802,6 @@ export const Actions = {
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -976,13 +939,6 @@ export const Actions = {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1026,7 +982,7 @@ export const Actions = {
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "9b8f0c856c1dec532d601d56a84c8267f591ff82b89d5750df62d6104271eeb7",
|
||||
"outputChecksum": "14efb96cade110fc8fef771fb439845b0892d169d9f26f0be10127b547262877",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:page"
|
||||
@@ -1040,7 +996,6 @@ export const Actions = {
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1088,13 +1043,6 @@ export const Actions = {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1102,7 +1050,7 @@ export const Actions = {
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "acf0b47a3dd2bb4dc9f7e87399f8e0fd2300391230886283588204ba9b8c8e4c",
|
||||
"inputChecksum": "437195e38df6988a131ad09b0b7ee089108857a4795c75aba395d077255676fc",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -1130,7 +1078,6 @@ export const Actions = {
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1178,7 +1125,7 @@ export const Crud = {
|
||||
moduleCode: "order",
|
||||
tableCode: "orders",
|
||||
operations: ["add","delete","update","info","list","page"],
|
||||
descriptorChecksum: "9748697d1a60b5e0957fb58c62a8564c997397007d15a6d35b783fceee178e97",
|
||||
descriptorChecksum: "b4b4c2c624d655282f336f4758e6d057082541502dfd0099ca0f520f75d973fd",
|
||||
actions: {
|
||||
add: Actions.OrdersAdd,
|
||||
delete: Actions.OrdersDelete,
|
||||
|
||||
@@ -14,16 +14,15 @@ export interface OrdersRow extends Record<string, unknown> {
|
||||
unit_price: string;
|
||||
amount: string;
|
||||
status: string;
|
||||
remark?: string | null;
|
||||
}
|
||||
|
||||
export class Orders extends SaasTableModel<OrdersRow> {
|
||||
static readonly definition = defineSaasTableModel({
|
||||
"kind": "table",
|
||||
"moduleCode": "order",
|
||||
"revision": 10,
|
||||
"schemaVersion": 10,
|
||||
"schemaInputChecksum": "9811550dfb225cd89362118cd649590d3d52f9388456aaf5aee082c2399bfc5b",
|
||||
"revision": 1,
|
||||
"schemaVersion": 1,
|
||||
"schemaInputChecksum": "1b3eec01e5b04880166e20e8e6df70b79f227129ea9165e38cfbb925be3c2d23",
|
||||
"tableCode": "orders",
|
||||
"fields": [
|
||||
{
|
||||
@@ -95,16 +94,6 @@ export class Orders extends SaasTableModel<OrdersRow> {
|
||||
"writable": true,
|
||||
"filterable": true,
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"code": "remark",
|
||||
"type": "varchar",
|
||||
"nullable": true,
|
||||
"primary": false,
|
||||
"readable": true,
|
||||
"writable": true,
|
||||
"filterable": false,
|
||||
"sortable": false
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -4,9 +4,9 @@ import { defineGeneratedSaasModule } from '@cool-midway/module-runtime';
|
||||
export const GeneratedSaasModule = defineGeneratedSaasModule({
|
||||
"formatVersion": 2,
|
||||
"moduleCode": "order",
|
||||
"revision": 10,
|
||||
"schemaVersion": 10,
|
||||
"schemaInputChecksum": "9811550dfb225cd89362118cd649590d3d52f9388456aaf5aee082c2399bfc5b",
|
||||
"runtimeContractChecksum": "44e98417f57e308e66e32fc306b3ba5793ae1140ed0465531315380970c57e4d",
|
||||
"revision": 1,
|
||||
"schemaVersion": 1,
|
||||
"schemaInputChecksum": "1b3eec01e5b04880166e20e8e6df70b79f227129ea9165e38cfbb925be3c2d23",
|
||||
"runtimeContractChecksum": "3d025d1b634c413449eb91164fb1f859a388d8930d2de112980a606b591befce",
|
||||
"implementationManifestChecksum": "f25647d2dd90e14d6226683d2ff67ba32132b2dfdeb861015805240a96d4635b"
|
||||
});
|
||||
|
||||
@@ -83,10 +83,10 @@ export const SaasActions = {
|
||||
"actionChecksum": "3978a7ba9a3e0f91842031fd323ec63b3816eef68cb8dc82ffad6d187de8b7ea",
|
||||
"outputChecksum": "fe644424ef6a9e462b56edc9f70f48bb218783c69469469d4310de48589a0df5",
|
||||
"contractVersion": 1,
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseId": 38,
|
||||
"consumerModuleCode": "order",
|
||||
"providerModuleCode": "demo",
|
||||
"providerReleaseVersion": "1.0.10-rc.10"
|
||||
"providerReleaseVersion": "1.0.0-rc.1"
|
||||
}),
|
||||
GoodsReleaseStock: defineInjectedSaasAction<DemoGoodsReleaseStockInput, DemoGoodsReleaseStockOutput>({
|
||||
"kind": "action",
|
||||
@@ -148,10 +148,10 @@ export const SaasActions = {
|
||||
"outputChecksum": "a632b9f89518c3c17861454b74173a4880d5e8482639d3ff7f761aee4d061bd9",
|
||||
"contractVersion": 1,
|
||||
"commandEventType": "saas.workflow.demo.goods.releaseStock",
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseId": 38,
|
||||
"consumerModuleCode": "order",
|
||||
"providerModuleCode": "demo",
|
||||
"providerReleaseVersion": "1.0.10-rc.10",
|
||||
"providerReleaseVersion": "1.0.0-rc.1",
|
||||
"commandEventContractChecksum": "18a727b91cf9410c3b7ac14e3a8799dbbfa8937f84667bfe7e31e21e662396be"
|
||||
}),
|
||||
GoodsReserveStock: defineInjectedSaasAction<DemoGoodsReserveStockInput, DemoGoodsReserveStockOutput>({
|
||||
@@ -208,10 +208,10 @@ export const SaasActions = {
|
||||
"outputChecksum": "545bd8b0bf6eb8670b21497236038187ee0f1df1544a318b16a399458fcb796e",
|
||||
"contractVersion": 1,
|
||||
"commandEventType": "saas.workflow.demo.goods.reserveStock",
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseId": 38,
|
||||
"consumerModuleCode": "order",
|
||||
"providerModuleCode": "demo",
|
||||
"providerReleaseVersion": "1.0.10-rc.10",
|
||||
"providerReleaseVersion": "1.0.0-rc.1",
|
||||
"commandEventContractChecksum": "ffbecad3a3d63b8bf92fde701dfaa11c8502a2c5f9f6bbb89b755e214024c3ae"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"manifestVersion": 1,
|
||||
"moduleCode": "order",
|
||||
"revision": 10,
|
||||
"revision": 1,
|
||||
"schemaChecksum": null,
|
||||
"schemaInputChecksum": "9811550dfb225cd89362118cd649590d3d52f9388456aaf5aee082c2399bfc5b",
|
||||
"schemaInputChecksum": "1b3eec01e5b04880166e20e8e6df70b79f227129ea9165e38cfbb925be3c2d23",
|
||||
"actionManifestChecksum": null,
|
||||
"runtimeContractChecksum": "44e98417f57e308e66e32fc306b3ba5793ae1140ed0465531315380970c57e4d",
|
||||
"runtimeContractChecksum": "3d025d1b634c413449eb91164fb1f859a388d8930d2de112980a606b591befce",
|
||||
"implementationManifestChecksum": "f25647d2dd90e14d6226683d2ff67ba32132b2dfdeb861015805240a96d4635b",
|
||||
"actions": [
|
||||
"OrdersAdd",
|
||||
@@ -50,7 +50,7 @@
|
||||
"list",
|
||||
"page"
|
||||
],
|
||||
"descriptorChecksum": "9748697d1a60b5e0957fb58c62a8564c997397007d15a6d35b783fceee178e97",
|
||||
"descriptorChecksum": "b4b4c2c624d655282f336f4758e6d057082541502dfd0099ca0f520f75d973fd",
|
||||
"actions": {
|
||||
"add": "OrdersAdd",
|
||||
"delete": "OrdersDelete",
|
||||
@@ -95,13 +95,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -112,7 +105,7 @@
|
||||
"amount"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "1a63df8bd8a0a663d853603eac460eb419f44131f9ca1de36c9d91925c03c95f",
|
||||
"inputChecksum": "bbaa3690f78676aeed57b00951cd36a1ae2a82c4afeb86911040fdae86da53c9",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -143,13 +136,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -162,7 +148,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:add"
|
||||
@@ -176,7 +162,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -502,13 +487,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -521,7 +499,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:info"
|
||||
@@ -535,7 +513,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -663,13 +640,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -683,7 +653,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "a02a513155bd8cbf6dc15471919a77f076e6225975e07a90285763bd3b481661",
|
||||
"outputChecksum": "040ec4e29e6999ab8ce2e1d9ebe4d4a5b1c09e805c10870401dbb273c9a8c9bc",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:list"
|
||||
@@ -697,7 +667,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -833,13 +802,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -883,7 +845,7 @@
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "9b8f0c856c1dec532d601d56a84c8267f591ff82b89d5750df62d6104271eeb7",
|
||||
"outputChecksum": "14efb96cade110fc8fef771fb439845b0892d169d9f26f0be10127b547262877",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:page"
|
||||
@@ -897,7 +859,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -944,13 +905,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -958,7 +912,7 @@
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "acf0b47a3dd2bb4dc9f7e87399f8e0fd2300391230886283588204ba9b8c8e4c",
|
||||
"inputChecksum": "437195e38df6988a131ad09b0b7ee089108857a4795c75aba395d077255676fc",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -986,7 +940,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"formatVersion": 2,
|
||||
"moduleCode": "order",
|
||||
"revision": 10,
|
||||
"revision": 1,
|
||||
"releaseVersion": null,
|
||||
"schemaVersion": 10,
|
||||
"schemaInputChecksum": "9811550dfb225cd89362118cd649590d3d52f9388456aaf5aee082c2399bfc5b",
|
||||
"schemaVersion": 1,
|
||||
"schemaInputChecksum": "1b3eec01e5b04880166e20e8e6df70b79f227129ea9165e38cfbb925be3c2d23",
|
||||
"schemaChecksum": null,
|
||||
"actionManifestChecksum": null,
|
||||
"runtimeContractChecksum": "44e98417f57e308e66e32fc306b3ba5793ae1140ed0465531315380970c57e4d",
|
||||
"runtimeContractChecksum": "3d025d1b634c413449eb91164fb1f859a388d8930d2de112980a606b591befce",
|
||||
"implementationManifestChecksum": "f25647d2dd90e14d6226683d2ff67ba32132b2dfdeb861015805240a96d4635b",
|
||||
"models": [
|
||||
{
|
||||
@@ -85,16 +85,6 @@
|
||||
"writable": true,
|
||||
"filterable": true,
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"code": "remark",
|
||||
"type": "varchar",
|
||||
"nullable": true,
|
||||
"primary": false,
|
||||
"readable": true,
|
||||
"writable": true,
|
||||
"filterable": false,
|
||||
"sortable": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -185,13 +175,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -202,7 +185,7 @@
|
||||
"amount"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "1a63df8bd8a0a663d853603eac460eb419f44131f9ca1de36c9d91925c03c95f",
|
||||
"inputChecksum": "bbaa3690f78676aeed57b00951cd36a1ae2a82c4afeb86911040fdae86da53c9",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -233,13 +216,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -252,7 +228,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:add"
|
||||
@@ -266,7 +242,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -333,13 +308,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -350,7 +318,7 @@
|
||||
"amount"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "1a63df8bd8a0a663d853603eac460eb419f44131f9ca1de36c9d91925c03c95f",
|
||||
"inputChecksum": "bbaa3690f78676aeed57b00951cd36a1ae2a82c4afeb86911040fdae86da53c9",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -381,13 +349,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -400,7 +361,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:add"
|
||||
@@ -414,7 +375,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -985,13 +945,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1004,7 +957,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:info"
|
||||
@@ -1018,7 +971,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1076,13 +1028,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1095,7 +1040,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "a1214f4132a2d2897384694e7f3bb8fc2c436cd6ed1d2d8f09c7515bb76538d1",
|
||||
"outputChecksum": "9621cab591356c44012f30c8ba2209b1c62ad4834e1b90b8899420ad1ab1721e",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:info"
|
||||
@@ -1109,7 +1054,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1240,13 +1184,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1260,7 +1197,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "a02a513155bd8cbf6dc15471919a77f076e6225975e07a90285763bd3b481661",
|
||||
"outputChecksum": "040ec4e29e6999ab8ce2e1d9ebe4d4a5b1c09e805c10870401dbb273c9a8c9bc",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:list"
|
||||
@@ -1274,7 +1211,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1400,13 +1336,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1420,7 +1349,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "a02a513155bd8cbf6dc15471919a77f076e6225975e07a90285763bd3b481661",
|
||||
"outputChecksum": "040ec4e29e6999ab8ce2e1d9ebe4d4a5b1c09e805c10870401dbb273c9a8c9bc",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:list"
|
||||
@@ -1434,7 +1363,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1573,13 +1501,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1623,7 +1544,7 @@
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "9b8f0c856c1dec532d601d56a84c8267f591ff82b89d5750df62d6104271eeb7",
|
||||
"outputChecksum": "14efb96cade110fc8fef771fb439845b0892d169d9f26f0be10127b547262877",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:page"
|
||||
@@ -1637,7 +1558,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1771,13 +1691,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1821,7 +1734,7 @@
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "9b8f0c856c1dec532d601d56a84c8267f591ff82b89d5750df62d6104271eeb7",
|
||||
"outputChecksum": "14efb96cade110fc8fef771fb439845b0892d169d9f26f0be10127b547262877",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "order:orders:page"
|
||||
@@ -1835,7 +1748,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1885,13 +1797,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1899,7 +1804,7 @@
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "acf0b47a3dd2bb4dc9f7e87399f8e0fd2300391230886283588204ba9b8c8e4c",
|
||||
"inputChecksum": "437195e38df6988a131ad09b0b7ee089108857a4795c75aba395d077255676fc",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -1927,7 +1832,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -1998,13 +1902,6 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"maxLength": 24
|
||||
},
|
||||
"remark": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -2012,7 +1909,7 @@
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "acf0b47a3dd2bb4dc9f7e87399f8e0fd2300391230886283588204ba9b8c8e4c",
|
||||
"inputChecksum": "437195e38df6988a131ad09b0b7ee089108857a4795c75aba395d077255676fc",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -2040,7 +1937,6 @@
|
||||
"id",
|
||||
"order_no",
|
||||
"quantity",
|
||||
"remark",
|
||||
"status",
|
||||
"unit_price"
|
||||
],
|
||||
@@ -2135,10 +2031,10 @@
|
||||
"actionChecksum": "3978a7ba9a3e0f91842031fd323ec63b3816eef68cb8dc82ffad6d187de8b7ea",
|
||||
"outputChecksum": "fe644424ef6a9e462b56edc9f70f48bb218783c69469469d4310de48589a0df5",
|
||||
"contractVersion": 1,
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseId": 38,
|
||||
"consumerModuleCode": "order",
|
||||
"providerModuleCode": "demo",
|
||||
"providerReleaseVersion": "1.0.10-rc.10"
|
||||
"providerReleaseVersion": "1.0.0-rc.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2205,10 +2101,10 @@
|
||||
"outputChecksum": "a632b9f89518c3c17861454b74173a4880d5e8482639d3ff7f761aee4d061bd9",
|
||||
"contractVersion": 1,
|
||||
"commandEventType": "saas.workflow.demo.goods.releaseStock",
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseId": 38,
|
||||
"consumerModuleCode": "order",
|
||||
"providerModuleCode": "demo",
|
||||
"providerReleaseVersion": "1.0.10-rc.10",
|
||||
"providerReleaseVersion": "1.0.0-rc.1",
|
||||
"commandEventContractChecksum": "18a727b91cf9410c3b7ac14e3a8799dbbfa8937f84667bfe7e31e21e662396be"
|
||||
}
|
||||
},
|
||||
@@ -2270,10 +2166,10 @@
|
||||
"outputChecksum": "545bd8b0bf6eb8670b21497236038187ee0f1df1544a318b16a399458fcb796e",
|
||||
"contractVersion": 1,
|
||||
"commandEventType": "saas.workflow.demo.goods.reserveStock",
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseId": 38,
|
||||
"consumerModuleCode": "order",
|
||||
"providerModuleCode": "demo",
|
||||
"providerReleaseVersion": "1.0.10-rc.10",
|
||||
"providerReleaseVersion": "1.0.0-rc.1",
|
||||
"commandEventContractChecksum": "ffbecad3a3d63b8bf92fde701dfaa11c8502a2c5f9f6bbb89b755e214024c3ae"
|
||||
}
|
||||
}
|
||||
@@ -2313,8 +2209,8 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"providerReleaseId": 59,
|
||||
"providerReleaseVersion": "1.0.10-rc.10"
|
||||
"providerReleaseId": 38,
|
||||
"providerReleaseVersion": "1.0.0-rc.1"
|
||||
}
|
||||
],
|
||||
"crud": [
|
||||
@@ -2329,7 +2225,7 @@
|
||||
"list",
|
||||
"page"
|
||||
],
|
||||
"descriptorChecksum": "9748697d1a60b5e0957fb58c62a8564c997397007d15a6d35b783fceee178e97",
|
||||
"descriptorChecksum": "b4b4c2c624d655282f336f4758e6d057082541502dfd0099ca0f520f75d973fd",
|
||||
"actions": {
|
||||
"add": "OrdersAdd",
|
||||
"delete": "OrdersDelete",
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// Exercise the actual TypeScript service, with only its injected CRUD/Action
|
||||
// collaborators stubbed. No application bootstrap, network, database or dist
|
||||
// writes are needed; generated contracts and decorators remain the real ones.
|
||||
require('reflect-metadata');
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const ts = require('typescript');
|
||||
const { SaasBusinessReject, ModuleRuntimeError } = require('@cool-midway/module-runtime');
|
||||
const sourceRoot = path.resolve(__dirname, '../src');
|
||||
const previousTsLoader = require.extensions['.ts'];
|
||||
let OrdersService;
|
||||
try {
|
||||
require.extensions['.ts'] = (module, filename) => {
|
||||
assert.ok(filename.startsWith(sourceRoot + path.sep), 'only this service source tree is compiled in memory');
|
||||
const compiled = ts.transpileModule(fs.readFileSync(filename, 'utf8'), {
|
||||
fileName: filename,
|
||||
compilerOptions: { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.CommonJS,
|
||||
experimentalDecorators: true, emitDecoratorMetadata: true, esModuleInterop: true },
|
||||
});
|
||||
module._compile(compiled.outputText, filename);
|
||||
};
|
||||
({ OrdersService } = require('../src/service/orders.ts'));
|
||||
} finally {
|
||||
if (previousTsLoader) require.extensions['.ts'] = previousTsLoader;
|
||||
else delete require.extensions['.ts'];
|
||||
}
|
||||
|
||||
function fixture(overrides = {}) {
|
||||
const state = {
|
||||
goods: { id: '24', status: 1, price: '12.50', stock: 20 },
|
||||
order: { id: '27', order_no: 'UNIT-ORDER', goods_id: '24', quantity: 3, amount: '37.50', status: 'confirmed' },
|
||||
calls: [], ...overrides,
|
||||
};
|
||||
const service = new OrdersService();
|
||||
service.batchInfo = async input => { state.calls.push(['batchInfo', input]); return { list: state.goods ? [state.goods] : [] }; };
|
||||
service.reserveStock = async input => { state.calls.push(['reserveStock', input]); return { goodsId: input.goodsId, remainingStock: 17 }; };
|
||||
service.releaseStock = async input => { state.calls.push(['releaseStock', input]); return { goodsId: input.goodsId, currentStock: 20 }; };
|
||||
service.orders = {
|
||||
lock: async input => {state.calls.push(['lock',input]);return state.order;},
|
||||
info: async () => assert.fail('missing-record lookup must not invoke the nonnullable info contract'),
|
||||
list: async input => { state.calls.push(['list', input]); return state.order ? [state.order] : []; },
|
||||
add: async input => { state.calls.push(['add', input]); return { id: '27', ...input, ...state.addResult }; },
|
||||
update: async input => { state.calls.push(['update', input]); return { affected: 1 }; },
|
||||
};
|
||||
service.workflow = {start: async input => {state.calls.push(['workflow',input]);return {sagaId:'test-saga'};}};
|
||||
return { service, state };
|
||||
}
|
||||
const createInput = { orderNo: 'UNIT-ORDER', goodsId: 24, quantity: 3 };
|
||||
const business = code => error => error instanceof SaasBusinessReject && !(error instanceof ModuleRuntimeError) && error.code === code;
|
||||
const contract = error => error instanceof ModuleRuntimeError && !(error instanceof SaasBusinessReject) &&
|
||||
error.errorCode === 'MODULE_ACTION_INPUT_INVALID' && error.statusCode === 409;
|
||||
const noWrites = state => assert.ok(state.calls.every(([name]) => !['reserveStock', 'releaseStock', 'add', 'update'].includes(name)));
|
||||
|
||||
test('the existing locked list contract authorizes ID filtering and valid empty-array results', () => {
|
||||
const lock = JSON.parse(fs.readFileSync(path.join(sourceRoot, 'saas/generated/order/saas-schema.lock.json'), 'utf8'));
|
||||
const model = lock.models.find(item => item.tableCode === 'orders');
|
||||
assert.equal(model.fields.find(field => field.code === 'id').filterable, true);
|
||||
const list = lock.actions.find(item => item.manifestDescriptor.name === 'orders.list').manifestDescriptor;
|
||||
assert.equal(list.inputSchema.properties.where.properties.id.type, 'string');
|
||||
assert.equal(list.inputSchema.properties.take.minimum, 1);
|
||||
assert.equal(list.outputSchema.type, 'array');
|
||||
assert.ok(list.tables.some(table => table.tableCode === 'orders' && table.select === true && table.fields.includes('id')));
|
||||
});
|
||||
|
||||
test('unlisted goods is an explicit GOODS_UNAVAILABLE business rejection before any write', async () => {
|
||||
const f = fixture({ goods: { id: '24', status: 0, price: '12.50' } });
|
||||
await assert.rejects(f.service.createOrder(createInput), business('GOODS_UNAVAILABLE'));
|
||||
noWrites(f.state);
|
||||
});
|
||||
|
||||
test('missing goods is GOODS_NOT_FOUND in both order creation and details', async t => {
|
||||
for (const method of ['createOrder', 'detailWithGoods']) await t.test(method, async () => {
|
||||
const f = fixture({ goods: null });
|
||||
await assert.rejects(f.service[method](method === 'createOrder' ? createInput : { id: 27 }), business('GOODS_NOT_FOUND'));
|
||||
noWrites(f.state);
|
||||
});
|
||||
});
|
||||
|
||||
test('missing order is ORDER_NOT_FOUND in details and cancellation', async t => {
|
||||
for (const method of ['detailWithGoods', 'cancelOrder']) await t.test(method, async () => {
|
||||
const f = fixture({ order: null });
|
||||
await assert.rejects(f.service[method]({ id: 27 }), business('ORDER_NOT_FOUND'));
|
||||
assert.deepEqual(f.state.calls, method === 'cancelOrder' ? [['lock',{id:'27'}]] : [['list', { where: { id: '27' }, take: 1 }]]);
|
||||
noWrites(f.state);
|
||||
});
|
||||
});
|
||||
|
||||
test('malformed goods status and price remain contract errors, not business warnings', async t => {
|
||||
for (const [label, patch] of [['fractional status', { status: 1.2 }], ['invalid status', { status: 'bad' }],
|
||||
['invalid price', { price: '12.5oops' }], ['nonfinite price', { price: Infinity }]]) {
|
||||
await t.test(label, async () => {
|
||||
const f = fixture(); Object.assign(f.state.goods, patch);
|
||||
await assert.rejects(f.service.createOrder(createInput), contract);
|
||||
noWrites(f.state);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('unsafe stored goods IDs remain contract failures before a cross-module call', async t => {
|
||||
for (const id of ['0', '-1', '1.5', '9007199254740992', 'bad']) await t.test(id, async () => {
|
||||
const f = fixture(); f.state.order.goods_id = id;
|
||||
await assert.rejects(f.service.detailWithGoods({ id: 27 }), contract);
|
||||
assert.deepEqual(f.state.calls.map(([name]) => name), ['list']);
|
||||
});
|
||||
});
|
||||
|
||||
test('invalid generated order ID or amount stays a contract error after mocked CRUD', async t => {
|
||||
for (const [label, addResult] of [['unsafe order ID', { id: '9007199254740992' }], ['nonfinite amount', { amount: 'NaN' }]]) {
|
||||
await t.test(label, async () => {
|
||||
const f = fixture({ addResult });
|
||||
await assert.rejects(f.service.createOrder(createInput), contract);
|
||||
assert.deepEqual(f.state.calls.map(([name]) => name), ['batchInfo', 'add', 'workflow']);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('failure to persist workflow propagates to the enclosing transaction', async () => {
|
||||
const f = fixture();
|
||||
const downstream = new SaasBusinessReject('INSUFFICIENT_STOCK', '库存不足');
|
||||
f.service.workflow.start = async () => { throw downstream; };
|
||||
await assert.rejects(f.service.createOrder(createInput), error => error === downstream);
|
||||
assert.equal(f.state.calls.some(([name]) => name === 'reserveStock'), false);
|
||||
});
|
||||
|
||||
test('list contract and database failures propagate unchanged instead of becoming ORDER_NOT_FOUND', async t => {
|
||||
for (const error of [new ModuleRuntimeError('MODULE_ACTION_OUTPUT_INVALID', 'invalid list output', 500),
|
||||
new ModuleRuntimeError('MODULE_ACTION_FORBIDDEN', 'list access denied', 403), new Error('database unavailable')]) {
|
||||
await t.test(error.message, async () => {
|
||||
const f = fixture();
|
||||
f.service.orders.list = async () => { throw error; };
|
||||
await assert.rejects(f.service.detailWithGoods({ id: 27 }), observed => observed === error && !(observed instanceof SaasBusinessReject));
|
||||
noWrites(f.state);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('creation persists pending intent and starts durable workflow without a synchronous stock write', async () => {
|
||||
const f = fixture();
|
||||
assert.deepEqual(await f.service.createOrder(createInput), { id: 27, orderNo: 'UNIT-ORDER', amount: 37.5, status: 'pending_reservation' });
|
||||
assert.deepEqual(f.state.calls.map(([name]) => name), ['batchInfo', 'add', 'workflow']);
|
||||
const flow=f.state.calls[2][1];
|
||||
assert.equal(flow.type,'order.create@1');
|
||||
assert.deepEqual(flow.steps[0].input,{goodsId:24,quantity:3});
|
||||
assert.deepEqual(flow.outcomes.completed,{id:'27',status:'confirmed'});
|
||||
assert.deepEqual(flow.outcomes.failed,{id:'27',status:'rejected'});
|
||||
});
|
||||
|
||||
test('cancellation locks state and persists release workflow; terminal and pending repeats are inert', async () => {
|
||||
const f = fixture();
|
||||
assert.deepEqual(await f.service.cancelOrder({ id: 27 }), { id: 27, status: 'cancel_pending', restoredStock: 0 });
|
||||
assert.deepEqual(f.state.calls.map(([name]) => name), ['lock', 'update', 'workflow']);
|
||||
const repeated = fixture(); repeated.state.order.status = 'cancelled';
|
||||
assert.deepEqual(await repeated.service.cancelOrder({ id: 27 }), { id: 27, status: 'cancelled', restoredStock: 0 });
|
||||
assert.deepEqual(repeated.state.calls.map(([name]) => name), ['lock']);
|
||||
const pending=fixture(); pending.state.order.status='cancel_pending';
|
||||
assert.equal((await pending.service.cancelOrder({id:27})).status,'cancel_pending');
|
||||
assert.deepEqual(pending.state.calls.map(([name])=>name),['lock']);
|
||||
});
|
||||
|
||||
test('legacy or unconfirmed orders cannot manufacture a stock release', async () => {
|
||||
for (const status of ['created','pending_reservation','rejected','manual_review']) {
|
||||
const f=fixture();f.state.order.status=status;
|
||||
await assert.rejects(f.service.cancelOrder({id:27}),business('ORDER_STATE_CONFLICT'));
|
||||
noWrites(f.state);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user