@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,437 @@
|
|
|
1
|
+
/*****************************************************************************
|
|
2
|
+
* OperationResult Model ver 1.0.0
|
|
3
|
+
* @author shisyamo4131
|
|
4
|
+
* ---------------------------------------------------------------------------
|
|
5
|
+
* - Extends Operation class to represent the result of an operation.
|
|
6
|
+
* - Also incorporates Agreement class properties for pricing and billing information.
|
|
7
|
+
* - Prevents deletion if the instance has `siteOperationScheduleId`.
|
|
8
|
+
* - Provides comprehensive billing calculations including statistics, sales amounts, and tax.
|
|
9
|
+
* - Supports both daily and hourly billing with adjusted quantities.
|
|
10
|
+
* ---------------------------------------------------------------------------
|
|
11
|
+
* @props {string|null} siteOperationScheduleId - Associated SiteOperationSchedule document ID
|
|
12
|
+
* - If this OperationResult was created from a SiteOperationSchedule, this property holds that ID.
|
|
13
|
+
* - If this property is set, the instance cannot be deleted.
|
|
14
|
+
* @props {boolean} useAdjustedQuantity - Flag to indicate if adjusted quantities are used for billing
|
|
15
|
+
* @props {number} adjustedQuantityBase - Adjusted quantity for base workers
|
|
16
|
+
* - Quantity used for billing base workers when `useAdjustedQuantity` is true.
|
|
17
|
+
* @props {number} adjustedOvertimeBase - Adjusted overtime for base workers
|
|
18
|
+
* - Overtime used for billing base workers when `useAdjustedQuantity` is true.
|
|
19
|
+
* @props {number} adjustedQuantityQualified - Adjusted quantity for qualified workers
|
|
20
|
+
* - Quantity used for billing qualified workers when `useAdjustedQuantity` is true.
|
|
21
|
+
* @props {number} adjustedOvertimeQualified - Adjusted overtime for qualified workers
|
|
22
|
+
* - Overtime used for billing qualified workers when `useAdjustedQuantity` is true.
|
|
23
|
+
* @props {Date} billingDateAt - Billing date
|
|
24
|
+
* ---------------------------------------------------------------------------
|
|
25
|
+
* @computed {Object} statistics - Statistics of workers (read-only)
|
|
26
|
+
* - Contains counts and total work minutes for base and qualified workers, including OJT breakdowns.
|
|
27
|
+
* - Structure: { base: {...}, qualified: {...}, total: {...} }
|
|
28
|
+
* - Each category contains: quantity, regularTimeWorkMinutes, overtimeWorkMinutes, totalWorkMinutes, breakMinutes
|
|
29
|
+
* - Each category also has an 'ojt' subcategory with the same structure.
|
|
30
|
+
* @computed {Object} sales - Sales amounts (read-only)
|
|
31
|
+
* - Contains sales calculations for base and qualified workers, including overtime breakdowns.
|
|
32
|
+
* - Structure: { base: {...}, qualified: {...} }
|
|
33
|
+
* - Each category contains: unitPrice, quantity, regularAmount, overtimeUnitPrice, overtimeMinutes, overtimeAmount, total
|
|
34
|
+
* - Calculations respect `useAdjustedQuantity`, `billingUnitType`, and `includeBreakInBilling` settings.
|
|
35
|
+
* @computed {number} salesAmount - Total sales amount (read-only)
|
|
36
|
+
* - Sum of sales amounts for base and qualified workers with rounding applied.
|
|
37
|
+
* @computed {number} tax - Calculated tax amount (read-only)
|
|
38
|
+
* - Calculated using the `Tax` utility based on `salesAmount` and `date`.
|
|
39
|
+
* @computed {number} billingAmount - Total billing amount including tax (read-only)
|
|
40
|
+
* - Sum of `salesAmount` and `tax`.
|
|
41
|
+
* ---------------------------------------------------------------------------
|
|
42
|
+
* @inherited - The following properties are inherited from Operation:
|
|
43
|
+
* @props {string} siteId - Site document ID (trigger property)
|
|
44
|
+
* - Automatically synchronizes to all `employees` and `outsourcers` when changed.
|
|
45
|
+
* @props {number} requiredPersonnel - Required number of personnel
|
|
46
|
+
* @props {boolean} qualificationRequired - Qualification required flag
|
|
47
|
+
* @props {string} workDescription - Work description
|
|
48
|
+
* @props {string} remarks - Remarks
|
|
49
|
+
* @props {Array<OperationResultDetail>} employees - Assigned employees
|
|
50
|
+
* - Array of `OperationResultDetail` instances representing assigned employees
|
|
51
|
+
* @props {Array<OperationResultDetail>} outsourcers - Assigned outsourcers
|
|
52
|
+
* - Array of `OperationResultDetail` instances representing assigned outsourcers
|
|
53
|
+
* ---------------------------------------------------------------------------
|
|
54
|
+
* @inherited - The following properties are inherited from Agreement (via Operation):
|
|
55
|
+
* @props {number} unitPriceBase - Base unit price (JPY)
|
|
56
|
+
* @props {number} overtimeUnitPriceBase - Overtime unit price (JPY/hour)
|
|
57
|
+
* @props {number} unitPriceQualified - Qualified unit price (JPY)
|
|
58
|
+
* @props {number} overtimeUnitPriceQualified - Qualified overtime unit price (JPY/hour)
|
|
59
|
+
* @props {string} billingUnitType - Billing unit type
|
|
60
|
+
* @props {boolean} includeBreakInBilling - Whether to include break time in billing if `billingUnitType` is `PER_HOUR`.
|
|
61
|
+
* @props {number} cutoffDate - Cutoff date value from CutoffDate.VALUES
|
|
62
|
+
* - The cutoff date for billing, using values defined in the CutoffDate utility class.
|
|
63
|
+
* ---------------------------------------------------------------------------
|
|
64
|
+
* @inherited - The following properties are inherited from WorkingResult (via Operation):
|
|
65
|
+
* @props {Date} dateAt - Date of operation (placement date) (trigger property)
|
|
66
|
+
* - Automatically synchronizes to all `employees` and `outsourcers` when changed.
|
|
67
|
+
* @props {string} dayType - Day type (e.g., `WEEKDAY`, `WEEKEND`, `HOLIDAY`)
|
|
68
|
+
* @props {string} shiftType - `DAY` or `NIGHT` (trigger property)
|
|
69
|
+
* - Automatically synchronizes to all `employees` and `outsourcers` when changed.
|
|
70
|
+
* @props {string} startTime - Start time (HH:MM format)
|
|
71
|
+
* @props {boolean} isStartNextDay - Next day start flag
|
|
72
|
+
* - `true` if the actual work starts the day after the placement date `dateAt`
|
|
73
|
+
* @props {string} endTime - End time (HH:MM format)
|
|
74
|
+
* @props {number} breakMinutes - Break time (minutes)
|
|
75
|
+
* @props {number} regulationWorkMinutes - Regulation work minutes (trigger property)
|
|
76
|
+
* - Indicates the maximum working time treated as regular working hours.
|
|
77
|
+
* - Automatically synchronizes to all `employees` and `outsourcers` when changed.
|
|
78
|
+
* ---------------------------------------------------------------------------
|
|
79
|
+
* @inherited - The following computed properties are inherited from Operation:
|
|
80
|
+
* @computed {Array<string>} employeeIds - Array of employee IDs from `employees` (read-only)
|
|
81
|
+
* @computed {Array<string>} outsourcerIds - Array of outsourcer IDs from `outsourcers` (read-only)
|
|
82
|
+
* @computed {number} employeesCount - Count of assigned employees (read-only)
|
|
83
|
+
* @computed {number} outsourcersCount - Count of assigned outsourcers (sum of amounts) (read-only)
|
|
84
|
+
* @computed {boolean} isPersonnelShortage - Indicates if there is a shortage of personnel (read-only)
|
|
85
|
+
* - `true` if the sum of `employeesCount` and `outsourcersCount` is less than `requiredPersonnel`
|
|
86
|
+
* @computed {Array<OperationResultDetail>} workers - Combined array of `employees` and `outsourcers`
|
|
87
|
+
* - Getter: Returns concatenated array of employees and outsourcers
|
|
88
|
+
* - Setter: Splits array into employees and outsourcers based on `isEmployee` property
|
|
89
|
+
* ---------------------------------------------------------------------------
|
|
90
|
+
* @inherited - The following computed properties are inherited from WorkingResult (via Operation):
|
|
91
|
+
* @computed {string} date - Date string in YYYY-MM-DD format based on `dateAt` (read-only)
|
|
92
|
+
* - Returns a string in the format YYYY-MM-DD based on `dateAt`.
|
|
93
|
+
* @computed {Date} startAt - Start date and time (Date object) (read-only)
|
|
94
|
+
* - Returns a Date object with `startTime` set based on `dateAt`.
|
|
95
|
+
* - If `isStartNextDay` is true, add 1 day.
|
|
96
|
+
* @computed {Date} endAt - End date and time (Date object) (read-only)
|
|
97
|
+
* - Returns a Date object with `endTime` set based on `dateAt`.
|
|
98
|
+
* - If `isStartNextDay` is true, add 1 day.
|
|
99
|
+
* - If `isSpansNextDay` is true, add 1 day.
|
|
100
|
+
* @computed {boolean} isSpansNextDay - Flag indicating whether the date spans from start date to end date (read-only)
|
|
101
|
+
* - `true` if `startTime` is later than `endTime`
|
|
102
|
+
* @computed {number} totalWorkMinutes - Total working time in minutes (excluding break time) (read-only)
|
|
103
|
+
* - Calculated as the difference between `endAt` and `startAt` minus `breakMinutes`
|
|
104
|
+
* @computed {number} regularTimeWorkMinutes - Regular working time in minutes (read-only)
|
|
105
|
+
* - The portion of `totalWorkMinutes` that is considered within the contract's `regulationWorkMinutes`.
|
|
106
|
+
* @computed {number} overtimeWorkMinutes - Overtime work in minutes (read-only)
|
|
107
|
+
* - Calculated as `totalWorkMinutes` minus `regulationWorkMinutes`
|
|
108
|
+
* ---------------------------------------------------------------------------
|
|
109
|
+
* @inherited - The following getter properties are inherited from Operation:
|
|
110
|
+
* @getter {string} groupKey - Combines `siteId`, `shiftType`, and `date` to indicate operation grouping (read-only)
|
|
111
|
+
* @getter {boolean} isEmployeesChanged - Indicates whether the employees have changed (read-only)
|
|
112
|
+
* - Returns true if the employee IDs have changed compared to `_beforeData`
|
|
113
|
+
* @getter {boolean} isOutsourcersChanged - Indicates whether the outsourcers have changed (read-only)
|
|
114
|
+
* - Returns true if the outsourcer IDs have changed compared to `_beforeData`
|
|
115
|
+
* @getter {Array<OperationResultDetail>} addedWorkers - An array of workers that have been added (read-only)
|
|
116
|
+
* - Workers that exist in current data but not in `_beforeData`
|
|
117
|
+
* @getter {Array<OperationResultDetail>} removedWorkers - An array of workers that have been removed (read-only)
|
|
118
|
+
* - Workers that exist in `_beforeData` but not in current data
|
|
119
|
+
* @getter {Array<OperationResultDetail>} updatedWorkers - An array of workers that have been updated (read-only)
|
|
120
|
+
* - Workers whose `startTime`, `isStartNextDay`, `endTime`, `breakMinutes`, `isQualified`, or `isOjt` have changed
|
|
121
|
+
* ---------------------------------------------------------------------------
|
|
122
|
+
* @inherited - The following getter properties are inherited from WorkingResult (via Operation):
|
|
123
|
+
* @getter {number} startHour - Start hour (0-23) (read-only)
|
|
124
|
+
* - Extracted from `startTime`.
|
|
125
|
+
* @getter {number} startMinute - Start minute (0-59) (read-only)
|
|
126
|
+
* - Extracted from `startTime`.
|
|
127
|
+
* @getter {number} endHour - End hour (0-23) (read-only)
|
|
128
|
+
* - Extracted from `endTime`.
|
|
129
|
+
* @getter {number} endMinute - End minute (0-59) (read-only)
|
|
130
|
+
* - Extracted from `endTime`.
|
|
131
|
+
* ---------------------------------------------------------------------------
|
|
132
|
+
* @method {function} beforeDelete - Override method to prevent deletion with siteOperationScheduleId
|
|
133
|
+
* - Prevents deletion if the instance has `siteOperationScheduleId`.
|
|
134
|
+
* - Throws an error if deletion is attempted on an instance created from SiteOperationSchedule.
|
|
135
|
+
* ---------------------------------------------------------------------------
|
|
136
|
+
* @inherited - The following methods are inherited from Operation:
|
|
137
|
+
* @method {function} addWorker - Adds a new worker (employee or outsourcer)
|
|
138
|
+
* - @param {Object} options - Options for adding a worker
|
|
139
|
+
* - @param {string} options.id - The worker ID (employeeId or outsourcerId)
|
|
140
|
+
* - @param {boolean} [options.isEmployee=true] - Whether the worker is an employee
|
|
141
|
+
* - @param {number} [index=0] - Insertion position. If -1, adds to the end
|
|
142
|
+
* @method {function} moveWorker - Moves the position of a worker (employee or outsourcer)
|
|
143
|
+
* - @param {Object} options - Options for changing worker position
|
|
144
|
+
* - @param {number} options.oldIndex - The original index
|
|
145
|
+
* - @param {number} options.newIndex - The new index
|
|
146
|
+
* - @param {boolean} [options.isEmployee=true] - True for employee, false for outsourcer
|
|
147
|
+
* @method {function} changeWorker - Changes the details of a worker
|
|
148
|
+
* - @param {Object} newWorker - New worker object
|
|
149
|
+
* @method {function} removeWorker - Removes a worker (employee or outsourcer)
|
|
150
|
+
* - @param {Object} options - Options for removing a worker
|
|
151
|
+
* - @param {string} options.workerId - The ID of the employee or outsourcer
|
|
152
|
+
* - @param {boolean} [options.isEmployee=true] - True for employee, false for outsourcer
|
|
153
|
+
* @method {function} setSiteIdCallback - Callback method called when `siteId` is set
|
|
154
|
+
* - Override this method in subclasses to add custom behavior when `siteId` changes.
|
|
155
|
+
* - By default, does nothing.
|
|
156
|
+
* - @param {string} v - The new `siteId` value
|
|
157
|
+
* @method {function} setShiftTypeCallback - Callback method called when `shiftType` is set
|
|
158
|
+
* - Override this method in subclasses to add custom behavior when `shiftType` changes.
|
|
159
|
+
* - By default, does nothing.
|
|
160
|
+
* - @param {string} v - The new `shiftType` value
|
|
161
|
+
* @method {function} setRegulationWorkMinutesCallback - Callback method called when `regulationWorkMinutes` is set
|
|
162
|
+
* - Override this method in subclasses to add custom behavior when `regulationWorkMinutes` changes.
|
|
163
|
+
* - By default, does nothing.
|
|
164
|
+
* - @param {number} v - The new `regulationWorkMinutes` value
|
|
165
|
+
* @static
|
|
166
|
+
* @method groupKeyDivider
|
|
167
|
+
* Returns an array dividing the key into siteId, shiftType, and date.
|
|
168
|
+
* @param {Object|string} key - The combined key string or object
|
|
169
|
+
* @returns {Array<string>} - Array containing [siteId, shiftType, date]
|
|
170
|
+
* @throws {Error} - If the key is invalid.
|
|
171
|
+
* ---------------------------------------------------------------------------
|
|
172
|
+
* @inherited - The following method is inherited from WorkingResult (via Operation):
|
|
173
|
+
* @method {function} setDateAtCallback - Callback method called when `dateAt` is set
|
|
174
|
+
* - Override this method in subclasses to add custom behavior when `dateAt` changes.
|
|
175
|
+
* - By default, updates `dayType` based on the new `dateAt` value and synchronizes to workers.
|
|
176
|
+
* - @param {Date} v - The new `dateAt` value
|
|
177
|
+
*****************************************************************************/
|
|
178
|
+
import Operation from "./Operation.js";
|
|
179
|
+
import Agreement from "./Agreement.js";
|
|
180
|
+
import { ContextualError } from "./utils/ContextualError.js";
|
|
181
|
+
import OperationResultDetail from "./OperationResultDetail.js";
|
|
182
|
+
import { defField } from "./parts/fieldDefinitions.js";
|
|
183
|
+
import Tax from "./tax.js";
|
|
184
|
+
import { BILLING_UNIT_TYPE_PER_HOUR } from "./constants/billing-unit-type.js";
|
|
185
|
+
import RoundSetting from "./RoundSetting.js";
|
|
186
|
+
import CutoffDate from "./utils/CutoffDate.js";
|
|
187
|
+
|
|
188
|
+
const classProps = {
|
|
189
|
+
...Operation.classProps,
|
|
190
|
+
...Agreement.classProps,
|
|
191
|
+
cutoffDate: defField("select", {
|
|
192
|
+
label: "締日区分",
|
|
193
|
+
default: CutoffDate.VALUES.END_OF_MONTH,
|
|
194
|
+
required: true,
|
|
195
|
+
hidden: true,
|
|
196
|
+
component: {
|
|
197
|
+
attrs: {
|
|
198
|
+
items: CutoffDate.OPTIONS,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
202
|
+
siteOperationScheduleId: defField("oneLine", { hidden: true }),
|
|
203
|
+
useAdjustedQuantity: defField("check", {
|
|
204
|
+
label: "調整数量を使用",
|
|
205
|
+
default: false,
|
|
206
|
+
}),
|
|
207
|
+
adjustedQuantityBase: defField("number", {
|
|
208
|
+
label: "基本人工(調整)",
|
|
209
|
+
default: 0,
|
|
210
|
+
}),
|
|
211
|
+
adjustedOvertimeBase: defField("number", {
|
|
212
|
+
label: "基本残業(調整)",
|
|
213
|
+
default: 0,
|
|
214
|
+
}),
|
|
215
|
+
adjustedQuantityQualified: defField("number", {
|
|
216
|
+
label: "資格人工(調整)",
|
|
217
|
+
default: 0,
|
|
218
|
+
}),
|
|
219
|
+
adjustedOvertimeQualified: defField("number", {
|
|
220
|
+
label: "資格残業(調整)",
|
|
221
|
+
default: 0,
|
|
222
|
+
}),
|
|
223
|
+
billingDateAt: defField("dateAt", { label: "請求日付", required: true }),
|
|
224
|
+
employees: defField("array", { customClass: OperationResultDetail }),
|
|
225
|
+
outsourcers: defField("array", {
|
|
226
|
+
customClass: OperationResultDetail,
|
|
227
|
+
}),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export default class OperationResult extends Operation {
|
|
231
|
+
static className = "稼働実績";
|
|
232
|
+
static collectionPath = "OperationResults";
|
|
233
|
+
static useAutonumber = false;
|
|
234
|
+
static logicalDelete = false;
|
|
235
|
+
static classProps = classProps;
|
|
236
|
+
|
|
237
|
+
static headers = [
|
|
238
|
+
{ title: "日付", key: "dateAt" },
|
|
239
|
+
{ title: "現場", key: "siteId", value: "siteId" },
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* afterInitialize
|
|
244
|
+
*/
|
|
245
|
+
afterInitialize() {
|
|
246
|
+
super.afterInitialize();
|
|
247
|
+
|
|
248
|
+
/** Computed properties */
|
|
249
|
+
Object.defineProperties(this, {
|
|
250
|
+
statistics: {
|
|
251
|
+
configurable: true,
|
|
252
|
+
enumerable: true,
|
|
253
|
+
get() {
|
|
254
|
+
const initialValues = {
|
|
255
|
+
quantity: 0,
|
|
256
|
+
regularTimeWorkMinutes: 0,
|
|
257
|
+
overtimeWorkMinutes: 0,
|
|
258
|
+
totalWorkMinutes: 0,
|
|
259
|
+
breakMinutes: 0,
|
|
260
|
+
};
|
|
261
|
+
const result = {
|
|
262
|
+
base: { ...initialValues, ojt: { ...initialValues } },
|
|
263
|
+
qualified: { ...initialValues, ojt: { ...initialValues } },
|
|
264
|
+
total: { ...initialValues, ojt: { ...initialValues } },
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// 各カテゴリに値を追加する関数
|
|
268
|
+
const addToCategory = (categoryObj, worker, isOjt) => {
|
|
269
|
+
const target = isOjt ? categoryObj.ojt : categoryObj;
|
|
270
|
+
target.quantity += 1;
|
|
271
|
+
target.regularTimeWorkMinutes += worker.regularTimeWorkMinutes;
|
|
272
|
+
target.overtimeWorkMinutes += worker.overtimeWorkMinutes;
|
|
273
|
+
target.totalWorkMinutes += worker.totalWorkMinutes;
|
|
274
|
+
target.breakMinutes += worker.breakMinutes;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
this.workers.forEach((worker) => {
|
|
278
|
+
const category = worker.isQualified ? "qualified" : "base";
|
|
279
|
+
const isOjt = worker.isOjt;
|
|
280
|
+
|
|
281
|
+
// 該当カテゴリ(base/qualified)に追加
|
|
282
|
+
addToCategory(result[category], worker, isOjt);
|
|
283
|
+
|
|
284
|
+
// 全体合計に追加
|
|
285
|
+
addToCategory(result.total, worker, isOjt);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
return result;
|
|
289
|
+
},
|
|
290
|
+
set(v) {},
|
|
291
|
+
},
|
|
292
|
+
sales: {
|
|
293
|
+
configurable: true,
|
|
294
|
+
enumerable: true,
|
|
295
|
+
get() {
|
|
296
|
+
const createInitialValues = () => ({
|
|
297
|
+
unitPrice: 0,
|
|
298
|
+
quantity: 0,
|
|
299
|
+
regularAmount: 0,
|
|
300
|
+
overtimeUnitPrice: 0,
|
|
301
|
+
overtimeMinutes: 0,
|
|
302
|
+
overtimeAmount: 0,
|
|
303
|
+
total: 0,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const calculateCategorySales = (category) => {
|
|
307
|
+
const isQualified = category === "qualified";
|
|
308
|
+
const categoryStats = this.statistics?.[category];
|
|
309
|
+
|
|
310
|
+
// 統計データが存在しない場合は警告を出力して初期値を返す
|
|
311
|
+
if (!categoryStats) {
|
|
312
|
+
console.warn(
|
|
313
|
+
`[OperationResult] Statistics data for category '${category}' is missing.`,
|
|
314
|
+
{
|
|
315
|
+
docId: this.docId,
|
|
316
|
+
dateAt: this.dateAt,
|
|
317
|
+
siteId: this.siteId,
|
|
318
|
+
category,
|
|
319
|
+
statistics: this.statistics,
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
return createInitialValues();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const unitPrice = isQualified
|
|
326
|
+
? this.unitPriceQualified || 0
|
|
327
|
+
: this.unitPriceBase || 0;
|
|
328
|
+
const overtimeUnitPrice = isQualified
|
|
329
|
+
? this.overtimeUnitPriceQualified || 0
|
|
330
|
+
: this.overtimeUnitPriceBase || 0;
|
|
331
|
+
const isPerHour =
|
|
332
|
+
this.billingUnitType === BILLING_UNIT_TYPE_PER_HOUR;
|
|
333
|
+
|
|
334
|
+
const result = createInitialValues();
|
|
335
|
+
|
|
336
|
+
// 基本情報の設定
|
|
337
|
+
result.unitPrice = unitPrice;
|
|
338
|
+
result.overtimeUnitPrice = overtimeUnitPrice;
|
|
339
|
+
|
|
340
|
+
// 調整値の使用判定
|
|
341
|
+
if (this.useAdjustedQuantity) {
|
|
342
|
+
result.quantity = isQualified
|
|
343
|
+
? this.adjustedQuantityQualified || 0
|
|
344
|
+
: this.adjustedQuantityBase || 0;
|
|
345
|
+
result.overtimeMinutes = isQualified
|
|
346
|
+
? this.adjustedOvertimeQualified || 0
|
|
347
|
+
: this.adjustedOvertimeBase || 0;
|
|
348
|
+
} else {
|
|
349
|
+
// result.quantity = isPerHour
|
|
350
|
+
// ? (categoryStats.totalWorkMinutes || 0) / 60
|
|
351
|
+
// : categoryStats.quantity || 0;
|
|
352
|
+
// result.overtimeMinutes = categoryStats.overtimeWorkMinutes || 0;
|
|
353
|
+
if (isPerHour) {
|
|
354
|
+
// 時間単位請求の場合
|
|
355
|
+
let totalMinutes = categoryStats.totalWorkMinutes || 0;
|
|
356
|
+
|
|
357
|
+
// 休憩時間を請求に含める場合は休憩時間を追加
|
|
358
|
+
if (this.includeBreakInBilling) {
|
|
359
|
+
totalMinutes += categoryStats.breakMinutes || 0;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
result.quantity = totalMinutes / 60;
|
|
363
|
+
} else {
|
|
364
|
+
// 日単位請求の場合(休憩時間は関係なし)
|
|
365
|
+
result.quantity = categoryStats.quantity || 0;
|
|
366
|
+
}
|
|
367
|
+
result.overtimeMinutes = categoryStats.overtimeWorkMinutes || 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// 金額計算(RoundSettingを適用)
|
|
371
|
+
result.regularAmount = RoundSetting.apply(
|
|
372
|
+
result.quantity * unitPrice
|
|
373
|
+
);
|
|
374
|
+
result.overtimeAmount = RoundSetting.apply(
|
|
375
|
+
(result.overtimeMinutes * overtimeUnitPrice) / 60
|
|
376
|
+
);
|
|
377
|
+
result.total = result.regularAmount + result.overtimeAmount;
|
|
378
|
+
|
|
379
|
+
return result;
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const base = calculateCategorySales("base");
|
|
383
|
+
const qualified = calculateCategorySales("qualified");
|
|
384
|
+
|
|
385
|
+
return { base, qualified };
|
|
386
|
+
},
|
|
387
|
+
set(v) {},
|
|
388
|
+
},
|
|
389
|
+
salesAmount: {
|
|
390
|
+
configurable: true,
|
|
391
|
+
enumerable: true,
|
|
392
|
+
get() {
|
|
393
|
+
const amount = this.sales.base.total + this.sales.qualified.total;
|
|
394
|
+
return RoundSetting.apply(amount);
|
|
395
|
+
},
|
|
396
|
+
set(v) {},
|
|
397
|
+
},
|
|
398
|
+
tax: {
|
|
399
|
+
configurable: true,
|
|
400
|
+
enumerable: true,
|
|
401
|
+
get() {
|
|
402
|
+
try {
|
|
403
|
+
return Tax.calc(this.salesAmount, this.date);
|
|
404
|
+
} catch (error) {
|
|
405
|
+
throw new ContextualError("Failed to calculate tax", {
|
|
406
|
+
method: "OperationResult.tax (computed)",
|
|
407
|
+
arguments: { amount: this.salesAmount, date: this.date },
|
|
408
|
+
error,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
set(v) {},
|
|
413
|
+
},
|
|
414
|
+
billingAmount: {
|
|
415
|
+
configurable: true,
|
|
416
|
+
enumerable: true,
|
|
417
|
+
get() {
|
|
418
|
+
return this.salesAmount + this.tax;
|
|
419
|
+
},
|
|
420
|
+
set(v) {},
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Override `beforeDelete`.
|
|
427
|
+
* - Prevents deletion if the instance has `siteOperationScheduleId`.
|
|
428
|
+
*/
|
|
429
|
+
async beforeDelete() {
|
|
430
|
+
await super.beforeDelete();
|
|
431
|
+
if (this.siteOperationScheduleId) {
|
|
432
|
+
throw new Error(
|
|
433
|
+
"この稼働実績は現場稼働予定から作成されているため、削除できません。"
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*****************************************************************************
|
|
2
|
+
* OperationResultDetail Model ver 1.0.0
|
|
3
|
+
* @author shisyamo4131
|
|
4
|
+
* ---------------------------------------------------------------------------
|
|
5
|
+
* - Model representing the details of an operation result.
|
|
6
|
+
* - Extends OperationDetail.
|
|
7
|
+
* ---------------------------------------------------------------------------
|
|
8
|
+
* @inherited - The following properties are inherited from OperationDetail:
|
|
9
|
+
* @props {string} id - Employee or Outsourcer document ID
|
|
10
|
+
* @props {number} index - Identifier index for Outsourcer (always 0 for Employee)
|
|
11
|
+
* @props {boolean} isEmployee - Employee flag (true: Employee, false: Outsourcer)
|
|
12
|
+
* @props {number} amount - Number of placements (always fixed at 1)
|
|
13
|
+
* @props {string} siteId - Site ID
|
|
14
|
+
* @props {boolean} isQualified - Qualified flag
|
|
15
|
+
* @props {boolean} isOjt - OJT flag
|
|
16
|
+
* @props {Date} dateAt - Placement date
|
|
17
|
+
* @props {string} dayType - Day type (e.g., `WEEKDAY`, `WEEKEND`, `HOLIDAY`)
|
|
18
|
+
* @props {string} shiftType - `DAY` or `NIGHT`
|
|
19
|
+
* @props {string} startTime - Start time (HH:MM format)
|
|
20
|
+
* @props {boolean} isStartNextDay - Next day start flag
|
|
21
|
+
* @props {string} endTime - End time (HH:MM format)
|
|
22
|
+
* @props {number} breakMinutes - Break time (minutes)
|
|
23
|
+
* @props {number} regulationWorkMinutes - Regulation work minutes
|
|
24
|
+
* --------------------------------------------------------------------------
|
|
25
|
+
* @inherited - The following computed properties are inherited from OperationDetail:
|
|
26
|
+
* @computed {string} workerId - Worker ID
|
|
27
|
+
* - For Employee, it's the same as `id`, for Outsourcer, it's a concatenation of `id` and `index` with ':'
|
|
28
|
+
* @computed {string|null} employeeId - Employee ID (null if not applicable)
|
|
29
|
+
* @computed {string|null} outsourcerId - Outsourcer ID (null if not applicable)
|
|
30
|
+
* @computed {number} overtimeWorkMinutes - Overtime work in minutes
|
|
31
|
+
* - Calculated as `totalWorkMinutes` minus `regulationWorkMinutes`
|
|
32
|
+
* - Overtime work is not negative; the minimum is 0.
|
|
33
|
+
* @computed {string} key - Unique key combining `date`, `dayType`, and `shiftType`
|
|
34
|
+
* @computed {string} date - Date string in YYYY-MM-DD format based on `dateAt`
|
|
35
|
+
* @computed {boolean} isSpansNextDay - Flag indicating whether the date spans from start date to end date
|
|
36
|
+
* @computed {Date} startAt - Start date and time (Date object)
|
|
37
|
+
* @computed {Date} endAt - End date and time (Date object)
|
|
38
|
+
* @computed {number} totalWorkMinutes - Total working time in minutes (excluding break time)
|
|
39
|
+
* @computed {number} regularTimeWorkMinutes - Regular working time in minutes
|
|
40
|
+
* --------------------------------------------------------------------------
|
|
41
|
+
* @inherited - The following accessor properties are inherited from OperationDetail:
|
|
42
|
+
* @accessor {number} startHour - Start hour (0-23)
|
|
43
|
+
* - Extracted from `startTime`.
|
|
44
|
+
* @accessor {number} startMinute - Start minute (0-59)
|
|
45
|
+
* - Extracted from `startTime`.
|
|
46
|
+
* @accessor {number} endHour - End hour (0-23)
|
|
47
|
+
* - Extracted from `endTime`.
|
|
48
|
+
* @accessor {number} endMinute - End minute (0-59)
|
|
49
|
+
* - Extracted from `endTime`.
|
|
50
|
+
* @accessor {number} breakHours - Break time in hours (converts to/from breakMinutes)
|
|
51
|
+
* - Accessor for break time in hours.
|
|
52
|
+
* @accessor {number} overtimeWorkHours - Overtime work in hours (converts to/from overtimeWorkMinutes)
|
|
53
|
+
* ---------------------------------------------------------------------------
|
|
54
|
+
* @inherited - The following method is inherited from WorkingResult:
|
|
55
|
+
* @method {function} setDateAtCallback - Callback method called when `dateAt` is set
|
|
56
|
+
* - Override this method in subclasses to add custom behavior when `dateAt` changes.
|
|
57
|
+
* - By default, updates `dayType` based on the new `dateAt` value.
|
|
58
|
+
* - @param {Date} v - The new `dateAt` value
|
|
59
|
+
*****************************************************************************/
|
|
60
|
+
import OperationDetail from "./OperationDetail.js";
|
|
61
|
+
|
|
62
|
+
const headers = [
|
|
63
|
+
{ title: "名前", key: "displayName" },
|
|
64
|
+
{ title: "開始", key: "startTime" },
|
|
65
|
+
{ title: "終了", key: "endTime" },
|
|
66
|
+
{ title: "休憩", key: "breakMinutes" },
|
|
67
|
+
{ title: "残業", key: "overtimeWorkMinutes" },
|
|
68
|
+
];
|
|
69
|
+
export default class OperationResultDetail extends OperationDetail {
|
|
70
|
+
static className = "稼働実績明細";
|
|
71
|
+
static headers = headers;
|
|
72
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/Outsourcer.js
|
|
3
|
+
* @author shisyamo4131
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
import FireModel from "@shisyamo4131/air-firebase-v2";
|
|
7
|
+
import { defField } from "./parts/fieldDefinitions.js";
|
|
8
|
+
import { VALUES } from "./constants/contract-status.js";
|
|
9
|
+
|
|
10
|
+
const classProps = {
|
|
11
|
+
code: defField("code", { label: "外注先コード" }),
|
|
12
|
+
name: defField("name", { required: true }),
|
|
13
|
+
nameKana: defField("nameKana", { required: true }),
|
|
14
|
+
displayName: defField("displayName", { label: "略称", required: true }),
|
|
15
|
+
contractStatus: defField("contractStatus", { required: true }),
|
|
16
|
+
remarks: defField("multipleLine", { label: "備考" }),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @extends FireModel
|
|
21
|
+
*
|
|
22
|
+
* @props {string} code - Outsourcer code.
|
|
23
|
+
* @props {string} name - Outsourcer name.
|
|
24
|
+
* @props {string} nameKana - Outsourcer name in Kana.
|
|
25
|
+
* @props {string} displayName - Abbreviated name.
|
|
26
|
+
* @props {string} contractStatus - Contract status.
|
|
27
|
+
* @props {string} remarks - Additional remarks.
|
|
28
|
+
*/
|
|
29
|
+
export default class Outsourcer extends FireModel {
|
|
30
|
+
static className = "外注先";
|
|
31
|
+
static collectionPath = "Outsourcers";
|
|
32
|
+
static useAutonumber = false;
|
|
33
|
+
static logicalDelete = true;
|
|
34
|
+
static classProps = classProps;
|
|
35
|
+
|
|
36
|
+
static tokenFields = ["name", "nameKana", "displayName"];
|
|
37
|
+
|
|
38
|
+
static headers = [
|
|
39
|
+
{ title: "外注先コード", key: "code" },
|
|
40
|
+
{ title: "外注先名", key: "name" },
|
|
41
|
+
{ title: "略称", key: "displayName" },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
static STATUS_ACTIVE = VALUES.ACTIVE.value;
|
|
45
|
+
static STATUS_TERMINATED = VALUES.TERMINATED.value;
|
|
46
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*****************************************************************************
|
|
2
|
+
* RoundSetting Model ver 1.0.0
|
|
3
|
+
* @author shisyamo4131
|
|
4
|
+
* ---------------------------------------------------------------------------
|
|
5
|
+
* - A class for managing rounding settings.
|
|
6
|
+
* - Provides static states for easy access to rounding modes.
|
|
7
|
+
* - Can get current rounding mode via `RoundSetting` directly.
|
|
8
|
+
* ---------------------------------------------------------------------------
|
|
9
|
+
* @props {string} operationResultSales - Rounding mode for operation result sales
|
|
10
|
+
* @props {string} operationResultTax - Rounding mode for operation result tax
|
|
11
|
+
* ---------------------------------------------------------------------------
|
|
12
|
+
* @static FLOOR - Rounding mode: Floor
|
|
13
|
+
* @static ROUND - Rounding mode: Round
|
|
14
|
+
* @static CEIL - Rounding mode: Ceil
|
|
15
|
+
* ---------------------------------------------------------------------------
|
|
16
|
+
* @method static set(value) - Sets the rounding mode
|
|
17
|
+
* @method static validate(value) - Validates the rounding mode
|
|
18
|
+
* @method static round(value, mode, precision) - Rounds a number based on the specified mode and precision
|
|
19
|
+
* @method static apply(value, precision) - Rounds a number using the current setting
|
|
20
|
+
* ---------------------------------------------------------------------------
|
|
21
|
+
* @example
|
|
22
|
+
* // Rounding examples
|
|
23
|
+
* RoundSetting.round(123.456, RoundSetting.FLOOR); // Returns: 123
|
|
24
|
+
* RoundSetting.round(123.456, RoundSetting.ROUND); // Returns: 123
|
|
25
|
+
* RoundSetting.round(123.456, RoundSetting.CEIL); // Returns: 124
|
|
26
|
+
* RoundSetting.round(123.456, RoundSetting.ROUND, 2); // Returns: 123.46
|
|
27
|
+
*
|
|
28
|
+
* // Using current setting
|
|
29
|
+
* RoundSetting.set(RoundSetting.ROUND); // Set to Round mode
|
|
30
|
+
* RoundSetting.apply(123.456); // Uses current setting
|
|
31
|
+
*/
|
|
32
|
+
const _DEFINITIONS = Object.freeze({
|
|
33
|
+
FLOOR: { key: "FLOOR", label: "切り捨て", order: 0 },
|
|
34
|
+
ROUND: { key: "ROUND", label: "四捨五入", order: 1 },
|
|
35
|
+
CEIL: { key: "CEIL", label: "切り上げ", order: 2 },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const _ARRAY = Object.values(_DEFINITIONS).map((def) => ({
|
|
39
|
+
key: def.key,
|
|
40
|
+
label: def.label,
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
const _ITEMS = _ARRAY.map((item) => ({
|
|
44
|
+
title: item.label,
|
|
45
|
+
value: item.key,
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
export default class RoundSetting {
|
|
49
|
+
/** Provides all rounding modes */
|
|
50
|
+
static FLOOR = _DEFINITIONS.FLOOR.key;
|
|
51
|
+
static ROUND = _DEFINITIONS.ROUND.key;
|
|
52
|
+
static CEIL = _DEFINITIONS.CEIL.key;
|
|
53
|
+
|
|
54
|
+
static ITEMS = _ITEMS;
|
|
55
|
+
|
|
56
|
+
/** Static states */
|
|
57
|
+
static _mode = _DEFINITIONS.ROUND.key;
|
|
58
|
+
static set(value) {
|
|
59
|
+
this.validate(value);
|
|
60
|
+
this._mode = value;
|
|
61
|
+
}
|
|
62
|
+
static [Symbol.toPrimitive]() {
|
|
63
|
+
return this._mode;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static label(value) {
|
|
67
|
+
this.validate(value);
|
|
68
|
+
return _DEFINITIONS[value].label;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static validate(value) {
|
|
72
|
+
if (!Object.values(_DEFINITIONS).some((def) => def.key === value)) {
|
|
73
|
+
throw new Error(`Invalid rounding value: ${value}`);
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Rounds a number based on the specified rounding mode
|
|
80
|
+
* @param {number} value - The number to round
|
|
81
|
+
* @param {string} mode - The rounding mode (FLOOR, ROUND, CEIL)
|
|
82
|
+
* @param {number} precision - Number of decimal places (default: 0)
|
|
83
|
+
* @returns {number} The rounded number
|
|
84
|
+
*/
|
|
85
|
+
static round(value, mode = null, precision = 0) {
|
|
86
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
87
|
+
throw new Error("Value must be a valid number");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const roundingMode = mode || this._mode;
|
|
91
|
+
this.validate(roundingMode);
|
|
92
|
+
|
|
93
|
+
const factor = Math.pow(10, precision);
|
|
94
|
+
const scaledValue = value * factor;
|
|
95
|
+
|
|
96
|
+
let result;
|
|
97
|
+
switch (roundingMode) {
|
|
98
|
+
case this.FLOOR:
|
|
99
|
+
result = Math.floor(scaledValue);
|
|
100
|
+
break;
|
|
101
|
+
case this.ROUND:
|
|
102
|
+
result = Math.round(scaledValue);
|
|
103
|
+
break;
|
|
104
|
+
case this.CEIL:
|
|
105
|
+
result = Math.ceil(scaledValue);
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
throw new Error(`Unsupported rounding mode: ${roundingMode}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return result / factor;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Rounds using current setting
|
|
116
|
+
* @param {number} value - The number to round
|
|
117
|
+
* @param {number} precision - Number of decimal places (default: 0)
|
|
118
|
+
* @returns {number} The rounded number
|
|
119
|
+
*/
|
|
120
|
+
static apply(value, precision = 0) {
|
|
121
|
+
return this.round(value, this._mode, precision);
|
|
122
|
+
}
|
|
123
|
+
}
|