@shisyamo4131/air-guard-v2-schemas 1.0.0

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 (38) hide show
  1. package/index.js +15 -0
  2. package/package.json +44 -0
  3. package/src/Agreement.js +262 -0
  4. package/src/ArrangementNotification.js +505 -0
  5. package/src/Billing.js +159 -0
  6. package/src/Company.js +176 -0
  7. package/src/Customer.js +98 -0
  8. package/src/Employee.js +201 -0
  9. package/src/Operation.js +779 -0
  10. package/src/OperationBilling.js +193 -0
  11. package/src/OperationDetail.js +147 -0
  12. package/src/OperationResult.js +437 -0
  13. package/src/OperationResultDetail.js +72 -0
  14. package/src/Outsourcer.js +46 -0
  15. package/src/RoundSetting.js +123 -0
  16. package/src/Site.js +192 -0
  17. package/src/SiteOperationSchedule.js +503 -0
  18. package/src/SiteOperationScheduleDetail.js +99 -0
  19. package/src/SiteOrder.js +62 -0
  20. package/src/Tax.js +39 -0
  21. package/src/User.js +41 -0
  22. package/src/WorkingResult.js +297 -0
  23. package/src/apis/index.js +9 -0
  24. package/src/constants/arrangement-notification-status.js +68 -0
  25. package/src/constants/billing-unit-type.js +15 -0
  26. package/src/constants/contract-status.js +15 -0
  27. package/src/constants/day-type.js +44 -0
  28. package/src/constants/employment-status.js +15 -0
  29. package/src/constants/gender.js +11 -0
  30. package/src/constants/index.js +9 -0
  31. package/src/constants/prefectures.js +56 -0
  32. package/src/constants/shift-type.js +20 -0
  33. package/src/constants/site-status.js +15 -0
  34. package/src/parts/accessorDefinitions.js +109 -0
  35. package/src/parts/fieldDefinitions.js +642 -0
  36. package/src/utils/ContextualError.js +49 -0
  37. package/src/utils/CutoffDate.js +223 -0
  38. package/src/utils/index.js +48 -0
@@ -0,0 +1,503 @@
1
+ /*****************************************************************************
2
+ * SiteOperationSchedule Model ver 1.0.0
3
+ * @author shisyamo4131
4
+ * ---------------------------------------------------------------------------
5
+ * - Extends Operation class to represent a site operation schedule.
6
+ * - Prevents updates or deletions if an associated OperationResult exists.
7
+ * - Automatically assigns a display order based on existing documents during creation.
8
+ * - Clears all notifications if related data have been changed during updates.
9
+ * - Deletes all related notifications before deleting the schedule.
10
+ * - Synchronizes properties specified below to assigned employees and outsourcers:
11
+ * `startTime`, `endTime`, `breakMinutes`, `isStartNextDay`
12
+ * [NOTE]
13
+ * `siteId`, `dateAt`, `shiftType`, and `regulationWorkMinutes` are synchronized
14
+ * in the parent `Operation` class.
15
+ * ---------------------------------------------------------------------------
16
+ * @prop {string|null} operationResultId - Associated OperationResult document ID
17
+ * - If an OperationResult has been created based on this schedule, this property
18
+ * holds the ID of that OperationResult document.
19
+ * - If this property is set, the schedule cannot be updated or deleted.
20
+ * Conversely, if the associated OperationResult is deleted, this property can be set to null.
21
+ * @prop {number} displayOrder - Display order
22
+ * - Property to control the display order of schedules on the same date and shift type.
23
+ * - Automatically assigned during creation based on existing documents.
24
+ * ---------------------------------------------------------------------------
25
+ * @getter {boolean} isEditable - Indicates whether the instance is editable (read-only)
26
+ * - Returns `false` if `operationResultId` is set, `true` otherwise
27
+ * @getter {boolean} isNotificatedAllWorkers - Indicates whether all workers have been notified (read-only)
28
+ * - Returns `true` if all workers in the `workers` array have `hasNotification` set to `true`
29
+ * ---------------------------------------------------------------------------
30
+ * @inherited - The following properties are inherited from Operation:
31
+ * @prop {string} siteId - Site document ID (trigger property)
32
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
33
+ * @prop {number} requiredPersonnel - Required number of personnel
34
+ * @prop {boolean} qualificationRequired - Qualification required flag
35
+ * @prop {string} workDescription - Work description
36
+ * @prop {string} remarks - Remarks
37
+ * @prop {Array<SiteOperationScheduleDetail>} employees - Assigned employees
38
+ * - Array of `SiteOperationScheduleDetail` instances representing assigned employees
39
+ * @prop {Array<SiteOperationScheduleDetail>} outsourcers - Assigned outsourcers
40
+ * - Array of `SiteOperationScheduleDetail` instances representing assigned outsourcers
41
+ * ---------------------------------------------------------------------------
42
+ * @inherited - The following properties are inherited from WorkingResult (via Operation):
43
+ * @prop {Date} dateAt - Date of operation (placement date) (trigger property)
44
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
45
+ * @prop {string} dayType - Day type (e.g., `WEEKDAY`, `WEEKEND`, `HOLIDAY`)
46
+ * @prop {string} shiftType - `DAY` or `NIGHT` (trigger property)
47
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
48
+ * @prop {string} startTime - Start time (HH:MM format) (trigger property)
49
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
50
+ * @prop {boolean} isStartNextDay - Next day start flag (trigger property)
51
+ * - `true` if the actual work starts the day after the placement date `dateAt`
52
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
53
+ * @prop {string} endTime - End time (HH:MM format) (trigger property)
54
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
55
+ * @prop {number} breakMinutes - Break time (minutes) (trigger property)
56
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
57
+ * @prop {number} regulationWorkMinutes - Regulation work minutes (trigger property)
58
+ * - Indicates the maximum working time treated as regular working hours.
59
+ * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
60
+ * ---------------------------------------------------------------------------
61
+ * @inherited - The following computed properties are inherited from Operation:
62
+ * @computed {Array<string>} employeeIds - Array of employee IDs from `employees` (read-only)
63
+ * @computed {Array<string>} outsourcerIds - Array of outsourcer IDs from `outsourcers` (read-only)
64
+ * @computed {number} employeesCount - Count of assigned employees (read-only)
65
+ * @computed {number} outsourcersCount - Count of assigned outsourcers (sum of amounts) (read-only)
66
+ * @computed {boolean} isPersonnelShortage - Indicates if there is a shortage of personnel (read-only)
67
+ * - `true` if the sum of `employeesCount` and `outsourcersCount` is less than `requiredPersonnel`
68
+ * @computed {Array<SiteOperationScheduleDetail>} workers - Combined array of `employees` and `outsourcers`
69
+ * - Getter: Returns concatenated array of employees and outsourcers
70
+ * - Setter: Splits array into employees and outsourcers based on `isEmployee` property
71
+ * ---------------------------------------------------------------------------
72
+ * @inherited - The following computed properties are inherited from WorkingResult (via Operation):
73
+ * @computed {string} date - Date string in YYYY-MM-DD format based on `dateAt` (read-only)
74
+ * - Returns a string in the format YYYY-MM-DD based on `dateAt`.
75
+ * @computed {Date} startAt - Start date and time (Date object) (read-only)
76
+ * - Returns a Date object with `startTime` set based on `dateAt`.
77
+ * - If `isStartNextDay` is true, add 1 day.
78
+ * @computed {Date} endAt - End date and time (Date object) (read-only)
79
+ * - Returns a Date object with `endTime` set based on `dateAt`.
80
+ * - If `isStartNextDay` is true, add 1 day.
81
+ * - If `isSpansNextDay` is true, add 1 day.
82
+ * @computed {boolean} isSpansNextDay - Flag indicating whether the date spans from start date to end date (read-only)
83
+ * - `true` if `startTime` is later than `endTime`
84
+ * @computed {number} totalWorkMinutes - Total working time in minutes (excluding break time) (read-only)
85
+ * - Calculated as the difference between `endAt` and `startAt` minus `breakMinutes`
86
+ * @computed {number} regularTimeWorkMinutes - Regular working time in minutes (read-only)
87
+ * - The portion of `totalWorkMinutes` that is considered within the contract's `regulationWorkMinutes`.
88
+ * @computed {number} overtimeWorkMinutes - Overtime work in minutes (read-only)
89
+ * - Calculated as `totalWorkMinutes` minus `regulationWorkMinutes`
90
+ * ---------------------------------------------------------------------------
91
+ * @inherited - The following getter properties are inherited from Operation:
92
+ * @getter {string} groupKey - Combines `siteId`, `shiftType`, and `date` to indicate operation grouping (read-only)
93
+ * @getter {boolean} isEmployeesChanged - Indicates whether the employees have changed (read-only)
94
+ * - Returns true if the employee IDs have changed compared to `_beforeData`
95
+ * @getter {boolean} isOutsourcersChanged - Indicates whether the outsourcers have changed (read-only)
96
+ * - Returns true if the outsourcer IDs have changed compared to `_beforeData`
97
+ * @getter {Array<SiteOperationScheduleDetail>} addedWorkers - An array of workers that have been added (read-only)
98
+ * - Workers that exist in current data but not in `_beforeData`
99
+ * @getter {Array<SiteOperationScheduleDetail>} removedWorkers - An array of workers that have been removed (read-only)
100
+ * - Workers that exist in `_beforeData` but not in current data
101
+ * @getter {Array<SiteOperationScheduleDetail>} updatedWorkers - An array of workers that have been updated (read-only)
102
+ * - Workers whose `startTime`, `isStartNextDay`, `endTime`, `breakMinutes`, `isQualified`, or `isOjt` have changed
103
+ * ---------------------------------------------------------------------------
104
+ * @inherited - The following getter properties are inherited from WorkingResult (via Operation):
105
+ * @getter {number} startHour - Start hour (0-23) (read-only)
106
+ * - Extracted from `startTime`.
107
+ * @getter {number} startMinute - Start minute (0-59) (read-only)
108
+ * - Extracted from `startTime`.
109
+ * @getter {number} endHour - End hour (0-23) (read-only)
110
+ * - Extracted from `endTime`.
111
+ * @getter {number} endMinute - End minute (0-59) (read-only)
112
+ * - Extracted from `endTime`.
113
+ * ---------------------------------------------------------------------------
114
+ * @method {function} create - Creates a new SiteOperationSchedule with automatic display order assignment
115
+ * - Automatically assigns a display order based on existing documents.
116
+ * - @param {Object} updateOptions - Options for creating the document
117
+ * @method {function} update - Updates the SiteOperationSchedule and manages related notifications
118
+ * - Clears all notifications if related data have been changed during updates.
119
+ * - Updates and deletes notifications for removed or updated employees if employee assignments have changed.
120
+ * - @param {Object} updateOptions - Options for updating the document
121
+ * @method {function} delete - Deletes the SiteOperationSchedule and all related notifications
122
+ * - Deletes all notifications associated with the schedule before deleting the schedule itself.
123
+ * - @param {Object} updateOptions - Options for deleting the document
124
+ * @method {function} addWorker - Adds a new worker with automatic siteOperationScheduleId assignment
125
+ * - Overrides parent method to automatically set `siteOperationScheduleId`
126
+ * - @param {Object} options - Options for adding a worker
127
+ * - @param {number} index - Insertion position
128
+ * ---------------------------------------------------------------------------
129
+ * @inherited - The following methods are inherited from Operation:
130
+ * @method {function} moveWorker - Moves the position of a worker (employee or outsourcer)
131
+ * - @param {Object} options - Options for changing worker position
132
+ * @method {function} changeWorker - Changes the details of a worker
133
+ * - @param {Object} newWorker - New worker object
134
+ * @method {function} removeWorker - Removes a worker (employee or outsourcer)
135
+ * - @param {Object} options - Options for removing a worker
136
+ * @method {function} setSiteIdCallback - Callback method called when `siteId` is set
137
+ * - Override this method in subclasses to add custom behavior when `siteId` changes.
138
+ * - @param {string} v - The new `siteId` value
139
+ * @method {function} setShiftTypeCallback - Callback method called when `shiftType` is set
140
+ * - Override this method in subclasses to add custom behavior when `shiftType` changes.
141
+ * - @param {string} v - The new `shiftType` value
142
+ * @method {function} setRegulationWorkMinutesCallback - Callback method called when `regulationWorkMinutes` is set
143
+ * - Override this method in subclasses to add custom behavior when `regulationWorkMinutes` changes.
144
+ * - @param {number} v - The new `regulationWorkMinutes` value
145
+ * @static
146
+ * @method groupKeyDivider
147
+ * Returns an array dividing the key into siteId, shiftType, and date.
148
+ * @param {Object|string} key - The combined key string or object
149
+ * @returns {Array<string>} - Array containing [siteId, shiftType, date]
150
+ * @throws {Error} - If the key is invalid.
151
+ * ---------------------------------------------------------------------------
152
+ * @inherited - The following method is inherited from WorkingResult (via Operation):
153
+ * @method {function} setDateAtCallback - Callback method called when `dateAt` is set
154
+ * - Override this method in subclasses to add custom behavior when `dateAt` changes.
155
+ * - By default, updates `dayType` based on the new `dateAt` value and synchronizes to workers.
156
+ * - @param {Date} v - The new `dateAt` value
157
+ *****************************************************************************/
158
+ import Operation from "./Operation.js";
159
+ import { defField } from "./parts/fieldDefinitions.js";
160
+ import { ContextualError } from "./utils/index.js";
161
+ import { runTransaction } from "firebase/firestore";
162
+ import ArrangementNotification from "./ArrangementNotification.js";
163
+ import SiteOperationScheduleDetail from "./SiteOperationScheduleDetail.js";
164
+
165
+ const classProps = {
166
+ ...Operation.classProps,
167
+ operationResultId: defField("oneLine", { hidden: true }),
168
+ displayOrder: defField("number", { default: 0, hidden: true }),
169
+ employees: defField("array", { customClass: SiteOperationScheduleDetail }),
170
+ outsourcers: defField("array", {
171
+ customClass: SiteOperationScheduleDetail,
172
+ }),
173
+ dayType: defField("dayType", { hidden: true }),
174
+ regulationWorkMinutes: defField("regulationWorkMinutes", { hidden: true }),
175
+ };
176
+
177
+ /**
178
+ * Wrapper to define computed properties.
179
+ * @param {*} obj
180
+ * @param {*} properties
181
+ */
182
+ function defineComputedProperties(obj, properties) {
183
+ const descriptors = {};
184
+ for (const [key, descriptor] of Object.entries(properties)) {
185
+ descriptors[key] = {
186
+ configurable: true,
187
+ enumerable: true,
188
+ ...descriptor,
189
+ };
190
+ }
191
+ Object.defineProperties(obj, descriptors);
192
+ }
193
+
194
+ export default class SiteOperationSchedule extends Operation {
195
+ static className = "現場稼働予定";
196
+ static collectionPath = "SiteOperationSchedules";
197
+ static classProps = classProps;
198
+
199
+ static headers = [
200
+ { title: "日付", key: "dateAt" },
201
+ { title: "現場", key: "siteId", value: "siteId" },
202
+ ];
203
+
204
+ /***************************************************************************
205
+ * Override `afterInitialize`
206
+ ***************************************************************************/
207
+ afterInitialize() {
208
+ super.afterInitialize();
209
+ const synchronizeToWorkers = (key, value) => {
210
+ this.employees.forEach((emp) => {
211
+ emp[key] = value;
212
+ });
213
+ this.outsourcers.forEach((out) => {
214
+ out[key] = value;
215
+ });
216
+ };
217
+
218
+ /***********************************************************
219
+ * TRIGGERS FOR SYNCRONIZATION TO EMPLOYEES AND OUTSOURCERS
220
+ * ---------------------------------------------------------
221
+ * When `docId`, `startTime`, `endTime`, `breakMinutes`, and
222
+ * `isStartNextDay` are changed on the SiteOperationSchedule
223
+ * instance, the corresponding properties on all employees
224
+ * and outsourcers are automatically updated to keep them in sync.
225
+ * Especially important is that when `docId` changes, the
226
+ * `siteOperationScheduleId` on all employees and outsourcers
227
+ * is updated accordingly.
228
+ * [NOTE]
229
+ * `siteId`, `dateAt`, `shiftType`, and `regulationWorkMinutes` are
230
+ * synchronized in the parent `Operation` class.
231
+ ***********************************************************/
232
+ let _docId = this.docId;
233
+ let _startTime = this.startTime;
234
+ let _endTime = this.endTime;
235
+ let _breakMinutes = this.breakMinutes;
236
+ let _isStartNextDay = this.isStartNextDay;
237
+ defineComputedProperties(this, {
238
+ docId: {
239
+ get() {
240
+ return _docId;
241
+ },
242
+ set(v) {
243
+ if (_docId === v) return;
244
+ _docId = v;
245
+ synchronizeToWorkers("siteOperationScheduleId", v);
246
+ },
247
+ },
248
+ startTime: {
249
+ get() {
250
+ return _startTime;
251
+ },
252
+ set(v) {
253
+ if (typeof v !== "string") {
254
+ throw new Error(`startTime must be a string. startTime: ${v}`);
255
+ }
256
+ if (_startTime === v) return;
257
+ _startTime = v;
258
+ synchronizeToWorkers("startTime", v);
259
+ },
260
+ },
261
+ endTime: {
262
+ get() {
263
+ return _endTime;
264
+ },
265
+ set(v) {
266
+ if (typeof v !== "string") {
267
+ throw new Error(`endTime must be a string. endTime: ${v}`);
268
+ }
269
+ if (_endTime === v) return;
270
+ _endTime = v;
271
+ synchronizeToWorkers("endTime", v);
272
+ },
273
+ },
274
+ breakMinutes: {
275
+ get() {
276
+ return _breakMinutes;
277
+ },
278
+ set(v) {
279
+ if (typeof v !== "number" || isNaN(v) || v < 0) {
280
+ throw new Error(
281
+ `breakMinutes must be a non-negative number. breakMinutes: ${v}`
282
+ );
283
+ }
284
+ if (_breakMinutes === v) return;
285
+ _breakMinutes = v;
286
+ synchronizeToWorkers("breakMinutes", v);
287
+ },
288
+ },
289
+ isStartNextDay: {
290
+ get() {
291
+ return _isStartNextDay;
292
+ },
293
+ set(v) {
294
+ if (typeof v !== "boolean") {
295
+ throw new Error(
296
+ `isStartNextDay must be a boolean. isStartNextDay: ${v}`
297
+ );
298
+ }
299
+ if (_isStartNextDay === v) return;
300
+ _isStartNextDay = v;
301
+ synchronizeToWorkers("isStartNextDay", v);
302
+ },
303
+ },
304
+ });
305
+ }
306
+ /***************************************************************************
307
+ * STATES
308
+ ***************************************************************************/
309
+ /**
310
+ * Returns whether the schedule is editable.
311
+ * @returns {boolean} - Whether the schedule is editable.
312
+ */
313
+ get isEditable() {
314
+ return !this.operationResultId;
315
+ }
316
+
317
+ /**
318
+ * Returns whether all workers have been notified.
319
+ * @returns {boolean} - Whether all workers have been notified.
320
+ */
321
+ get isNotificatedAllWorkers() {
322
+ return this.workers.every((worker) => worker.hasNotification);
323
+ }
324
+
325
+ /***************************************************************************
326
+ * METHODS
327
+ ***************************************************************************/
328
+ /**
329
+ * Override `beforeUpdate`.
330
+ * - Prevents updates if an associated OperationResult exists.
331
+ */
332
+ async beforeUpdate() {
333
+ if (this._beforeData.operationResultId) {
334
+ throw new Error(
335
+ `Could not update this document. The OperationResult based on this document already exists. OperationResultId: ${this._beforeData.operationResultId}`
336
+ );
337
+ }
338
+ await super.beforeUpdate();
339
+ }
340
+
341
+ /**
342
+ * Override `beforeDelete`.
343
+ * - Prevents deletions if an associated OperationResult exists.
344
+ */
345
+ async beforeDelete() {
346
+ if (this._beforeData.operationResultId) {
347
+ throw new Error(
348
+ `Could not delete this document. The OperationResult based on this document already exists. OperationResultId: ${this._beforeData.operationResultId}`
349
+ );
350
+ }
351
+ await super.beforeDelete();
352
+ }
353
+
354
+ /**
355
+ * Override create method.
356
+ * - Automatically assigns a display order based on existing documents.
357
+ * @param {Object} updateOptions - Options for creating the notification.
358
+ * @param {boolean} updateOptions.useAutonumber - Whether to use autonumbering.
359
+ * @param {Object} updateOptions.transaction - The Firestore transaction object.
360
+ * @param {function} updateOptions.callback - The callback function.
361
+ * @param {string} updateOptions.prefix - The prefix.
362
+ */
363
+ async create(updateOptions = {}) {
364
+ try {
365
+ const existingDocs = await this.fetchDocs({
366
+ constraints: [
367
+ ["where", "siteId", "==", this.siteId],
368
+ ["where", "shiftType", "==", this.shiftType],
369
+ ["where", "date", "==", this.date],
370
+ ["orderBy", "displayOrder", "desc"],
371
+ ["limit", 1],
372
+ ],
373
+ });
374
+ if (existingDocs.length > 0) {
375
+ this.displayOrder = existingDocs[0].displayOrder + 1;
376
+ }
377
+ return await super.create(updateOptions);
378
+ } catch (error) {
379
+ throw new ContextualError(error.message, {
380
+ method: "create",
381
+ className: "SiteOperationSchedule",
382
+ arguments: updateOptions,
383
+ state: this.toObject(),
384
+ });
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Override update method.
390
+ * - Updates and clears notifications if related data have been changed.
391
+ * - Updates and deletes notifications for removed or updated employees if employee assignments have changed.
392
+ * - Just updates if no changes detected.
393
+ * @param {Object} updateOptions - Options for updating the notification.
394
+ * @param {Object} updateOptions.transaction - The Firestore transaction object.
395
+ * @param {function} updateOptions.callback - The callback function.
396
+ * @param {string} updateOptions.prefix - The prefix.
397
+ */
398
+ async update(updateOptions = {}) {
399
+ try {
400
+ // Returns whether the notifications should be cleared.
401
+ // - All notifications should be cleared if any of the following properties have changed:
402
+ // `siteId`, `date`, `shiftType`, `startTime`, `isStartNextDay`, `endTime`, or `breakMinutes`.
403
+ // - Returns false if there are no changes.
404
+ const shouldClearNotifications = () => {
405
+ const keys1 = ["siteId", "date", "shiftType"];
406
+ const keys2 = ["startTime", "isStartNextDay", "endTime"];
407
+ const keys3 = ["breakMinutes"];
408
+ const changes = {};
409
+ for (const key of [...keys1, ...keys2, ...keys3]) {
410
+ if (this._beforeData?.[key] !== this[key]) {
411
+ changes[key] = {
412
+ before: this._beforeData?.[key],
413
+ after: this[key],
414
+ };
415
+ }
416
+ }
417
+ return Object.keys(changes).length > 0 ? changes : false;
418
+ };
419
+
420
+ // Perform the update within a transaction.
421
+ // - All notifications will be deleted if `shouldClearNotifications` returns not false.
422
+ // - Notifications for removed or updated workers will be deleted.
423
+ const performTransaction = async (txn) => {
424
+ // Prepare arguments for bulk deletion of notifications.
425
+ const args = { siteOperationScheduleId: this.docId };
426
+
427
+ // Delete all notifications if related data have been changed.
428
+ if (shouldClearNotifications()) {
429
+ this.employees.forEach((emp) => (emp.hasNotification = false));
430
+ this.outsourcers.forEach((out) => (out.hasNotification = false));
431
+ await ArrangementNotification.bulkDelete(args, txn);
432
+ }
433
+ // Delete notifications for removed or updated workers that have been notified
434
+ else {
435
+ const updatedWorkers = this.updatedWorkers;
436
+ const removedWorkers = this.removedWorkers;
437
+ const workerIds = updatedWorkers
438
+ .map((w) => w.workerId)
439
+ .concat(removedWorkers.map((w) => w.workerId));
440
+ args.workerIds = Array.from(new Set(workerIds));
441
+ updatedWorkers.forEach((w) => (w.hasNotification = false));
442
+ if (args.workerIds.length !== 0) {
443
+ await ArrangementNotification.bulkDelete(args, txn);
444
+ }
445
+ }
446
+ await super.update({ ...updateOptions, transaction: txn });
447
+ };
448
+
449
+ if (updateOptions.transaction) {
450
+ await performTransaction(updateOptions.transaction);
451
+ } else {
452
+ const firestore = this.constructor.getAdapter().firestore;
453
+ await runTransaction(firestore, performTransaction);
454
+ }
455
+ } catch (error) {
456
+ this.undo();
457
+ throw new ContextualError(error.message, {
458
+ method: "update",
459
+ className: "SiteOperationSchedule",
460
+ arguments: updateOptions,
461
+ state: this.toObject(),
462
+ });
463
+ }
464
+ }
465
+
466
+ /**
467
+ * Override delete method.
468
+ * - Deletes all notifications associated with the schedule before deleting the schedule itself.
469
+ * @param {Object} updateOptions - Options for deleting the notification.
470
+ * @param {Object} updateOptions.transaction - The Firestore transaction object.
471
+ * @param {function} updateOptions.callback - The callback function.
472
+ * @param {string} updateOptions.prefix - The prefix.
473
+ */
474
+ async delete(updateOptions = {}) {
475
+ try {
476
+ const performTransaction = async (txn) => {
477
+ const siteOperationScheduleId = this.docId;
478
+ await Promise.all([
479
+ ArrangementNotification.bulkDelete({ siteOperationScheduleId }, txn),
480
+ super.delete({ ...updateOptions, transaction: txn }),
481
+ ]);
482
+ };
483
+ if (updateOptions.transaction) {
484
+ await performTransaction(updateOptions.transaction);
485
+ } else {
486
+ const firestore = this.constructor.getAdapter().firestore;
487
+ await runTransaction(firestore, performTransaction);
488
+ }
489
+ } catch (error) {
490
+ throw new ContextualError(error.message, {
491
+ method: "delete",
492
+ className: "SiteOperationSchedule",
493
+ arguments: updateOptions,
494
+ state: this.toObject(),
495
+ });
496
+ }
497
+ }
498
+
499
+ /** Override addWorker for specify siteOperationScheduleId */
500
+ addWorker(options = {}, index = 0) {
501
+ super.addWorker({ ...options, siteOperationScheduleId: this.docId }, index);
502
+ }
503
+ }
@@ -0,0 +1,99 @@
1
+ /*****************************************************************************
2
+ * SiteOperationScheduleDetail ver 1.0.0
3
+ * @author shisyamo4131
4
+ * ---------------------------------------------------------------------------
5
+ * - Model representing the details of a site operation schedule.
6
+ * - Inherits from OperationDetail.
7
+ * ---------------------------------------------------------------------------
8
+ * @prop {string} siteOperationScheduleId - Site Operation Schedule ID
9
+ * @prop {boolean} hasNotification - Notification flag
10
+ * ---------------------------------------------------------------------------
11
+ * @computed {string} notificationKey - Notification key (read-only)
12
+ * - Concatenation of `siteOperationScheduleId` and `workerId` with '-'
13
+ * ---------------------------------------------------------------------------
14
+ * @inherited - The following properties are inherited from OperationDetail:
15
+ * @prop {string} id - Employee or Outsourcer document ID
16
+ * @prop {number} index - Identifier index for Outsourcer (always 0 for Employee)
17
+ * @prop {boolean} isEmployee - Employee flag (true: Employee, false: Outsourcer)
18
+ * @prop {number} amount - Number of placements (always fixed at 1)
19
+ * @prop {string} siteId - Site ID
20
+ * @prop {boolean} isQualified - Qualified flag
21
+ * @prop {boolean} isOjt - OJT flag
22
+ * ---------------------------------------------------------------------------
23
+ * @inherited - The following computed properties are inherited from OperationDetail:
24
+ * @computed {string} workerId - Worker ID (read-only)
25
+ * - For Employee, it's the same as `id`, for Outsourcer, it's a concatenation of `id` and `index` with ':'
26
+ * @computed {string|null} employeeId - Employee ID (null if not applicable) (read-only)
27
+ * @computed {string|null} outsourcerId - Outsourcer ID (null if not applicable) (read-only)
28
+ * ---------------------------------------------------------------------------
29
+ * @inherited - The following properties are inherited from WorkingResult (via OperationDetail):
30
+ * @prop {Date} dateAt - Placement date (trigger property)
31
+ * @prop {string} dayType - Day type (e.g., `WEEKDAY`, `WEEKEND`, `HOLIDAY`)
32
+ * @prop {string} shiftType - `DAY` or `NIGHT`
33
+ * @prop {string} startTime - Start time (HH:MM format)
34
+ * @prop {boolean} isStartNextDay - Next day start flag
35
+ * @prop {string} endTime - End time (HH:MM format)
36
+ * @prop {number} breakMinutes - Break time (minutes)
37
+ * @prop {number} regulationWorkMinutes - Regulation work minutes
38
+ * ---------------------------------------------------------------------------
39
+ * @inherited - The following computed properties are inherited from WorkingResult (via OperationDetail):
40
+ * @computed {string} key - Unique key combining `date`, `dayType`, and `shiftType` (read-only)
41
+ * @computed {string} date - Date string in YYYY-MM-DD format based on `dateAt` (read-only)
42
+ * @computed {boolean} isSpansNextDay - Flag indicating whether the date spans from start date to end date (read-only)
43
+ * @computed {Date} startAt - Start date and time (Date object) (read-only)
44
+ * @computed {Date} endAt - End date and time (Date object) (read-only)
45
+ * @computed {number} totalWorkMinutes - Total working time in minutes (excluding break time) (read-only)
46
+ * @computed {number} regularTimeWorkMinutes - Regular working time in minutes (read-only)
47
+ * @computed {number} overtimeWorkMinutes - Overtime work in minutes (read-only)
48
+ * - Calculated as `totalWorkMinutes` minus `regulationWorkMinutes`
49
+ * - Overtime work is not negative; the minimum is 0.
50
+ * ---------------------------------------------------------------------------
51
+ * @inherited - The following getter properties are inherited from WorkingResult (via OperationDetail):
52
+ * @getter {number} startHour - Start hour (0-23) (read-only)
53
+ * - Extracted from `startTime`.
54
+ * @getter {number} startMinute - Start minute (0-59) (read-only)
55
+ * - Extracted from `startTime`.
56
+ * @getter {number} endHour - End hour (0-23) (read-only)
57
+ * - Extracted from `endTime`.
58
+ * @getter {number} endMinute - End minute (0-59) (read-only)
59
+ * - Extracted from `endTime`.
60
+ * ---------------------------------------------------------------------------
61
+ * @inherited - The following method is inherited from WorkingResult (via OperationDetail):
62
+ * @method {function} setDateAtCallback - Callback method called when `dateAt` is set
63
+ * - Override this method in subclasses to add custom behavior when `dateAt` changes.
64
+ * - By default, updates `dayType` based on the new `dateAt` value.
65
+ * - @param {Date} v - The new `dateAt` value
66
+ *****************************************************************************/
67
+ import OperationDetail from "./OperationDetail.js";
68
+ import { defField } from "./parts/fieldDefinitions.js";
69
+
70
+ const classProps = {
71
+ ...OperationDetail.classProps,
72
+ siteOperationScheduleId: defField("oneLine", { required: true }),
73
+ hasNotification: defField("check"),
74
+ };
75
+ export default class SiteOperationScheduleDetail extends OperationDetail {
76
+ static className = "現場稼働予定明細";
77
+ static collectionPath = "SiteOperationScheduleDetails";
78
+ static classProps = classProps;
79
+
80
+ /**
81
+ * afterInitialize
82
+ * @param {*} item
83
+ */
84
+ afterInitialize(item = {}) {
85
+ super.afterInitialize(item);
86
+
87
+ /** NOTIFICATION KEY */
88
+ Object.defineProperties(this, {
89
+ notificationKey: {
90
+ configurable: true,
91
+ enumerable: true,
92
+ get() {
93
+ return `${this.siteOperationScheduleId}-${this.workerId}`;
94
+ },
95
+ set() {},
96
+ },
97
+ });
98
+ }
99
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Represents the order of site-shift type pairs for placement management.
3
+ *
4
+ * @class SiteOrder
5
+ * @extends BaseClass
6
+ *
7
+ * @property {string} siteId - The unique identifier for the site. Required.
8
+ * @property {string} shiftType - The type of shift associated with the site. Required.
9
+ *
10
+ * @property {string} key - A computed property that returns a unique key in the format `${siteId}-${shiftType}` for identifying the site-shift pair.
11
+ */
12
+ import { BaseClass } from "@shisyamo4131/air-firebase-v2";
13
+ import { defField } from "./parts/fieldDefinitions.js";
14
+
15
+ /**
16
+ * Represents the order configuration for a site and shift type.
17
+ *
18
+ * @class SiteOrder
19
+ * @extends BaseClass
20
+ *
21
+ * @property {string} siteId - The unique identifier for the site.
22
+ * @property {string} shiftType - The type of shift associated with the site.
23
+ * @property {string} key - A composite key in the format "siteId-shiftType".
24
+ *
25
+ * @getter
26
+ * Returns the composite key for the site and shift type in the format "siteId-shiftType".
27
+ *
28
+ * @setter
29
+ * Sets the `siteId` and `shiftType` properties from a composite key string in the format "siteId-shiftType".
30
+ */
31
+ export default class SiteOrder extends BaseClass {
32
+ static className = "現場配置順序";
33
+ static classProps = {
34
+ siteId: defField("oneLine", { required: true }),
35
+ shiftType: defField("shiftType", { required: true }),
36
+ };
37
+
38
+ /**
39
+ * Gets the composite key for this site and shift type.
40
+ * @returns {string} The key in the format "siteId-shiftType".
41
+ */
42
+ get key() {
43
+ return `${this.siteId}-${this.shiftType}`;
44
+ }
45
+
46
+ /**
47
+ * Setter for the `key` property.
48
+ * Expects a string in the format "siteId-shiftType".
49
+ * Splits the input string and assigns the values to `siteId` and `shiftType` properties if both are present.
50
+ * Ignores the value if it is not a string.
51
+ *
52
+ * @param {string} value - The key string in the format "siteId-shiftType".
53
+ */
54
+ set key(value) {
55
+ if (typeof value !== "string") return;
56
+ const [siteId, shiftType] = value.split("-");
57
+ if (siteId && shiftType) {
58
+ this.siteId = siteId;
59
+ this.shiftType = shiftType;
60
+ }
61
+ }
62
+ }