washday-sdk 1.0.2 → 1.1.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 (254) hide show
  1. package/README.md +127 -0
  2. package/babel.config.js +8 -0
  3. package/dist/api/attendance/delete.js +2 -0
  4. package/dist/api/attendance/get.js +89 -0
  5. package/dist/api/attendance/index.js +4 -0
  6. package/dist/api/attendance/post.js +39 -0
  7. package/dist/api/attendance/put.js +25 -0
  8. package/dist/api/auth/index.js +3 -0
  9. package/dist/api/auth/post.js +170 -0
  10. package/dist/api/axiosInstance.js +15 -11
  11. package/dist/api/cashierbox/delete.js +40 -0
  12. package/dist/api/cashierbox/get.js +63 -0
  13. package/dist/api/cashierbox/post.js +42 -0
  14. package/dist/api/cashierbox/put.js +42 -0
  15. package/dist/api/cashups/delete.js +25 -0
  16. package/dist/api/cashups/get.js +60 -0
  17. package/dist/api/cashups/index.js +4 -0
  18. package/dist/api/cashups/post.js +25 -0
  19. package/dist/api/cashups/put.js +52 -0
  20. package/dist/api/cfdi/delete.js +25 -0
  21. package/dist/api/cfdi/get.js +126 -0
  22. package/dist/api/cfdi/index.js +4 -0
  23. package/dist/api/cfdi/post.js +41 -0
  24. package/dist/api/cfdi/put.js +52 -0
  25. package/dist/api/companies/get.js +29 -0
  26. package/dist/api/companies/post.js +41 -0
  27. package/dist/api/companies/put.js +57 -0
  28. package/dist/api/countries/get.js +29 -0
  29. package/dist/api/countries/post.js +1 -0
  30. package/dist/api/countries/put.js +1 -0
  31. package/dist/api/csv/get.js +325 -0
  32. package/dist/api/csv/index.js +1 -0
  33. package/dist/api/customers/delete.js +40 -0
  34. package/dist/api/customers/get.js +75 -20
  35. package/dist/api/customers/index.js +4 -1
  36. package/dist/api/customers/post.js +41 -0
  37. package/dist/api/customers/put.js +52 -0
  38. package/dist/api/discounts/get.js +120 -0
  39. package/dist/api/discounts/post.js +40 -0
  40. package/dist/api/discounts/put.js +68 -0
  41. package/dist/api/index.js +316 -8
  42. package/dist/api/inventory/delete.js +26 -0
  43. package/dist/api/inventory/get.js +62 -0
  44. package/dist/api/inventory/index.js +4 -0
  45. package/dist/api/inventory/post.js +26 -0
  46. package/dist/api/inventory/put.js +41 -0
  47. package/dist/api/order/delete.js +40 -0
  48. package/dist/api/order/get.js +181 -0
  49. package/dist/api/order/index.js +4 -0
  50. package/dist/api/order/post.js +115 -0
  51. package/dist/api/order/put.js +202 -0
  52. package/dist/api/outsourcedOrders/delete.js +25 -0
  53. package/dist/api/outsourcedOrders/get.js +62 -0
  54. package/dist/api/outsourcedOrders/index.js +4 -0
  55. package/dist/api/outsourcedOrders/post.js +25 -0
  56. package/dist/api/outsourcedOrders/put.js +25 -0
  57. package/dist/api/partners/delete.js +25 -0
  58. package/dist/api/partners/get.js +40 -0
  59. package/dist/api/partners/index.js +4 -0
  60. package/dist/api/partners/post.js +25 -0
  61. package/dist/api/partners/put.js +25 -0
  62. package/dist/api/pdf/get.js +43 -0
  63. package/dist/api/pdf/index.js +1 -0
  64. package/dist/api/products/delete.js +40 -0
  65. package/dist/api/products/get.js +25 -0
  66. package/dist/api/products/index.js +4 -0
  67. package/dist/api/products/post.js +60 -0
  68. package/dist/api/products/put.js +40 -0
  69. package/dist/api/publics/get.js +26 -0
  70. package/dist/api/publics/index.js +1 -0
  71. package/dist/api/reports/get.js +303 -0
  72. package/dist/api/reports/index.js +1 -0
  73. package/dist/api/reviews/delete.js +15 -0
  74. package/dist/api/reviews/get.js +41 -0
  75. package/dist/api/reviews/index.js +4 -0
  76. package/dist/api/reviews/post.js +20 -0
  77. package/dist/api/reviews/put.js +52 -0
  78. package/dist/api/routes/delete.js +25 -0
  79. package/dist/api/routes/get.js +95 -0
  80. package/dist/api/routes/index.js +4 -0
  81. package/dist/api/routes/post.js +67 -0
  82. package/dist/api/routes/put.js +54 -0
  83. package/dist/api/sections/delete.js +25 -0
  84. package/dist/api/sections/get.js +71 -0
  85. package/dist/api/sections/index.js +4 -0
  86. package/dist/api/sections/post.js +26 -0
  87. package/dist/api/sections/put.js +25 -0
  88. package/dist/api/staff/delete.js +26 -0
  89. package/dist/api/staff/get.js +40 -0
  90. package/dist/api/staff/post.js +26 -0
  91. package/dist/api/staff/put.js +26 -0
  92. package/dist/api/stores/get.js +110 -0
  93. package/dist/api/stores/post.js +61 -0
  94. package/dist/api/stores/put.js +44 -0
  95. package/dist/api/stripe/get.js +1 -0
  96. package/dist/api/stripe/post.js +71 -0
  97. package/dist/api/stripe/put.js +1 -0
  98. package/dist/api/supplies/delete.js +26 -0
  99. package/dist/api/supplies/get.js +62 -0
  100. package/dist/api/supplies/post.js +26 -0
  101. package/dist/api/supplies/put.js +41 -0
  102. package/dist/api/users/delete.js +26 -0
  103. package/dist/api/users/post.js +25 -0
  104. package/dist/api/users/put.js +29 -0
  105. package/dist/enum/index.js +12 -7
  106. package/dist/index.js +3 -33
  107. package/dist/interfaces/Api.js +1 -3
  108. package/dist/interfaces/Apple.js +16 -0
  109. package/dist/interfaces/Attendance.js +1 -0
  110. package/dist/interfaces/Customer.js +1 -2
  111. package/dist/interfaces/Order.js +1 -2
  112. package/dist/interfaces/Permission.js +1 -2
  113. package/dist/interfaces/Product.js +1 -2
  114. package/dist/interfaces/Section.js +1 -2
  115. package/dist/interfaces/Store.js +1 -2
  116. package/dist/interfaces/StoreImage.js +1 -2
  117. package/dist/interfaces/User.js +1 -2
  118. package/dist/utils/apiUtils.js +9 -0
  119. package/dist/utils/index.js +2 -17
  120. package/dist/utils/orders/calculateOrderTotal.js +30 -21
  121. package/dist/utils/orders/calculateTotalTaxesIncluded.js +55 -29
  122. package/dist/utils/orders/calculateTotalTaxesOverPrice.js +56 -45
  123. package/dist/utils/orders/helpers.js +126 -17
  124. package/dist/utils/orders/index.js +3 -5
  125. package/dist/utils/receipt/generateReceiptHTML.js +157 -0
  126. package/dist/utils/util.js +63 -0
  127. package/docs/README.md +67 -0
  128. package/docs/examples/common-use-cases.md +487 -0
  129. package/docs/getting-started.md +237 -0
  130. package/docs/modules/attendance.md +404 -0
  131. package/jest.config.js +0 -0
  132. package/package.json +12 -4
  133. package/src/api/attendance/delete.ts +1 -0
  134. package/src/api/attendance/get.ts +88 -0
  135. package/src/api/attendance/index.ts +4 -0
  136. package/src/api/attendance/post.ts +38 -0
  137. package/src/api/attendance/put.ts +20 -0
  138. package/src/api/auth/index.ts +3 -0
  139. package/src/api/auth/post.ts +198 -0
  140. package/src/api/axiosInstance.ts +13 -3
  141. package/src/api/cashierbox/delete.ts +28 -0
  142. package/src/api/cashierbox/get.ts +53 -0
  143. package/src/api/cashierbox/post.ts +39 -0
  144. package/src/api/cashierbox/put.ts +32 -0
  145. package/src/api/cashups/delete.ts +15 -0
  146. package/src/api/cashups/get.ts +52 -0
  147. package/src/api/cashups/index.ts +4 -0
  148. package/src/api/cashups/post.ts +23 -0
  149. package/src/api/cashups/put.ts +53 -0
  150. package/src/api/cfdi/delete.ts +21 -0
  151. package/src/api/cfdi/get.ts +119 -0
  152. package/src/api/cfdi/index.ts +4 -0
  153. package/src/api/cfdi/post.ts +60 -0
  154. package/src/api/cfdi/put.ts +53 -0
  155. package/src/api/companies/get.ts +23 -0
  156. package/src/api/companies/post.ts +29 -0
  157. package/src/api/companies/put.ts +43 -0
  158. package/src/api/countries/get.ts +23 -0
  159. package/src/api/countries/post.ts +0 -0
  160. package/src/api/countries/put.ts +0 -0
  161. package/src/api/csv/get.ts +354 -0
  162. package/src/api/csv/index.ts +1 -0
  163. package/src/api/customers/delete.ts +29 -0
  164. package/src/api/customers/get.ts +80 -8
  165. package/src/api/customers/index.ts +4 -0
  166. package/src/api/customers/post.ts +48 -0
  167. package/src/api/customers/put.ts +68 -0
  168. package/src/api/discounts/get.ts +100 -0
  169. package/src/api/discounts/post.ts +35 -0
  170. package/src/api/discounts/put.ts +66 -0
  171. package/src/api/index.ts +318 -11
  172. package/src/api/inventory/delete.ts +16 -0
  173. package/src/api/inventory/get.ts +53 -0
  174. package/src/api/inventory/index.ts +4 -0
  175. package/src/api/inventory/post.ts +22 -0
  176. package/src/api/inventory/put.ts +35 -0
  177. package/src/api/order/delete.ts +29 -0
  178. package/src/api/order/get.ts +207 -0
  179. package/src/api/order/index.ts +4 -0
  180. package/src/api/order/post.ts +118 -0
  181. package/src/api/order/put.ts +224 -0
  182. package/src/api/outsourcedOrders/delete.ts +15 -0
  183. package/src/api/outsourcedOrders/get.ts +54 -0
  184. package/src/api/outsourcedOrders/index.ts +4 -0
  185. package/src/api/outsourcedOrders/post.ts +24 -0
  186. package/src/api/outsourcedOrders/put.ts +21 -0
  187. package/src/api/partners/delete.ts +15 -0
  188. package/src/api/partners/get.ts +28 -0
  189. package/src/api/partners/index.ts +4 -0
  190. package/src/api/partners/post.ts +21 -0
  191. package/src/api/partners/put.ts +21 -0
  192. package/src/api/pdf/get.ts +43 -0
  193. package/src/api/pdf/index.ts +1 -0
  194. package/src/api/products/delete.ts +28 -0
  195. package/src/api/products/get.ts +16 -0
  196. package/src/api/products/index.ts +4 -0
  197. package/src/api/products/post.ts +73 -0
  198. package/src/api/products/put.ts +49 -0
  199. package/src/api/publics/get.ts +16 -0
  200. package/src/api/publics/index.ts +1 -0
  201. package/src/api/reports/get.ts +329 -0
  202. package/src/api/reports/index.ts +1 -0
  203. package/src/api/reviews/delete.ts +15 -0
  204. package/src/api/reviews/get.ts +31 -0
  205. package/src/api/reviews/index.ts +4 -0
  206. package/src/api/reviews/post.ts +20 -0
  207. package/src/api/reviews/put.ts +53 -0
  208. package/src/api/routes/delete.ts +15 -0
  209. package/src/api/routes/get.ts +86 -0
  210. package/src/api/routes/index.ts +4 -0
  211. package/src/api/routes/post.ts +60 -0
  212. package/src/api/routes/put.ts +44 -0
  213. package/src/api/sections/delete.ts +15 -0
  214. package/src/api/sections/get.ts +67 -0
  215. package/src/api/sections/index.ts +4 -0
  216. package/src/api/sections/post.ts +22 -0
  217. package/src/api/sections/put.ts +23 -0
  218. package/src/api/staff/delete.ts +16 -0
  219. package/src/api/staff/get.ts +29 -0
  220. package/src/api/staff/post.ts +17 -0
  221. package/src/api/staff/put.ts +17 -0
  222. package/src/api/stores/get.ts +93 -0
  223. package/src/api/stores/post.ts +49 -0
  224. package/src/api/stores/put.ts +35 -0
  225. package/src/api/stripe/get.ts +0 -0
  226. package/src/api/stripe/post.ts +59 -0
  227. package/src/api/stripe/put.ts +0 -0
  228. package/src/api/supplies/delete.ts +16 -0
  229. package/src/api/supplies/get.ts +53 -0
  230. package/src/api/supplies/post.ts +26 -0
  231. package/src/api/supplies/put.ts +33 -0
  232. package/src/api/users/delete.ts +16 -0
  233. package/src/api/users/post.ts +18 -0
  234. package/src/api/users/put.ts +36 -0
  235. package/src/enum/index.ts +9 -1
  236. package/src/index.ts +1 -4
  237. package/src/interfaces/Api.ts +307 -2
  238. package/src/interfaces/Apple.ts +74 -0
  239. package/src/interfaces/Attendance.ts +45 -0
  240. package/src/interfaces/Customer.ts +15 -11
  241. package/src/interfaces/Order.ts +38 -1
  242. package/src/interfaces/Product.ts +1 -0
  243. package/src/interfaces/Store.ts +41 -0
  244. package/src/utils/apiUtils.ts +11 -0
  245. package/src/utils/index.ts +6 -1
  246. package/src/utils/orders/calculateOrderTotal.test.js +930 -0
  247. package/src/utils/orders/calculateOrderTotal.ts +60 -15
  248. package/src/utils/orders/calculateTotalTaxesIncluded.ts +57 -25
  249. package/src/utils/orders/calculateTotalTaxesOverPrice.ts +57 -41
  250. package/src/utils/orders/helpers.ts +195 -47
  251. package/src/utils/orders/index.ts +3 -1
  252. package/src/utils/receipt/generateReceiptHTML.ts +163 -0
  253. package/src/utils/util.ts +65 -0
  254. package/tsconfig.json +13 -9
@@ -0,0 +1,404 @@
1
+ # 📋 Attendance Module
2
+
3
+ The Attendance module provides comprehensive employee time tracking functionality including clock-in/out, shift management, and reporting capabilities.
4
+
5
+ ## 🚀 Quick Start
6
+
7
+ ```typescript
8
+ import { WashdayClient } from 'washday-sdk';
9
+
10
+ const client = new WashdayClient('your-api-token');
11
+
12
+ // Clock in
13
+ await client.attendance.clockIn({
14
+ storeId: 'store-id-here',
15
+ notes: 'Starting shift'
16
+ });
17
+
18
+ // Check status
19
+ const status = await client.attendance.getStatus();
20
+ console.log(status); // { active: true, clockInTime: '2025-01-01T08:00:00.000Z' }
21
+ ```
22
+
23
+ ## 📝 Available Methods
24
+
25
+ ### 1. Clock In
26
+ Clock in to start a work shift at a specific store.
27
+
28
+ ```typescript
29
+ const clockInResult = await client.attendance.clockIn({
30
+ storeId: 'store-id-here', // Required: Store where employee is clocking in
31
+ userId: 'user-id-here', // Optional: Defaults to token user
32
+ ipAddress: '192.168.1.1', // Optional: Client IP address
33
+ notes: 'Starting shift' // Optional: Additional notes
34
+ });
35
+
36
+ // Response
37
+ console.log(clockInResult);
38
+ // {
39
+ // status: 201,
40
+ // data: {
41
+ // attendanceRecord: {
42
+ // _id: 'record-id',
43
+ // employee: 'user-id',
44
+ // store: 'store-id',
45
+ // type: 'IN',
46
+ // timestamp: '2025-01-01T08:00:00.000Z',
47
+ // notes: 'Starting shift'
48
+ // },
49
+ // message: 'Entrada registrada exitosamente'
50
+ // }
51
+ // }
52
+ ```
53
+
54
+ ### 2. Clock Out
55
+ Clock out to end the current work shift. The system automatically uses the same store as the last clock-in.
56
+
57
+ ```typescript
58
+ const clockOutResult = await client.attendance.clockOut({
59
+ userId: 'user-id-here', // Optional: Defaults to token user
60
+ ipAddress: '192.168.1.1', // Optional: Client IP address
61
+ notes: 'End of shift' // Optional: Additional notes
62
+ });
63
+
64
+ // Response
65
+ console.log(clockOutResult);
66
+ // {
67
+ // status: 201,
68
+ // data: {
69
+ // clockOutEntry: { /* OUT record */ },
70
+ // clockInEntry: { /* matching IN record */ },
71
+ // shiftDuration: {
72
+ // hours: 8,
73
+ // minutes: 30,
74
+ // totalMinutes: 510
75
+ // }
76
+ // }
77
+ // }
78
+ ```
79
+
80
+ ### 3. Get Attendance Status
81
+ Check if an employee has an active shift (clocked in without clocking out).
82
+
83
+ ```typescript
84
+ const statusResult = await client.attendance.getStatus({
85
+ storeId: 'store-id-here' // Optional: Check specific store, omit for all stores
86
+ });
87
+
88
+ // Active shift response
89
+ console.log(statusResult);
90
+ // {
91
+ // active: true,
92
+ // clockInTime: '2025-01-01T08:00:00.000Z',
93
+ // clockInStore: 'store-id'
94
+ // }
95
+
96
+ // No active shift response
97
+ // {
98
+ // active: false
99
+ // }
100
+ ```
101
+
102
+ ### 4. Get Attendance History
103
+ Retrieve attendance records with filtering and pagination.
104
+
105
+ ```typescript
106
+ const historyResult = await client.attendance.getHistory({
107
+ storeId: 'store-id-here', // Optional: Filter by store
108
+ startDate: '2025-01-01', // Optional: Start date (YYYY-MM-DD)
109
+ endDate: '2025-01-31', // Optional: End date (YYYY-MM-DD)
110
+ pageNum: '1', // Optional: Page number (default: 1)
111
+ limit: '50' // Optional: Records per page (default: 50)
112
+ });
113
+
114
+ // Response
115
+ console.log(historyResult);
116
+ // {
117
+ // attendanceRecords: [
118
+ // {
119
+ // _id: 'record-1',
120
+ // employee: { name: 'John Doe', _id: 'user-id' },
121
+ // store: { name: 'Main Store', _id: 'store-id' },
122
+ // type: 'IN',
123
+ // timestamp: '2025-01-01T08:00:00.000Z',
124
+ // notes: 'Starting shift'
125
+ // },
126
+ // {
127
+ // _id: 'record-2',
128
+ // employee: { name: 'John Doe', _id: 'user-id' },
129
+ // store: { name: 'Main Store', _id: 'store-id' },
130
+ // type: 'OUT',
131
+ // timestamp: '2025-01-01T17:00:00.000Z',
132
+ // notes: 'End of shift'
133
+ // }
134
+ // ],
135
+ // totalRecords: 100,
136
+ // currentPage: 1,
137
+ // totalPages: 2
138
+ // }
139
+ ```
140
+
141
+ ### 5. Get Store Report
142
+ Generate a comprehensive attendance report for a specific store.
143
+
144
+ ```typescript
145
+ const reportResult = await client.attendance.getStoreReport('store-id-here', {
146
+ startDate: '2025-01-01', // Optional: Report start date
147
+ endDate: '2025-01-31', // Optional: Report end date
148
+ pageNum: '1', // Optional: Page number
149
+ limit: '100' // Optional: Records per page
150
+ });
151
+
152
+ // Response
153
+ console.log(reportResult);
154
+ // {
155
+ // storeId: 'store-id',
156
+ // storeName: 'Main Store',
157
+ // employees: [
158
+ // {
159
+ // employee: {
160
+ // _id: 'user-id',
161
+ // name: 'John Doe',
162
+ // email: 'john@example.com'
163
+ // },
164
+ // records: [
165
+ // { type: 'IN', timestamp: '...', notes: '...' },
166
+ // { type: 'OUT', timestamp: '...', notes: '...' }
167
+ // ],
168
+ // totalHours: 160,
169
+ // totalShifts: 20
170
+ // }
171
+ // ],
172
+ // dateRange: {
173
+ // startDate: '2025-01-01T00:00:00.000Z',
174
+ // endDate: '2025-01-31T23:59:59.000Z'
175
+ // }
176
+ // }
177
+ ```
178
+
179
+ ### 6. Update Attendance Entry
180
+ Update an existing attendance record (typically admin-only functionality).
181
+
182
+ ```typescript
183
+ const updateResult = await client.attendance.updateById('attendance-record-id', {
184
+ timestamp: '2025-01-01T09:00:00.000Z', // Optional: Correct the timestamp
185
+ notes: 'Corrected time', // Optional: Update notes
186
+ editorId: 'admin-user-id' // Optional: Who made the edit
187
+ });
188
+
189
+ // Response
190
+ console.log(updateResult);
191
+ // {
192
+ // status: 200,
193
+ // data: {
194
+ // updatedRecord: {
195
+ // _id: 'record-id',
196
+ // timestamp: '2025-01-01T09:00:00.000Z',
197
+ // notes: 'Corrected time',
198
+ // editedBy: 'admin-user-id',
199
+ // editedAt: '2025-01-01T10:00:00.000Z'
200
+ // }
201
+ // }
202
+ // }
203
+ ```
204
+
205
+ ## 🎯 TypeScript Interfaces
206
+
207
+ ```typescript
208
+ import {
209
+ IAttendanceRecord,
210
+ IAttendanceHistory,
211
+ IAttendanceStatus,
212
+ IAttendanceReport
213
+ } from 'washday-sdk';
214
+
215
+ interface IAttendanceRecord {
216
+ _id?: string;
217
+ employee: IUser | string;
218
+ store: IStore | string;
219
+ type: 'IN' | 'OUT';
220
+ timestamp: Date;
221
+ ipAddress?: string;
222
+ notes?: string;
223
+ editedBy?: IUser | string;
224
+ editedAt?: Date;
225
+ autoClosed?: boolean; // Set to true if automatically closed by system
226
+ createdAt?: Date;
227
+ updatedAt?: Date;
228
+ }
229
+
230
+ interface IAttendanceStatus {
231
+ active: boolean;
232
+ clockInTime?: Date; // Only present if active is true
233
+ clockInStore?: IStore | string; // Store where employee clocked in
234
+ }
235
+
236
+ interface IAttendanceHistory {
237
+ attendanceRecords: IAttendanceRecord[];
238
+ totalRecords?: number;
239
+ currentPage?: number;
240
+ totalPages?: number;
241
+ }
242
+
243
+ interface IAttendanceReport {
244
+ storeId: string;
245
+ storeName?: string;
246
+ employees: {
247
+ employee: IUser | string;
248
+ records: IAttendanceRecord[];
249
+ totalHours?: number;
250
+ totalShifts?: number;
251
+ }[];
252
+ dateRange?: {
253
+ startDate: Date;
254
+ endDate: Date;
255
+ };
256
+ }
257
+ ```
258
+
259
+ ## 📊 Error Handling
260
+
261
+ The attendance module returns standard HTTP status codes and error messages:
262
+
263
+ ```typescript
264
+ try {
265
+ const result = await client.attendance.clockIn({
266
+ storeId: 'store-id',
267
+ notes: 'Starting work'
268
+ });
269
+ console.log('Success:', result.data);
270
+ } catch (error) {
271
+ console.error('Error:', error.response?.data?.errors || error.message);
272
+
273
+ // Handle specific error cases
274
+ if (error.response?.status === 400) {
275
+ // Validation error examples:
276
+ // - Already clocked in
277
+ // - Invalid store ID
278
+ // - User not found
279
+ console.log('Validation error:', error.response.data.errors);
280
+ } else if (error.response?.status === 401) {
281
+ // Authentication error
282
+ console.log('Please check your API token');
283
+ } else if (error.response?.status === 403) {
284
+ // Permission error
285
+ console.log('Insufficient permissions');
286
+ } else if (error.response?.status === 500) {
287
+ // Server error
288
+ console.log('Internal server error');
289
+ }
290
+ }
291
+ ```
292
+
293
+ ### Common Error Scenarios
294
+
295
+ | Error | Status | Description | Solution |
296
+ |-------|--------|-------------|----------|
297
+ | Already clocked in | 400 | Employee has active shift | Clock out first |
298
+ | No active shift | 400 | Trying to clock out without clock-in | Clock in first |
299
+ | Invalid store | 400 | Store ID doesn't exist | Verify store ID |
300
+ | User not found | 400 | User ID doesn't exist | Verify user ID |
301
+ | Unauthorized | 401 | Invalid API token | Check authentication |
302
+ | Forbidden | 403 | Insufficient permissions | Check user permissions |
303
+
304
+ ## 🔧 Advanced Features
305
+
306
+ ### Auto Clock-Out Configuration
307
+ The attendance system supports automatic clock-out after a configurable number of hours per store:
308
+
309
+ ```typescript
310
+ // This is managed through store configuration endpoints
311
+ const store = await client.stores.getStoreById('store-id');
312
+ console.log(store.attendanceConfig);
313
+ // {
314
+ // maxShiftHours: 12, // Auto clock-out after 12 hours
315
+ // requireClockInOnLogin: false, // Force clock-in on POS login
316
+ // autoClosedFlag: true // Enable auto clock-out feature
317
+ // }
318
+ ```
319
+
320
+ ### Multi-Store Support
321
+ - Employees can work across multiple stores
322
+ - Clock-out automatically occurs in the same store as the last clock-in
323
+ - History and reports can be filtered by store or show all stores
324
+ - Status checks can be store-specific or global
325
+
326
+ ### IP Address Tracking
327
+ IP addresses are automatically captured when available for:
328
+ - Security auditing
329
+ - Location verification
330
+ - Fraud prevention
331
+
332
+ ### Shift Duration Calculation
333
+ The system automatically calculates shift durations:
334
+ - Hours and minutes worked
335
+ - Total minutes for easy calculations
336
+ - Handles overnight shifts correctly
337
+
338
+ ## 📋 Best Practices
339
+
340
+ ### For Client Applications
341
+ 1. **Always check status before actions**:
342
+ ```typescript
343
+ const status = await client.attendance.getStatus();
344
+ if (status.active) {
345
+ // Show clock-out button
346
+ } else {
347
+ // Show clock-in button
348
+ }
349
+ ```
350
+
351
+ 2. **Handle errors gracefully**:
352
+ ```typescript
353
+ try {
354
+ await client.attendance.clockIn({ storeId });
355
+ } catch (error) {
356
+ if (error.response?.status === 400) {
357
+ // Show user-friendly message
358
+ alert('You are already clocked in');
359
+ }
360
+ }
361
+ ```
362
+
363
+ 3. **Use pagination for large datasets**:
364
+ ```typescript
365
+ const history = await client.attendance.getHistory({
366
+ limit: '50',
367
+ pageNum: '1'
368
+ });
369
+ ```
370
+
371
+ ### For Managers/Admins
372
+ 1. **Regular report generation**:
373
+ ```typescript
374
+ const weeklyReport = await client.attendance.getStoreReport(storeId, {
375
+ startDate: getWeekStart(),
376
+ endDate: getWeekEnd()
377
+ });
378
+ ```
379
+
380
+ 2. **Monitor auto-closed shifts**:
381
+ ```typescript
382
+ const history = await client.attendance.getHistory({
383
+ storeId,
384
+ startDate: 'today'
385
+ });
386
+
387
+ const autoClosedShifts = history.attendanceRecords.filter(
388
+ record => record.autoClosed
389
+ );
390
+ ```
391
+
392
+ ### Performance Optimization
393
+ 1. **Use store-specific queries when possible**
394
+ 2. **Implement proper pagination for large date ranges**
395
+ 3. **Cache status information for short periods**
396
+ 4. **Use appropriate date ranges to limit data volume**
397
+
398
+ ## 🚨 Important Notes
399
+
400
+ - **Clock-out enforcement**: The system enforces that clock-out occurs in the same store as the corresponding clock-in
401
+ - **Auto clock-out**: Shifts are automatically closed after the configured maximum hours
402
+ - **Data integrity**: All records are immutable once created (updates create edit logs)
403
+ - **Time zones**: All timestamps are stored in UTC and should be converted to local time for display
404
+ - **Permissions**: Some operations (like editing records) require administrative permissions
package/jest.config.js ADDED
File without changes
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "washday-sdk",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "Washday utilities functions and API",
5
5
  "main": "dist/index.js",
6
+ "type": "module",
6
7
  "scripts": {
7
- "test": "test",
8
+ "test": "jest",
8
9
  "build": "tsc",
9
- "publish": "npm run build && npm publish --access public"
10
+ "publishVersion": "npm run build && npm publish --access public"
10
11
  },
11
12
  "keywords": [
12
13
  "washday"
@@ -14,10 +15,17 @@
14
15
  "author": "Washday",
15
16
  "license": "ISC",
16
17
  "devDependencies": {
18
+ "@babel/core": "^7.24.4",
19
+ "@babel/preset-env": "^7.24.4",
20
+ "@babel/preset-typescript": "^7.24.1",
21
+ "babel-jest": "^29.7.0",
22
+ "jest": "^29.7.0",
17
23
  "typescript": "^5.4.4"
18
24
  },
19
25
  "dependencies": {
20
26
  "axios": "^1.6.8",
21
- "joi": "^17.12.3"
27
+ "joi": "^17.12.3",
28
+ "moment": "^2.30.1",
29
+ "uuid": "^11.1.0"
22
30
  }
23
31
  }
@@ -0,0 +1 @@
1
+ // No delete endpoints implemented for attendance module
@@ -0,0 +1,88 @@
1
+ import { WashdayClientInstance } from "../../interfaces/Api";
2
+ import axiosInstance from "../axiosInstance";
3
+
4
+ const ATTENDANCE_API = 'api/attendance';
5
+
6
+ export const getHistory = async function (this: WashdayClientInstance, params: {
7
+ userId?: string; // ✅ AÑADIDO - requerido por backend
8
+ storeId?: string;
9
+ startDate?: string;
10
+ endDate?: string;
11
+ pageNum?: string;
12
+ limit?: string;
13
+ }): Promise<any> {
14
+ try {
15
+ const config = {
16
+ headers: { Authorization: `Bearer ${this.apiToken}` }
17
+ };
18
+
19
+ let queryParams = '';
20
+ if (params.userId) queryParams += `userId=${params.userId}&`; // ✅ AÑADIDO
21
+ if (params.storeId) queryParams += `storeId=${params.storeId}&`;
22
+ if (params.startDate) queryParams += `startDate=${params.startDate}&`;
23
+ if (params.endDate) queryParams += `endDate=${params.endDate}&`;
24
+ if (params.pageNum) queryParams += `pageNum=${params.pageNum}&`;
25
+ if (params.limit) queryParams += `limit=${params.limit}&`;
26
+
27
+ // Remove trailing '&'
28
+ queryParams = queryParams.slice(0, -1);
29
+
30
+ const url = queryParams ? `${ATTENDANCE_API}/history?${queryParams}` : `${ATTENDANCE_API}/history`;
31
+ return await axiosInstance.get(url, config);
32
+ } catch (error) {
33
+ console.error('Error fetching attendance history:', error);
34
+ throw error;
35
+ }
36
+ };
37
+
38
+ export const getStatus = async function (this: WashdayClientInstance, params?: {
39
+ storeId?: string;
40
+ userId?: string;
41
+ }): Promise<any> {
42
+ try {
43
+ const config = {
44
+ headers: { Authorization: `Bearer ${this.apiToken}` }
45
+ };
46
+
47
+ let queryParams = '';
48
+ if (params?.storeId) queryParams += `storeId=${params.storeId}&`;
49
+ if (params?.userId) queryParams += `userId=${params.userId}&`; // ✅ ARREGLADO - añadir &
50
+
51
+ // Remove trailing '&'
52
+ queryParams = queryParams.slice(0, -1);
53
+
54
+ const url = queryParams ? `${ATTENDANCE_API}/status?${queryParams}` : `${ATTENDANCE_API}/status`;
55
+ return await axiosInstance.get(url, config);
56
+ } catch (error) {
57
+ console.error('Error fetching attendance status:', error);
58
+ throw error;
59
+ }
60
+ };
61
+
62
+ export const getStoreReport = async function (this: WashdayClientInstance, storeId: string, params?: {
63
+ startDate?: string;
64
+ endDate?: string;
65
+ pageNum?: string;
66
+ limit?: string;
67
+ }): Promise<any> {
68
+ try {
69
+ const config = {
70
+ headers: { Authorization: `Bearer ${this.apiToken}` }
71
+ };
72
+
73
+ let queryParams = '';
74
+ if (params?.startDate) queryParams += `startDate=${params.startDate}&`;
75
+ if (params?.endDate) queryParams += `endDate=${params.endDate}&`;
76
+ if (params?.pageNum) queryParams += `pageNum=${params.pageNum}&`;
77
+ if (params?.limit) queryParams += `limit=${params.limit}&`;
78
+
79
+ // Remove trailing '&'
80
+ queryParams = queryParams.slice(0, -1);
81
+
82
+ const url = queryParams ? `${ATTENDANCE_API}/store/${storeId}/report?${queryParams}` : `${ATTENDANCE_API}/store/${storeId}/report`;
83
+ return await axiosInstance.get(url, config);
84
+ } catch (error) {
85
+ console.error('Error fetching store attendance report:', error);
86
+ throw error;
87
+ }
88
+ };
@@ -0,0 +1,4 @@
1
+ // export * as deleteModule from './delete';
2
+ export * as getModule from './get';
3
+ export * as postModule from './post';
4
+ export * as putModule from './put';
@@ -0,0 +1,38 @@
1
+ import { WashdayClientInstance } from "../../interfaces/Api";
2
+ import axiosInstance from "../axiosInstance";
3
+
4
+ const ATTENDANCE_API = 'api/attendance';
5
+
6
+ export const clockIn = async function (this: WashdayClientInstance, data: {
7
+ storeId: string;
8
+ userId?: string;
9
+ ipAddress?: string;
10
+ notes?: string;
11
+ }): Promise<any> {
12
+ try {
13
+ const config = {
14
+ headers: { Authorization: `Bearer ${this.apiToken}` }
15
+ };
16
+ return await axiosInstance.post(`${ATTENDANCE_API}/clock-in`, data, config);
17
+ } catch (error) {
18
+ console.error('Error clock-in:', error);
19
+ throw error;
20
+ }
21
+ };
22
+
23
+ export const clockOut = async function (this: WashdayClientInstance, data: {
24
+ userId?: string;
25
+ storeId?: string; // ✅ AÑADIDO - requerido por backend
26
+ ipAddress?: string;
27
+ notes?: string;
28
+ }): Promise<any> {
29
+ try {
30
+ const config = {
31
+ headers: { Authorization: `Bearer ${this.apiToken}` }
32
+ };
33
+ return await axiosInstance.post(`${ATTENDANCE_API}/clock-out`, data, config);
34
+ } catch (error) {
35
+ console.error('Error clock-out:', error);
36
+ throw error;
37
+ }
38
+ };
@@ -0,0 +1,20 @@
1
+ import { WashdayClientInstance } from "../../interfaces/Api";
2
+ import axiosInstance from "../axiosInstance";
3
+
4
+ const ATTENDANCE_API = 'api/attendance';
5
+
6
+ export const updateById = async function (this: WashdayClientInstance, id: string, data: {
7
+ timestamp?: string;
8
+ notes?: string;
9
+ editorId?: string;
10
+ }): Promise<any> {
11
+ try {
12
+ const config = {
13
+ headers: { Authorization: `Bearer ${this.apiToken}` }
14
+ };
15
+ return await axiosInstance.put(`${ATTENDANCE_API}/${id}`, data, config);
16
+ } catch (error) {
17
+ console.error('Error updating attendance entry:', error);
18
+ throw error;
19
+ }
20
+ };
@@ -0,0 +1,3 @@
1
+ // export * as deleteModule from './delete';
2
+ export * as postModule from './post';
3
+ // export * as putModule from './put';