@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.
- package/index.js +15 -0
- package/package.json +44 -0
- package/src/Agreement.js +262 -0
- package/src/ArrangementNotification.js +505 -0
- package/src/Billing.js +159 -0
- package/src/Company.js +176 -0
- package/src/Customer.js +98 -0
- package/src/Employee.js +201 -0
- package/src/Operation.js +779 -0
- package/src/OperationBilling.js +193 -0
- package/src/OperationDetail.js +147 -0
- package/src/OperationResult.js +437 -0
- package/src/OperationResultDetail.js +72 -0
- package/src/Outsourcer.js +46 -0
- package/src/RoundSetting.js +123 -0
- package/src/Site.js +192 -0
- package/src/SiteOperationSchedule.js +503 -0
- package/src/SiteOperationScheduleDetail.js +99 -0
- package/src/SiteOrder.js +62 -0
- package/src/Tax.js +39 -0
- package/src/User.js +41 -0
- package/src/WorkingResult.js +297 -0
- package/src/apis/index.js +9 -0
- package/src/constants/arrangement-notification-status.js +68 -0
- package/src/constants/billing-unit-type.js +15 -0
- package/src/constants/contract-status.js +15 -0
- package/src/constants/day-type.js +44 -0
- package/src/constants/employment-status.js +15 -0
- package/src/constants/gender.js +11 -0
- package/src/constants/index.js +9 -0
- package/src/constants/prefectures.js +56 -0
- package/src/constants/shift-type.js +20 -0
- package/src/constants/site-status.js +15 -0
- package/src/parts/accessorDefinitions.js +109 -0
- package/src/parts/fieldDefinitions.js +642 -0
- package/src/utils/ContextualError.js +49 -0
- package/src/utils/CutoffDate.js +223 -0
- 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
|
+
}
|
package/src/SiteOrder.js
ADDED
|
@@ -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
|
+
}
|