@devx-retailos/cms 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.medusa/server/src/admin/index.js +23 -0
  2. package/.medusa/server/src/admin/index.mjs +24 -0
  3. package/.medusa/server/src/api/admin/retailos/cms/accumulation/[storeId]/route.js +34 -0
  4. package/.medusa/server/src/api/admin/retailos/cms/export/route.js +52 -0
  5. package/.medusa/server/src/api/admin/retailos/cms/handovers/[id]/route.js +35 -0
  6. package/.medusa/server/src/api/admin/retailos/cms/handovers/route.js +78 -0
  7. package/.medusa/server/src/api/admin/retailos/cms/operation/route.js +124 -0
  8. package/.medusa/server/src/api/admin/retailos/cms/petty-cash/route.js +31 -0
  9. package/.medusa/server/src/api/admin/retailos/cms/shift-logs/route.js +36 -0
  10. package/.medusa/server/src/links/employee-to-cms-handover.js +13 -0
  11. package/.medusa/server/src/links/store-to-cms-handover.js +13 -0
  12. package/.medusa/server/src/modules/cms/constants.js +5 -0
  13. package/.medusa/server/src/modules/cms/index.js +53 -0
  14. package/.medusa/server/src/modules/cms/migrations/Migration20260622000000.js +30 -0
  15. package/.medusa/server/src/modules/cms/migrations/Migration20260622000001.js +16 -0
  16. package/.medusa/server/src/modules/cms/models/cms-accumulation.js +11 -0
  17. package/.medusa/server/src/modules/cms/models/cms-handover.js +17 -0
  18. package/.medusa/server/src/modules/cms/models/index.js +15 -0
  19. package/.medusa/server/src/modules/cms/models/petty-cash-transaction.js +24 -0
  20. package/.medusa/server/src/modules/cms/models/petty-cash.js +11 -0
  21. package/.medusa/server/src/modules/cms/permissions.js +36 -0
  22. package/.medusa/server/src/modules/cms/services/cms-module-service.js +210 -0
  23. package/.medusa/server/src/modules/cms/services/index.js +9 -0
  24. package/README.md +155 -0
  25. package/package.json +60 -0
  26. package/src/admin/.gitkeep +0 -0
  27. package/src/api/admin/retailos/cms/accumulation/[storeId]/__tests__/route.test.ts +68 -0
  28. package/src/api/admin/retailos/cms/accumulation/[storeId]/route.ts +35 -0
  29. package/src/api/admin/retailos/cms/export/__tests__/route.test.ts +126 -0
  30. package/src/api/admin/retailos/cms/export/route.ts +58 -0
  31. package/src/api/admin/retailos/cms/handovers/[id]/__tests__/route.test.ts +68 -0
  32. package/src/api/admin/retailos/cms/handovers/[id]/route.ts +36 -0
  33. package/src/api/admin/retailos/cms/handovers/__tests__/route.test.ts +104 -0
  34. package/src/api/admin/retailos/cms/handovers/route.ts +79 -0
  35. package/src/api/admin/retailos/cms/operation/__tests__/route.test.ts +169 -0
  36. package/src/api/admin/retailos/cms/operation/route.ts +130 -0
  37. package/src/api/admin/retailos/cms/petty-cash/__tests__/route.test.ts +73 -0
  38. package/src/api/admin/retailos/cms/petty-cash/route.ts +35 -0
  39. package/src/api/admin/retailos/cms/shift-logs/__tests__/route.test.ts +77 -0
  40. package/src/api/admin/retailos/cms/shift-logs/route.ts +38 -0
  41. package/src/links/employee-to-cms-handover.ts +11 -0
  42. package/src/links/store-to-cms-handover.ts +11 -0
  43. package/src/modules/cms/__tests__/cms-module-service.test.ts +333 -0
  44. package/src/modules/cms/__tests__/permissions.test.ts +36 -0
  45. package/src/modules/cms/constants.ts +1 -0
  46. package/src/modules/cms/index.ts +24 -0
  47. package/src/modules/cms/migrations/Migration20260622000000.ts +58 -0
  48. package/src/modules/cms/migrations/Migration20260622000001.ts +17 -0
  49. package/src/modules/cms/models/cms-accumulation.ts +10 -0
  50. package/src/modules/cms/models/cms-handover.ts +16 -0
  51. package/src/modules/cms/models/index.ts +4 -0
  52. package/src/modules/cms/models/petty-cash-transaction.ts +23 -0
  53. package/src/modules/cms/models/petty-cash.ts +10 -0
  54. package/src/modules/cms/permissions.ts +34 -0
  55. package/src/modules/cms/services/cms-module-service.ts +284 -0
  56. package/src/modules/cms/services/index.ts +13 -0
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@medusajs/framework/utils");
4
+ const CmsAccumulation = utils_1.model.define("retailos_cms_accumulation", {
5
+ id: utils_1.model.id({ prefix: "cmsa" }).primaryKey(),
6
+ store_id: utils_1.model.text().searchable(),
7
+ cash_in_store: utils_1.model.number(),
8
+ metadata: utils_1.model.json().nullable(),
9
+ });
10
+ exports.default = CmsAccumulation;
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY21zLWFjY3VtdWxhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2Ntcy9tb2RlbHMvY21zLWFjY3VtdWxhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUFpRDtBQUVqRCxNQUFNLGVBQWUsR0FBRyxhQUFLLENBQUMsTUFBTSxDQUFDLDJCQUEyQixFQUFFO0lBQ2hFLEVBQUUsRUFBRSxhQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsVUFBVSxFQUFFO0lBQzdDLFFBQVEsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsVUFBVSxFQUFFO0lBQ25DLGFBQWEsRUFBRSxhQUFLLENBQUMsTUFBTSxFQUFFO0lBQzdCLFFBQVEsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQ2xDLENBQUMsQ0FBQTtBQUVGLGtCQUFlLGVBQWUsQ0FBQSJ9
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@medusajs/framework/utils");
4
+ const CmsHandover = utils_1.model.define("retailos_cms_handover", {
5
+ id: utils_1.model.id({ prefix: "cmsh" }).primaryKey(),
6
+ store_id: utils_1.model.text().searchable(),
7
+ employee_id: utils_1.model.text().searchable(),
8
+ handover_id: utils_1.model.text().nullable(), // free-text correlation field: the brand can pass their own ID (e.g. a bank slip number, a vault reference, a POS transaction ID) so they can cross-reference this handover record with their own external system.
9
+ handover_amount: utils_1.model.number().nullable(),
10
+ total_cash: utils_1.model.number().nullable(),
11
+ type: utils_1.model.text().nullable(),
12
+ image_url: utils_1.model.text().nullable(),
13
+ remark: utils_1.model.text().nullable(),
14
+ metadata: utils_1.model.json().nullable(),
15
+ });
16
+ exports.default = CmsHandover;
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY21zLWhhbmRvdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21vZHVsZXMvY21zL21vZGVscy9jbXMtaGFuZG92ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxxREFBaUQ7QUFFakQsTUFBTSxXQUFXLEdBQUcsYUFBSyxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsRUFBRTtJQUN4RCxFQUFFLEVBQUUsYUFBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBRTtJQUM3QyxRQUFRLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFVBQVUsRUFBRTtJQUNuQyxXQUFXLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFVBQVUsRUFBRTtJQUN0QyxXQUFXLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRSxFQUFFLG1OQUFtTjtJQUN6UCxlQUFlLEVBQUUsYUFBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMxQyxVQUFVLEVBQUUsYUFBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNyQyxJQUFJLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM3QixTQUFTLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNsQyxNQUFNLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMvQixRQUFRLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRTtDQUNsQyxDQUFDLENBQUE7QUFFRixrQkFBZSxXQUFXLENBQUEifQ==
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PettyCashTransaction = exports.PettyCash = exports.CmsAccumulation = exports.CmsHandover = void 0;
7
+ var cms_handover_1 = require("./cms-handover");
8
+ Object.defineProperty(exports, "CmsHandover", { enumerable: true, get: function () { return __importDefault(cms_handover_1).default; } });
9
+ var cms_accumulation_1 = require("./cms-accumulation");
10
+ Object.defineProperty(exports, "CmsAccumulation", { enumerable: true, get: function () { return __importDefault(cms_accumulation_1).default; } });
11
+ var petty_cash_1 = require("./petty-cash");
12
+ Object.defineProperty(exports, "PettyCash", { enumerable: true, get: function () { return __importDefault(petty_cash_1).default; } });
13
+ var petty_cash_transaction_1 = require("./petty-cash-transaction");
14
+ Object.defineProperty(exports, "PettyCashTransaction", { enumerable: true, get: function () { return __importDefault(petty_cash_transaction_1).default; } });
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9jbXMvbW9kZWxzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLCtDQUF1RDtBQUE5Qyw0SEFBQSxPQUFPLE9BQWU7QUFDL0IsdURBQStEO0FBQXRELG9JQUFBLE9BQU8sT0FBbUI7QUFDbkMsMkNBQW1EO0FBQTFDLHdIQUFBLE9BQU8sT0FBYTtBQUM3QixtRUFBMEU7QUFBakUsK0lBQUEsT0FBTyxPQUF3QiJ9
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@medusajs/framework/utils");
4
+ const PettyCashTransaction = utils_1.model.define("retailos_petty_cash_transaction", {
5
+ id: utils_1.model.id({ prefix: "pct" }).primaryKey(),
6
+ store_id: utils_1.model.text().searchable(),
7
+ employee_id: utils_1.model.text().searchable(),
8
+ transaction_type: utils_1.model.text(),
9
+ entry_type: utils_1.model.text().nullable(),
10
+ source: utils_1.model.text().nullable(),
11
+ amount: utils_1.model.number(),
12
+ opening_balance: utils_1.model.number().nullable(),
13
+ closing_balance: utils_1.model.number().nullable(),
14
+ expense_amount: utils_1.model.number(),
15
+ difference_amount: utils_1.model.number(),
16
+ category: utils_1.model.text().nullable(),
17
+ sub_category: utils_1.model.text().nullable(),
18
+ reason: utils_1.model.text().nullable(),
19
+ image_url: utils_1.model.text().nullable(),
20
+ date: utils_1.model.dateTime().nullable(),
21
+ metadata: utils_1.model.json().nullable(),
22
+ });
23
+ exports.default = PettyCashTransaction;
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGV0dHktY2FzaC10cmFuc2FjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2Ntcy9tb2RlbHMvcGV0dHktY2FzaC10cmFuc2FjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUFpRDtBQUVqRCxNQUFNLG9CQUFvQixHQUFHLGFBQUssQ0FBQyxNQUFNLENBQUMsaUNBQWlDLEVBQUU7SUFDM0UsRUFBRSxFQUFFLGFBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUU7SUFDNUMsUUFBUSxFQUFFLGFBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxVQUFVLEVBQUU7SUFDbkMsV0FBVyxFQUFFLGFBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxVQUFVLEVBQUU7SUFDdEMsZ0JBQWdCLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRTtJQUM5QixVQUFVLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNuQyxNQUFNLEVBQUUsYUFBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMvQixNQUFNLEVBQUUsYUFBSyxDQUFDLE1BQU0sRUFBRTtJQUN0QixlQUFlLEVBQUUsYUFBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMxQyxlQUFlLEVBQUUsYUFBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMxQyxjQUFjLEVBQUUsYUFBSyxDQUFDLE1BQU0sRUFBRTtJQUM5QixpQkFBaUIsRUFBRSxhQUFLLENBQUMsTUFBTSxFQUFFO0lBQ2pDLFFBQVEsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2pDLFlBQVksRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3JDLE1BQU0sRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQy9CLFNBQVMsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2xDLElBQUksRUFBRSxhQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2pDLFFBQVEsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQ2xDLENBQUMsQ0FBQTtBQUVGLGtCQUFlLG9CQUFvQixDQUFBIn0=
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@medusajs/framework/utils");
4
+ const PettyCash = utils_1.model.define("retailos_petty_cash", {
5
+ id: utils_1.model.id({ prefix: "pc" }).primaryKey(),
6
+ store_id: utils_1.model.text().searchable(),
7
+ balance: utils_1.model.number(),
8
+ metadata: utils_1.model.json().nullable(),
9
+ });
10
+ exports.default = PettyCash;
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGV0dHktY2FzaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2Ntcy9tb2RlbHMvcGV0dHktY2FzaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUFpRDtBQUVqRCxNQUFNLFNBQVMsR0FBRyxhQUFLLENBQUMsTUFBTSxDQUFDLHFCQUFxQixFQUFFO0lBQ3BELEVBQUUsRUFBRSxhQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsVUFBVSxFQUFFO0lBQzNDLFFBQVEsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsVUFBVSxFQUFFO0lBQ25DLE9BQU8sRUFBRSxhQUFLLENBQUMsTUFBTSxFQUFFO0lBQ3ZCLFFBQVEsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQ2xDLENBQUMsQ0FBQTtBQUVGLGtCQUFlLFNBQVMsQ0FBQSJ9
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CMS_PERMISSIONS = void 0;
4
+ exports.CMS_PERMISSIONS = [
5
+ {
6
+ key: "cms.handover.read",
7
+ description: "View cash handover records",
8
+ registered_by: "cms",
9
+ },
10
+ {
11
+ key: "cms.handover.create",
12
+ description: "Create a cash handover record",
13
+ registered_by: "cms",
14
+ },
15
+ {
16
+ key: "cms.shift.operate",
17
+ description: "Open and close shift (day start / day end)",
18
+ registered_by: "cms",
19
+ },
20
+ {
21
+ key: "cms.petty_cash.read",
22
+ description: "View petty cash balance and transactions",
23
+ registered_by: "cms",
24
+ },
25
+ {
26
+ key: "cms.petty_cash.operate",
27
+ description: "Add petty cash or record expenses",
28
+ registered_by: "cms",
29
+ },
30
+ {
31
+ key: "cms.accumulation.read",
32
+ description: "View current cash accumulation for a store",
33
+ registered_by: "cms",
34
+ },
35
+ ];
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9jbXMvcGVybWlzc2lvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRWEsUUFBQSxlQUFlLEdBQTZCO0lBQ3ZEO1FBQ0UsR0FBRyxFQUFFLG1CQUFtQjtRQUN4QixXQUFXLEVBQUUsNEJBQTRCO1FBQ3pDLGFBQWEsRUFBRSxLQUFLO0tBQ3JCO0lBQ0Q7UUFDRSxHQUFHLEVBQUUscUJBQXFCO1FBQzFCLFdBQVcsRUFBRSwrQkFBK0I7UUFDNUMsYUFBYSxFQUFFLEtBQUs7S0FDckI7SUFDRDtRQUNFLEdBQUcsRUFBRSxtQkFBbUI7UUFDeEIsV0FBVyxFQUFFLDRDQUE0QztRQUN6RCxhQUFhLEVBQUUsS0FBSztLQUNyQjtJQUNEO1FBQ0UsR0FBRyxFQUFFLHFCQUFxQjtRQUMxQixXQUFXLEVBQUUsMENBQTBDO1FBQ3ZELGFBQWEsRUFBRSxLQUFLO0tBQ3JCO0lBQ0Q7UUFDRSxHQUFHLEVBQUUsd0JBQXdCO1FBQzdCLFdBQVcsRUFBRSxtQ0FBbUM7UUFDaEQsYUFBYSxFQUFFLEtBQUs7S0FDckI7SUFDRDtRQUNFLEdBQUcsRUFBRSx1QkFBdUI7UUFDNUIsV0FBVyxFQUFFLDRDQUE0QztRQUN6RCxhQUFhLEVBQUUsS0FBSztLQUNyQjtDQUNGLENBQUEifQ==
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("@medusajs/framework/utils");
7
+ const core_1 = require("@devx-retailos/core");
8
+ const cms_handover_1 = __importDefault(require("../models/cms-handover"));
9
+ const cms_accumulation_1 = __importDefault(require("../models/cms-accumulation"));
10
+ const petty_cash_1 = __importDefault(require("../models/petty-cash"));
11
+ const petty_cash_transaction_1 = __importDefault(require("../models/petty-cash-transaction"));
12
+ class CmsModuleService extends (0, utils_1.MedusaService)({
13
+ CmsHandover: cms_handover_1.default,
14
+ CmsAccumulation: cms_accumulation_1.default,
15
+ PettyCash: petty_cash_1.default,
16
+ PettyCashTransaction: petty_cash_transaction_1.default,
17
+ }) {
18
+ constructor(...args) {
19
+ super(...args);
20
+ const container = (args[0] ?? {});
21
+ this.logger_ = container.logger ?? (0, core_1.createNoopLogger)();
22
+ this.logger_.debug("[retailos/cms] service initialized");
23
+ }
24
+ async dayStart(input) {
25
+ const { store_id, employee_id, opening_amount } = input;
26
+ if (opening_amount < 0) {
27
+ throw new Error("[retailos/cms] opening_amount must be >= 0");
28
+ }
29
+ const existing = await this.listCmsAccumulations({ store_id: [store_id] });
30
+ if (existing.length === 0) {
31
+ await this.createCmsAccumulations([{ store_id, cash_in_store: opening_amount }]);
32
+ }
33
+ else {
34
+ await this.updateCmsAccumulations([{ id: existing[0].id, cash_in_store: opening_amount }]);
35
+ }
36
+ await this.createPettyCashTransactions([{
37
+ store_id,
38
+ employee_id,
39
+ transaction_type: "open",
40
+ entry_type: "CR",
41
+ source: null,
42
+ amount: opening_amount,
43
+ opening_balance: opening_amount,
44
+ closing_balance: null,
45
+ expense_amount: 0,
46
+ difference_amount: 0,
47
+ category: null,
48
+ sub_category: null,
49
+ reason: null,
50
+ image_url: null,
51
+ date: new Date(),
52
+ metadata: null,
53
+ }]);
54
+ this.logger_.info("cms.day_started", { store_id, employee_id, opening_amount });
55
+ }
56
+ async dayEnd(input) {
57
+ const { store_id, employee_id, closing_amount } = input;
58
+ if (closing_amount < 0) {
59
+ throw new Error("[retailos/cms] closing_amount must be >= 0");
60
+ }
61
+ const accumulations = await this.listCmsAccumulations({ store_id: [store_id] });
62
+ const current_cash = accumulations[0] ? accumulations[0].cash_in_store : 0;
63
+ const difference = closing_amount - current_cash;
64
+ await this.createPettyCashTransactions([{
65
+ store_id,
66
+ employee_id,
67
+ transaction_type: "close",
68
+ entry_type: "DB",
69
+ source: null,
70
+ amount: closing_amount,
71
+ opening_balance: current_cash,
72
+ closing_balance: closing_amount,
73
+ expense_amount: 0,
74
+ difference_amount: difference,
75
+ category: null,
76
+ sub_category: null,
77
+ reason: null,
78
+ image_url: null,
79
+ date: new Date(),
80
+ metadata: null,
81
+ }]);
82
+ this.logger_.info("cms.day_ended", { store_id, employee_id, closing_amount, difference });
83
+ }
84
+ async handover(input) {
85
+ const { store_id, handover_amount, type } = input;
86
+ if (handover_amount < 0) {
87
+ throw new Error("[retailos/cms] handover_amount must be >= 0");
88
+ }
89
+ const [created] = await this.createCmsHandovers([{
90
+ store_id,
91
+ employee_id: input.employee_id,
92
+ handover_id: input.handover_id ?? null,
93
+ handover_amount,
94
+ total_cash: input.total_cash ?? null,
95
+ type: type ?? null,
96
+ image_url: input.image_url ?? null,
97
+ remark: input.remark ?? null,
98
+ metadata: input.metadata ?? null,
99
+ }]);
100
+ const accumulations = await this.listCmsAccumulations({ store_id: [store_id] });
101
+ const current = accumulations[0] ? accumulations[0].cash_in_store : 0;
102
+ let updated_cash = current;
103
+ if (type === "CR") {
104
+ updated_cash = current + handover_amount;
105
+ }
106
+ else if (type === "DB") {
107
+ updated_cash = current - handover_amount;
108
+ }
109
+ if (accumulations.length === 0) {
110
+ await this.createCmsAccumulations([{ store_id, cash_in_store: updated_cash }]);
111
+ }
112
+ else {
113
+ await this.updateCmsAccumulations([{ id: accumulations[0].id, cash_in_store: updated_cash }]);
114
+ }
115
+ this.logger_.info("[retailos/cms] handover created", {
116
+ id: created?.id,
117
+ store_id,
118
+ handover_amount,
119
+ type,
120
+ });
121
+ return created;
122
+ }
123
+ async addPettyCash(input) {
124
+ const { store_id, employee_id, amount, source } = input;
125
+ if (amount <= 0) {
126
+ throw new Error("[retailos/cms] amount must be > 0");
127
+ }
128
+ const existing = await this.listPettyCashes({ store_id: [store_id] });
129
+ const current_balance = existing[0] ? existing[0].balance : 0;
130
+ const new_balance = current_balance + amount;
131
+ if (existing.length === 0) {
132
+ await this.createPettyCashes([{ store_id, balance: new_balance }]);
133
+ }
134
+ else {
135
+ await this.updatePettyCashes([{ id: existing[0].id, balance: new_balance }]);
136
+ }
137
+ const [tx] = await this.createPettyCashTransactions([{
138
+ store_id,
139
+ employee_id,
140
+ transaction_type: "petty_cash",
141
+ entry_type: "CR",
142
+ source: source ?? null,
143
+ amount,
144
+ opening_balance: current_balance,
145
+ closing_balance: new_balance,
146
+ expense_amount: 0,
147
+ difference_amount: 0,
148
+ category: null,
149
+ sub_category: null,
150
+ reason: null,
151
+ image_url: null,
152
+ date: new Date(),
153
+ metadata: null,
154
+ }]);
155
+ this.logger_.info("[retailos/cms] petty cash added", { store_id, amount, new_balance });
156
+ return tx;
157
+ }
158
+ async addExpense(input) {
159
+ const { store_id, employee_id, amount } = input;
160
+ if (amount <= 0) {
161
+ throw new Error("[retailos/cms] expense amount must be > 0");
162
+ }
163
+ const existing = await this.listPettyCashes({ store_id: [store_id] });
164
+ const current_balance = existing[0] ? existing[0].balance : 0;
165
+ const new_balance = current_balance - amount;
166
+ if (existing.length === 0) {
167
+ await this.createPettyCashes([{ store_id, balance: new_balance }]);
168
+ }
169
+ else {
170
+ await this.updatePettyCashes([{ id: existing[0].id, balance: new_balance }]);
171
+ }
172
+ const [tx] = await this.createPettyCashTransactions([{
173
+ store_id,
174
+ employee_id,
175
+ transaction_type: "petty_cash",
176
+ entry_type: "DB",
177
+ source: null,
178
+ amount,
179
+ opening_balance: current_balance,
180
+ closing_balance: new_balance,
181
+ expense_amount: amount,
182
+ difference_amount: 0,
183
+ category: input.category ?? null,
184
+ sub_category: input.sub_category ?? null,
185
+ reason: input.reason ?? null,
186
+ image_url: input.image_url ?? null,
187
+ date: new Date(),
188
+ metadata: input.metadata ?? null,
189
+ }]);
190
+ this.logger_.info("[retailos/cms] expense recorded", { store_id, amount, category: input.category });
191
+ return tx;
192
+ }
193
+ async getAccumulation(store_id) {
194
+ const rows = await this.listCmsAccumulations({ store_id: [store_id] });
195
+ return rows[0] ?? null;
196
+ }
197
+ async getShiftLogs(filters) {
198
+ const dbFilters = {};
199
+ if (filters.store_id)
200
+ dbFilters.store_id = [filters.store_id];
201
+ dbFilters.transaction_type = ["open", "close"];
202
+ const rows = await this.listPettyCashTransactions(dbFilters, {
203
+ take: filters.limit ?? 100,
204
+ order: { created_at: "DESC" },
205
+ });
206
+ return rows;
207
+ }
208
+ }
209
+ exports.default = CmsModuleService;
210
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY21zLW1vZHVsZS1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21vZHVsZXMvY21zL3NlcnZpY2VzL2Ntcy1tb2R1bGUtc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHFEQUF5RDtBQUN6RCw4Q0FBbUU7QUFDbkUsMEVBQWdEO0FBQ2hELGtGQUF3RDtBQUN4RCxzRUFBNEM7QUFDNUMsOEZBQW1FO0FBd0RuRSxNQUFNLGdCQUFpQixTQUFRLElBQUEscUJBQWEsRUFBQztJQUMzQyxXQUFXLEVBQVgsc0JBQVc7SUFDWCxlQUFlLEVBQWYsMEJBQWU7SUFDZixTQUFTLEVBQVQsb0JBQVM7SUFDVCxvQkFBb0IsRUFBcEIsZ0NBQW9CO0NBQ3JCLENBQUM7SUFHQSxZQUFZLEdBQUcsSUFBVztRQUN4QixLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQTtRQUNkLE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBd0IsQ0FBQTtRQUN4RCxJQUFJLENBQUMsT0FBTyxHQUFHLFNBQVMsQ0FBQyxNQUFNLElBQUksSUFBQSx1QkFBZ0IsR0FBRSxDQUFBO1FBQ3JELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUE7SUFDMUQsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBb0I7UUFDakMsTUFBTSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLEdBQUcsS0FBSyxDQUFBO1FBQ3ZELElBQUksY0FBYyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsNENBQTRDLENBQUMsQ0FBQTtRQUMvRCxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFB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
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CmsModuleService = void 0;
7
+ var cms_module_service_1 = require("./cms-module-service");
8
+ Object.defineProperty(exports, "CmsModuleService", { enumerable: true, get: function () { return __importDefault(cms_module_service_1).default; } });
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9jbXMvc2VydmljZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsMkRBQWtFO0FBQXpELHVJQUFBLE9BQU8sT0FBb0IifQ==
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @devx-retailos/cms
2
+
3
+ Cash Management System (CMS) for retailOS. Manages shift operations, cash handovers, petty cash, and in-store cash accumulation for POS stores.
4
+
5
+ Covers the full cash lifecycle for a shift: open → intraday handovers and petty-cash movements → close, with a running per-store accumulation balance.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pnpm add @devx-retailos/cms
13
+ ```
14
+
15
+ Register in `medusa-config.ts`:
16
+
17
+ ```ts
18
+ import { CmsModule } from "@devx-retailos/cms"
19
+
20
+ export default defineConfig({
21
+ modules: [
22
+ {
23
+ resolve: "@devx-retailos/cms",
24
+ options: {},
25
+ },
26
+ ],
27
+ })
28
+ ```
29
+
30
+ Sync permissions at startup (alongside other retailOS modules):
31
+
32
+ ```ts
33
+ import { CMS_PERMISSIONS } from "@devx-retailos/cms"
34
+ import { syncAllPermissions } from "@devx-retailos/rbac"
35
+
36
+ await syncAllPermissions([...CMS_PERMISSIONS])
37
+ ```
38
+
39
+ Run migrations after adding the module:
40
+
41
+ ```bash
42
+ medusa plugin:db:generate @devx-retailos/cms
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Configuration
48
+
49
+ No plugin options are required. The module registers under the identifier `"cms"` and is fully configured through Medusa's dependency injection system.
50
+
51
+ ---
52
+
53
+ ## Usage
54
+
55
+ Resolve the service from the Medusa container:
56
+
57
+ ```ts
58
+ import { CMS_MODULE } from "@devx-retailos/cms"
59
+ import type { CmsModuleService } from "@devx-retailos/cms"
60
+
61
+ const cmsService: CmsModuleService = container.resolve(CMS_MODULE)
62
+ ```
63
+
64
+ ### Shift operations
65
+
66
+ ```ts
67
+ // Open a shift
68
+ await cmsService.dayStart({
69
+ store_id: "store_01",
70
+ employee_id: "emp_01",
71
+ opening_amount: 5000,
72
+ })
73
+
74
+ // Close a shift
75
+ await cmsService.dayEnd({
76
+ store_id: "store_01",
77
+ employee_id: "emp_01",
78
+ closing_amount: 4800,
79
+ })
80
+ ```
81
+
82
+ ### Cash handover
83
+
84
+ ```ts
85
+ const handover = await cmsService.handover({
86
+ store_id: "store_01",
87
+ employee_id: "emp_01",
88
+ handover_amount: 2000,
89
+ type: "CR", // "CR" = cash coming in, "DB" = cash going out
90
+ remark: "shift change",
91
+ })
92
+ ```
93
+
94
+ ### Petty cash
95
+
96
+ ```ts
97
+ // Add petty cash
98
+ await cmsService.addPettyCash({
99
+ store_id: "store_01",
100
+ employee_id: "emp_01",
101
+ amount: 500,
102
+ source: "self", // "self" | "from_petty_cash"
103
+ })
104
+
105
+ // Record an expense
106
+ await cmsService.addExpense({
107
+ store_id: "store_01",
108
+ employee_id: "emp_01",
109
+ amount: 150,
110
+ category: "supplies",
111
+ sub_category: "stationery",
112
+ reason: "pens and paper",
113
+ })
114
+ ```
115
+
116
+ ### Queries
117
+
118
+ ```ts
119
+ // Current in-store cash balance
120
+ const accumulation = await cmsService.getAccumulation("store_01")
121
+
122
+ // Shift open/close log
123
+ const logs = await cmsService.getShiftLogs({
124
+ store_id: "store_01",
125
+ from: new Date("2024-01-01"),
126
+ to: new Date("2024-01-31"),
127
+ limit: 50,
128
+ })
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Permissions
134
+
135
+ | Key | Description |
136
+ |-----|-------------|
137
+ | `cms.handover.read` | View cash handover records |
138
+ | `cms.handover.create` | Create a cash handover record |
139
+ | `cms.shift.operate` | Open and close a shift (day start / day end) |
140
+ | `cms.petty_cash.read` | View petty cash balance and transactions |
141
+ | `cms.petty_cash.operate` | Add petty cash or record expenses |
142
+ | `cms.accumulation.read` | View current cash accumulation for a store |
143
+
144
+ ---
145
+
146
+ ## Extension points
147
+
148
+ This module has no pluggable adapters or strategy interfaces. All cash logic is handled internally by `CmsModuleService`.
149
+
150
+ Module links — resolved automatically by Medusa's link layer:
151
+
152
+ | Link | Cardinality |
153
+ |------|-------------|
154
+ | Store → CmsHandover | 1:N |
155
+ | Employee → CmsHandover | 1:N |
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@devx-retailos/cms",
3
+ "version": "0.0.1",
4
+ "description": "Cash Management System for retailOS: shift ops, handovers, petty cash, accumulation.",
5
+ "license": "MIT",
6
+ "main": "./.medusa/server/src/modules/cms/index.js",
7
+ "types": "./.medusa/server/src/modules/cms/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./.medusa/server/src/modules/cms/index.d.ts",
11
+ "import": "./.medusa/server/src/modules/cms/index.js",
12
+ "require": "./.medusa/server/src/modules/cms/index.js"
13
+ },
14
+ "./permissions": {
15
+ "types": "./.medusa/server/src/modules/cms/permissions.d.ts",
16
+ "import": "./.medusa/server/src/modules/cms/permissions.js",
17
+ "require": "./.medusa/server/src/modules/cms/permissions.js"
18
+ },
19
+ "./package.json": "./package.json",
20
+ "./.medusa/server/src/modules/cms": "./.medusa/server/src/modules/cms/index.js",
21
+ "./.medusa/server/src/modules/cms/*": "./.medusa/server/src/modules/cms/*"
22
+ },
23
+ "files": [
24
+ ".medusa",
25
+ "src"
26
+ ],
27
+ "dependencies": {
28
+ "@devx-retailos/core": "0.0.2",
29
+ "@devx-retailos/employee": "0.0.3",
30
+ "@devx-retailos/rbac": "0.0.2"
31
+ },
32
+ "peerDependencies": {
33
+ "@medusajs/framework": "^2.15.0",
34
+ "@medusajs/medusa": "^2.15.0"
35
+ },
36
+ "devDependencies": {
37
+ "@medusajs/admin-sdk": "2.15.5",
38
+ "@medusajs/admin-shared": "2.15.5",
39
+ "@medusajs/cli": "2.15.5",
40
+ "@medusajs/framework": "2.15.5",
41
+ "@medusajs/medusa": "2.15.5",
42
+ "typescript": "^5.7.2",
43
+ "zod": "^3.23.0"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "sideEffects": false,
49
+ "keywords": [
50
+ "medusa-plugin"
51
+ ],
52
+ "scripts": {
53
+ "build": "medusa plugin:build",
54
+ "develop": "medusa plugin:develop",
55
+ "db:generate": "medusa plugin:db:generate",
56
+ "test": "vitest run",
57
+ "typecheck": "tsc --noEmit",
58
+ "clean": "rm -rf .medusa dist .turbo *.tsbuildinfo"
59
+ }
60
+ }
File without changes
@@ -0,0 +1,68 @@
1
+ import { describe, it, expect, vi } from "vitest"
2
+ import { GET } from "../route"
3
+
4
+ function makeService() {
5
+ return {
6
+ getAccumulation: vi.fn(),
7
+ }
8
+ }
9
+
10
+ function makeReq(params: Record<string, string>, service = makeService()) {
11
+ return {
12
+ params,
13
+ scope: {
14
+ resolve: vi.fn().mockImplementation((key: string) => {
15
+ if (key === "cms") return service
16
+ throw new Error("not found")
17
+ }),
18
+ },
19
+ _service: service,
20
+ }
21
+ }
22
+
23
+ function makeRes() {
24
+ return {
25
+ status: vi.fn().mockReturnThis(),
26
+ json: vi.fn().mockReturnThis(),
27
+ }
28
+ }
29
+
30
+ describe("GET /accumulation/[storeId]", () => {
31
+ it("returns accumulation when it exists", async () => {
32
+ const service = makeService()
33
+ const accumulation = { id: "cmsa_1", store_id: "s1", cash_in_store: 750 }
34
+ service.getAccumulation.mockResolvedValue(accumulation)
35
+ const req = makeReq({ storeId: "s1" }, service)
36
+ const res = makeRes()
37
+
38
+ await GET(req as any, res as any)
39
+
40
+ expect(service.getAccumulation).toHaveBeenCalledWith("s1")
41
+ expect(res.status).toHaveBeenCalledWith(200)
42
+ expect(res.json).toHaveBeenCalledWith({ accumulation })
43
+ })
44
+
45
+ it("returns default zero accumulation when none exists", async () => {
46
+ const service = makeService()
47
+ service.getAccumulation.mockResolvedValue(null)
48
+ const req = makeReq({ storeId: "s1" }, service)
49
+ const res = makeRes()
50
+
51
+ await GET(req as any, res as any)
52
+
53
+ expect(res.status).toHaveBeenCalledWith(200)
54
+ expect(res.json).toHaveBeenCalledWith({ accumulation: { store_id: "s1", cash_in_store: 0 } })
55
+ })
56
+
57
+ it("returns 500 when service throws", async () => {
58
+ const service = makeService()
59
+ service.getAccumulation.mockRejectedValue(new Error("db error"))
60
+ const req = makeReq({ storeId: "s1" }, service)
61
+ const res = makeRes()
62
+
63
+ await GET(req as any, res as any)
64
+
65
+ expect(res.status).toHaveBeenCalledWith(500)
66
+ expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ code: "INTERNAL_ERROR" }))
67
+ })
68
+ })