@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.
- package/.medusa/server/src/admin/index.js +23 -0
- package/.medusa/server/src/admin/index.mjs +24 -0
- package/.medusa/server/src/api/admin/retailos/cms/accumulation/[storeId]/route.js +34 -0
- package/.medusa/server/src/api/admin/retailos/cms/export/route.js +52 -0
- package/.medusa/server/src/api/admin/retailos/cms/handovers/[id]/route.js +35 -0
- package/.medusa/server/src/api/admin/retailos/cms/handovers/route.js +78 -0
- package/.medusa/server/src/api/admin/retailos/cms/operation/route.js +124 -0
- package/.medusa/server/src/api/admin/retailos/cms/petty-cash/route.js +31 -0
- package/.medusa/server/src/api/admin/retailos/cms/shift-logs/route.js +36 -0
- package/.medusa/server/src/links/employee-to-cms-handover.js +13 -0
- package/.medusa/server/src/links/store-to-cms-handover.js +13 -0
- package/.medusa/server/src/modules/cms/constants.js +5 -0
- package/.medusa/server/src/modules/cms/index.js +53 -0
- package/.medusa/server/src/modules/cms/migrations/Migration20260622000000.js +30 -0
- package/.medusa/server/src/modules/cms/migrations/Migration20260622000001.js +16 -0
- package/.medusa/server/src/modules/cms/models/cms-accumulation.js +11 -0
- package/.medusa/server/src/modules/cms/models/cms-handover.js +17 -0
- package/.medusa/server/src/modules/cms/models/index.js +15 -0
- package/.medusa/server/src/modules/cms/models/petty-cash-transaction.js +24 -0
- package/.medusa/server/src/modules/cms/models/petty-cash.js +11 -0
- package/.medusa/server/src/modules/cms/permissions.js +36 -0
- package/.medusa/server/src/modules/cms/services/cms-module-service.js +210 -0
- package/.medusa/server/src/modules/cms/services/index.js +9 -0
- package/README.md +155 -0
- package/package.json +60 -0
- package/src/admin/.gitkeep +0 -0
- package/src/api/admin/retailos/cms/accumulation/[storeId]/__tests__/route.test.ts +68 -0
- package/src/api/admin/retailos/cms/accumulation/[storeId]/route.ts +35 -0
- package/src/api/admin/retailos/cms/export/__tests__/route.test.ts +126 -0
- package/src/api/admin/retailos/cms/export/route.ts +58 -0
- package/src/api/admin/retailos/cms/handovers/[id]/__tests__/route.test.ts +68 -0
- package/src/api/admin/retailos/cms/handovers/[id]/route.ts +36 -0
- package/src/api/admin/retailos/cms/handovers/__tests__/route.test.ts +104 -0
- package/src/api/admin/retailos/cms/handovers/route.ts +79 -0
- package/src/api/admin/retailos/cms/operation/__tests__/route.test.ts +169 -0
- package/src/api/admin/retailos/cms/operation/route.ts +130 -0
- package/src/api/admin/retailos/cms/petty-cash/__tests__/route.test.ts +73 -0
- package/src/api/admin/retailos/cms/petty-cash/route.ts +35 -0
- package/src/api/admin/retailos/cms/shift-logs/__tests__/route.test.ts +77 -0
- package/src/api/admin/retailos/cms/shift-logs/route.ts +38 -0
- package/src/links/employee-to-cms-handover.ts +11 -0
- package/src/links/store-to-cms-handover.ts +11 -0
- package/src/modules/cms/__tests__/cms-module-service.test.ts +333 -0
- package/src/modules/cms/__tests__/permissions.test.ts +36 -0
- package/src/modules/cms/constants.ts +1 -0
- package/src/modules/cms/index.ts +24 -0
- package/src/modules/cms/migrations/Migration20260622000000.ts +58 -0
- package/src/modules/cms/migrations/Migration20260622000001.ts +17 -0
- package/src/modules/cms/models/cms-accumulation.ts +10 -0
- package/src/modules/cms/models/cms-handover.ts +16 -0
- package/src/modules/cms/models/index.ts +4 -0
- package/src/modules/cms/models/petty-cash-transaction.ts +23 -0
- package/src/modules/cms/models/petty-cash.ts +10 -0
- package/src/modules/cms/permissions.ts +34 -0
- package/src/modules/cms/services/cms-module-service.ts +284 -0
- package/src/modules/cms/services/index.ts +13 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { MedusaService } from "@medusajs/framework/utils"
|
|
2
|
+
import { createNoopLogger, type Logger } from "@devx-retailos/core"
|
|
3
|
+
import CmsHandover from "../models/cms-handover"
|
|
4
|
+
import CmsAccumulation from "../models/cms-accumulation"
|
|
5
|
+
import PettyCash from "../models/petty-cash"
|
|
6
|
+
import PettyCashTransaction from "../models/petty-cash-transaction"
|
|
7
|
+
|
|
8
|
+
export type HandoverType = "DB" | "CR"
|
|
9
|
+
export type TransactionType = "open" | "close" | "petty_cash"
|
|
10
|
+
export type EntryType = "DB" | "CR"
|
|
11
|
+
export type PettyCashSource = "self" | "from_petty_cash"
|
|
12
|
+
|
|
13
|
+
export interface DayStartInput {
|
|
14
|
+
store_id: string
|
|
15
|
+
employee_id: string
|
|
16
|
+
opening_amount: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DayEndInput {
|
|
20
|
+
store_id: string
|
|
21
|
+
employee_id: string
|
|
22
|
+
closing_amount: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface HandoverInput {
|
|
26
|
+
store_id: string
|
|
27
|
+
employee_id: string
|
|
28
|
+
handover_id?: string | null
|
|
29
|
+
handover_amount: number
|
|
30
|
+
total_cash?: number | null
|
|
31
|
+
type?: HandoverType | null
|
|
32
|
+
image_url?: string | null
|
|
33
|
+
remark?: string | null
|
|
34
|
+
metadata?: Record<string, unknown> | null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AddPettyCashInput {
|
|
38
|
+
store_id: string
|
|
39
|
+
employee_id: string
|
|
40
|
+
amount: number
|
|
41
|
+
source?: PettyCashSource | null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface AddExpenseInput {
|
|
45
|
+
store_id: string
|
|
46
|
+
employee_id: string
|
|
47
|
+
amount: number
|
|
48
|
+
category?: string | null
|
|
49
|
+
sub_category?: string | null
|
|
50
|
+
reason?: string | null
|
|
51
|
+
image_url?: string | null
|
|
52
|
+
metadata?: Record<string, unknown> | null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ShiftLogFilters {
|
|
56
|
+
store_id?: string
|
|
57
|
+
from?: Date
|
|
58
|
+
to?: Date
|
|
59
|
+
limit?: number
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class CmsModuleService extends MedusaService({
|
|
63
|
+
CmsHandover,
|
|
64
|
+
CmsAccumulation,
|
|
65
|
+
PettyCash,
|
|
66
|
+
PettyCashTransaction,
|
|
67
|
+
}) {
|
|
68
|
+
protected logger_: Logger
|
|
69
|
+
|
|
70
|
+
constructor(...args: any[]) {
|
|
71
|
+
super(...args)
|
|
72
|
+
const container = (args[0] ?? {}) as { logger?: Logger }
|
|
73
|
+
this.logger_ = container.logger ?? createNoopLogger()
|
|
74
|
+
this.logger_.debug("[retailos/cms] service initialized")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async dayStart(input: DayStartInput): Promise<void> {
|
|
78
|
+
const { store_id, employee_id, opening_amount } = input
|
|
79
|
+
if (opening_amount < 0) {
|
|
80
|
+
throw new Error("[retailos/cms] opening_amount must be >= 0")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const existing = await this.listCmsAccumulations({ store_id: [store_id] })
|
|
84
|
+
if (existing.length === 0) {
|
|
85
|
+
await this.createCmsAccumulations([{ store_id, cash_in_store: opening_amount }])
|
|
86
|
+
} else {
|
|
87
|
+
await this.updateCmsAccumulations([{ id: (existing[0] as any).id, cash_in_store: opening_amount }])
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await this.createPettyCashTransactions([{
|
|
91
|
+
store_id,
|
|
92
|
+
employee_id,
|
|
93
|
+
transaction_type: "open" as TransactionType,
|
|
94
|
+
entry_type: "CR" as EntryType,
|
|
95
|
+
source: null,
|
|
96
|
+
amount: opening_amount,
|
|
97
|
+
opening_balance: opening_amount,
|
|
98
|
+
closing_balance: null,
|
|
99
|
+
expense_amount: 0,
|
|
100
|
+
difference_amount: 0,
|
|
101
|
+
category: null,
|
|
102
|
+
sub_category: null,
|
|
103
|
+
reason: null,
|
|
104
|
+
image_url: null,
|
|
105
|
+
date: new Date(),
|
|
106
|
+
metadata: null,
|
|
107
|
+
}])
|
|
108
|
+
|
|
109
|
+
this.logger_.info("cms.day_started", { store_id, employee_id, opening_amount })
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async dayEnd(input: DayEndInput): Promise<void> {
|
|
113
|
+
const { store_id, employee_id, closing_amount } = input
|
|
114
|
+
if (closing_amount < 0) {
|
|
115
|
+
throw new Error("[retailos/cms] closing_amount must be >= 0")
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const accumulations = await this.listCmsAccumulations({ store_id: [store_id] })
|
|
119
|
+
const current_cash = accumulations[0] ? (accumulations[0] as any).cash_in_store : 0
|
|
120
|
+
const difference = closing_amount - current_cash
|
|
121
|
+
|
|
122
|
+
await this.createPettyCashTransactions([{
|
|
123
|
+
store_id,
|
|
124
|
+
employee_id,
|
|
125
|
+
transaction_type: "close" as TransactionType,
|
|
126
|
+
entry_type: "DB" as EntryType,
|
|
127
|
+
source: null,
|
|
128
|
+
amount: closing_amount,
|
|
129
|
+
opening_balance: current_cash,
|
|
130
|
+
closing_balance: closing_amount,
|
|
131
|
+
expense_amount: 0,
|
|
132
|
+
difference_amount: difference,
|
|
133
|
+
category: null,
|
|
134
|
+
sub_category: null,
|
|
135
|
+
reason: null,
|
|
136
|
+
image_url: null,
|
|
137
|
+
date: new Date(),
|
|
138
|
+
metadata: null,
|
|
139
|
+
}])
|
|
140
|
+
|
|
141
|
+
this.logger_.info("cms.day_ended", { store_id, employee_id, closing_amount, difference })
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async handover(input: HandoverInput) {
|
|
145
|
+
const { store_id, handover_amount, type } = input
|
|
146
|
+
if (handover_amount < 0) {
|
|
147
|
+
throw new Error("[retailos/cms] handover_amount must be >= 0")
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const [created] = await this.createCmsHandovers([{
|
|
151
|
+
store_id,
|
|
152
|
+
employee_id: input.employee_id,
|
|
153
|
+
handover_id: input.handover_id ?? null,
|
|
154
|
+
handover_amount,
|
|
155
|
+
total_cash: input.total_cash ?? null,
|
|
156
|
+
type: type ?? null,
|
|
157
|
+
image_url: input.image_url ?? null,
|
|
158
|
+
remark: input.remark ?? null,
|
|
159
|
+
metadata: input.metadata ?? null,
|
|
160
|
+
}])
|
|
161
|
+
|
|
162
|
+
const accumulations = await this.listCmsAccumulations({ store_id: [store_id] })
|
|
163
|
+
const current = accumulations[0] ? (accumulations[0] as any).cash_in_store : 0
|
|
164
|
+
|
|
165
|
+
let updated_cash = current
|
|
166
|
+
if (type === "CR") {
|
|
167
|
+
updated_cash = current + handover_amount
|
|
168
|
+
} else if (type === "DB") {
|
|
169
|
+
updated_cash = current - handover_amount
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (accumulations.length === 0) {
|
|
173
|
+
await this.createCmsAccumulations([{ store_id, cash_in_store: updated_cash }])
|
|
174
|
+
} else {
|
|
175
|
+
await this.updateCmsAccumulations([{ id: (accumulations[0] as any).id, cash_in_store: updated_cash }])
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.logger_.info("[retailos/cms] handover created", {
|
|
179
|
+
id: (created as any)?.id,
|
|
180
|
+
store_id,
|
|
181
|
+
handover_amount,
|
|
182
|
+
type,
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
return created
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async addPettyCash(input: AddPettyCashInput) {
|
|
189
|
+
const { store_id, employee_id, amount, source } = input
|
|
190
|
+
if (amount <= 0) {
|
|
191
|
+
throw new Error("[retailos/cms] amount must be > 0")
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const existing = await this.listPettyCashes({ store_id: [store_id] })
|
|
195
|
+
const current_balance = existing[0] ? (existing[0] as any).balance : 0
|
|
196
|
+
const new_balance = current_balance + amount
|
|
197
|
+
|
|
198
|
+
if (existing.length === 0) {
|
|
199
|
+
await this.createPettyCashes([{ store_id, balance: new_balance }])
|
|
200
|
+
} else {
|
|
201
|
+
await this.updatePettyCashes([{ id: (existing[0] as any).id, balance: new_balance }])
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const [tx] = await this.createPettyCashTransactions([{
|
|
205
|
+
store_id,
|
|
206
|
+
employee_id,
|
|
207
|
+
transaction_type: "petty_cash" as TransactionType,
|
|
208
|
+
entry_type: "CR" as EntryType,
|
|
209
|
+
source: source ?? null,
|
|
210
|
+
amount,
|
|
211
|
+
opening_balance: current_balance,
|
|
212
|
+
closing_balance: new_balance,
|
|
213
|
+
expense_amount: 0,
|
|
214
|
+
difference_amount: 0,
|
|
215
|
+
category: null,
|
|
216
|
+
sub_category: null,
|
|
217
|
+
reason: null,
|
|
218
|
+
image_url: null,
|
|
219
|
+
date: new Date(),
|
|
220
|
+
metadata: null,
|
|
221
|
+
}])
|
|
222
|
+
|
|
223
|
+
this.logger_.info("[retailos/cms] petty cash added", { store_id, amount, new_balance })
|
|
224
|
+
return tx
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async addExpense(input: AddExpenseInput) {
|
|
228
|
+
const { store_id, employee_id, amount } = input
|
|
229
|
+
if (amount <= 0) {
|
|
230
|
+
throw new Error("[retailos/cms] expense amount must be > 0")
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const existing = await this.listPettyCashes({ store_id: [store_id] })
|
|
234
|
+
const current_balance = existing[0] ? (existing[0] as any).balance : 0
|
|
235
|
+
const new_balance = current_balance - amount
|
|
236
|
+
|
|
237
|
+
if (existing.length === 0) {
|
|
238
|
+
await this.createPettyCashes([{ store_id, balance: new_balance }])
|
|
239
|
+
} else {
|
|
240
|
+
await this.updatePettyCashes([{ id: (existing[0] as any).id, balance: new_balance }])
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const [tx] = await this.createPettyCashTransactions([{
|
|
244
|
+
store_id,
|
|
245
|
+
employee_id,
|
|
246
|
+
transaction_type: "petty_cash" as TransactionType,
|
|
247
|
+
entry_type: "DB" as EntryType,
|
|
248
|
+
source: null,
|
|
249
|
+
amount,
|
|
250
|
+
opening_balance: current_balance,
|
|
251
|
+
closing_balance: new_balance,
|
|
252
|
+
expense_amount: amount,
|
|
253
|
+
difference_amount: 0,
|
|
254
|
+
category: input.category ?? null,
|
|
255
|
+
sub_category: input.sub_category ?? null,
|
|
256
|
+
reason: input.reason ?? null,
|
|
257
|
+
image_url: input.image_url ?? null,
|
|
258
|
+
date: new Date(),
|
|
259
|
+
metadata: input.metadata ?? null,
|
|
260
|
+
}])
|
|
261
|
+
|
|
262
|
+
this.logger_.info("[retailos/cms] expense recorded", { store_id, amount, category: input.category })
|
|
263
|
+
return tx
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async getAccumulation(store_id: string) {
|
|
267
|
+
const rows = await this.listCmsAccumulations({ store_id: [store_id] })
|
|
268
|
+
return rows[0] ?? null
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async getShiftLogs(filters: ShiftLogFilters) {
|
|
272
|
+
const dbFilters: Record<string, unknown> = {}
|
|
273
|
+
if (filters.store_id) dbFilters.store_id = [filters.store_id]
|
|
274
|
+
dbFilters.transaction_type = ["open", "close"]
|
|
275
|
+
|
|
276
|
+
const rows = await this.listPettyCashTransactions(dbFilters, {
|
|
277
|
+
take: filters.limit ?? 100,
|
|
278
|
+
order: { created_at: "DESC" } as any,
|
|
279
|
+
})
|
|
280
|
+
return rows
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export default CmsModuleService
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { default as CmsModuleService } from "./cms-module-service"
|
|
2
|
+
export type {
|
|
3
|
+
DayStartInput,
|
|
4
|
+
DayEndInput,
|
|
5
|
+
HandoverInput,
|
|
6
|
+
AddPettyCashInput,
|
|
7
|
+
AddExpenseInput,
|
|
8
|
+
ShiftLogFilters,
|
|
9
|
+
HandoverType,
|
|
10
|
+
TransactionType,
|
|
11
|
+
EntryType,
|
|
12
|
+
PettyCashSource,
|
|
13
|
+
} from "./cms-module-service"
|