@shisyamo4131/air-guard-v2-schemas 2.4.2-dev.8 → 2.4.2-dev.81

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 (48) hide show
  1. package/index.js +12 -0
  2. package/package.json +45 -47
  3. package/src/Agreement.js +17 -24
  4. package/src/AgreementV2.js +185 -0
  5. package/src/ArrangementNotification.js +16 -8
  6. package/src/Billing.js +5 -34
  7. package/src/Company.js +162 -25
  8. package/src/Customer.js +39 -59
  9. package/src/Employee.js +590 -300
  10. package/src/FcmToken.js +73 -0
  11. package/src/Insurance.js +409 -0
  12. package/src/Notification.js +95 -0
  13. package/src/NotificationRecipient.js +68 -0
  14. package/src/Operation.js +272 -280
  15. package/src/OperationBilling.js +126 -192
  16. package/src/OperationDetail.js +115 -85
  17. package/src/OperationResult.js +257 -254
  18. package/src/OperationResultDetail.js +65 -56
  19. package/src/Site.js +160 -137
  20. package/src/SiteOperationSchedule.js +187 -247
  21. package/src/SiteOperationScheduleDetail.js +75 -65
  22. package/src/SiteOrder.js +18 -29
  23. package/src/User.js +44 -47
  24. package/src/WorkTimeBase.js +205 -0
  25. package/src/WorkingResult.js +83 -255
  26. package/src/constants/day-type.js +20 -12
  27. package/src/constants/employment-status.js +2 -2
  28. package/src/constants/index.js +4 -0
  29. package/src/constants/insurance-status.js +15 -0
  30. package/src/constants/shift-type.js +5 -2
  31. package/src/errorDefinitions.js +173 -0
  32. package/src/parts/fieldDefinitions/array.js +50 -0
  33. package/src/parts/fieldDefinitions/check.js +53 -0
  34. package/src/parts/fieldDefinitions/code.js +8 -0
  35. package/src/parts/fieldDefinitions/constants.js +9 -0
  36. package/src/parts/fieldDefinitions/dateAt.js +63 -0
  37. package/src/parts/fieldDefinitions/dateTimeAt.js +8 -0
  38. package/src/parts/fieldDefinitions/defaultDefinition.js +118 -0
  39. package/src/parts/fieldDefinitions/multipleLine.js +16 -0
  40. package/src/parts/fieldDefinitions/number.js +69 -0
  41. package/src/parts/fieldDefinitions/object.js +38 -0
  42. package/src/parts/fieldDefinitions/oneLine.js +409 -0
  43. package/src/parts/fieldDefinitions/radio.js +8 -0
  44. package/src/parts/fieldDefinitions/select.js +267 -0
  45. package/src/parts/fieldDefinitions/time.js +8 -0
  46. package/src/parts/fieldDefinitions.js +46 -669
  47. package/src/utils/CutoffDate.js +11 -15
  48. package/src/utils/index.js +44 -8
@@ -1,191 +1,153 @@
1
1
  /*****************************************************************************
2
- * OperationResult Model
2
+ * @file ./src/OperationResult.js
3
3
  * @author shisyamo4131
4
+ * @description 稼働実績クラス
5
+ * ### ドキュメント作成前処理
6
+ * - `siteId` から `customerId` を同期し、関連する `agreement` を適用します。
4
7
  *
5
- * - Extends Operation class to represent the result of an operation.
6
- * - Also incorporates Agreement class properties for pricing and billing information.
7
- * - Provides comprehensive billing calculations including statistics, sales amounts, and tax.
8
- * - Supports both daily and hourly billing with adjusted quantities.
9
- * - Automatically updates `billingDateAt` based on `dateAt` and `cutoffDate`.
10
- * - Introduces a lock mechanism (`isLocked`) to prevent edits when necessary.
8
+ * ### ドキュメント更新前処理
9
+ * - 更新前および更新後の `isLocked` true の場合は編集不可とします。(`isLocked` `OperationBilling` クラスで更新されます。)
10
+ * - `groupKey` が変更された場合は `customerId` の同期と `agreement` の適用を行います。
11
11
  *
12
- * @property { string } key - {@link Operation#key}
12
+ * @class
13
+ * @extends Operation
14
+ * @abstract
15
+ * @see OperationDetail
13
16
  *
14
- * @property {string} agreementKey - {@link Operation#agreementKey}
15
- *
16
- * @property {string} orderKey - {@link Operation#orderKey}
17
- *
18
- * @property {string} siteId - Site document ID (trigger property)
19
- * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
20
- *
21
- * @property {Date} dateAt - Date of operation (placement date) (trigger property)
22
- * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
23
- * - Used to determine `dayType`.
24
- * - When `dateAt` changes, `billingDateAt` is also updated based on `agreement.cutoffDate`.
25
- * @property {string} dayType - Day type (e.g., `WEEKDAY`, `WEEKEND`, `HOLIDAY`)
26
- * @property {string} shiftType - `DAY` or `NIGHT` (trigger property)
27
- * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
28
- * @property {string} startTime - Start time (HH:MM format)
29
- * @property {boolean} isStartNextDay - Next day start flag
30
- * - `true` if the actual work starts the day after the placement date `dateAt`
31
- * @property {string} endTime - End time (HH:MM format)
32
- * @property {number} breakMinutes - Break time (minutes)
33
- * @property {number} regulationWorkMinutes - Regulation work minutes (trigger property)
34
- * - Indicates the maximum working time treated as regular working hours.
35
- * - Automatically synchronizes to all `employees` and `outsourcers` when changed.
36
- * @property {number} requiredPersonnel - Required number of personnel
37
- * @property {boolean} qualificationRequired - Qualification required flag
38
- * @property {string} workDescription - Work description
39
- * @property {string} remarks - Remarks
40
- * @property {Array<OperationResultDetail>} employees - Assigned employees
41
- * - Array of `OperationResultDetail` instances representing assigned employees
42
- * @property {Array<OperationResultDetail>} outsourcers - Assigned outsourcers
43
- * - Array of `OperationResultDetail` instances representing assigned outsourcers
44
- * @property {Array<OperationResultDetail>} workers - Combined array of `employees` and `outsourcers`
45
- * - Getter: Returns concatenated array of employees and outsourcers
46
- * - Setter: Splits array into employees and outsourcers based on `isEmployee` property
47
- * @property {string|null} siteOperationScheduleId - Associated SiteOperationSchedule document ID
48
- * - If this OperationResult was created from a SiteOperationSchedule, this property holds that ID.
49
- * @property {boolean} useAdjustedQuantity - Flag to indicate if adjusted quantities are used for billing
50
- * @property {number} adjustedQuantityBase - Adjusted quantity for base workers
51
- * - Quantity used for billing base workers when `useAdjustedQuantity` is true.
52
- * @property {number} adjustedOvertimeBase - Adjusted overtime for base workers
53
- * - Overtime used for billing base workers when `useAdjustedQuantity` is true.
54
- * @property {number} adjustedQuantityQualified - Adjusted quantity for qualified workers
55
- * - Quantity used for billing qualified workers when `useAdjustedQuantity` is true.
56
- * @property {number} adjustedOvertimeQualified - Adjusted overtime for qualified workers
57
- * - Overtime used for billing qualified workers when `useAdjustedQuantity` is true.
58
- * @property {Date} billingDateAt - Billing date
59
- * - The date used for billing purposes.
60
- * @property {boolean} isLocked - Lock flag
61
- * - When set to true, the OperationResult is locked from edits exept for editing as OperationBilling.
62
- * @property {Agreement|null} agreement - Associated Agreement object
63
- * - The Agreement instance associated with this OperationResult for pricing and billing information.
64
- * - When set, it influences billing calculations such as unit prices and billing dates.
65
- * @property {boolean} allowEmptyAgreement - Flag to ignore missing Agreement
66
- * - When set to true, allows the OperationResult to be valid even if no Agreement is associated.
67
- * @readonly
68
- * @property {string} date - Date string in YYYY-MM-DD format based on `dateAt` (read-only)
69
- * - Returns a string in the format YYYY-MM-DD based on `dateAt`.
70
- * @property {Date} startAt - Start date and time (Date object) (read-only)
71
- * - Returns a Date object with `startTime` set based on `dateAt`.
72
- * - If `isStartNextDay` is true, add 1 day.
73
- * @property {Date} endAt - End date and time (Date object) (read-only)
74
- * - Returns a Date object with `endTime` set based on `dateAt`.
75
- * - If `isStartNextDay` is true, add 1 day.
76
- * - If `isSpansNextDay` is true, add 1 day.
77
- * @property {boolean} isSpansNextDay - Flag indicating whether the date spans from start date to end date (read-only)
78
- * - `true` if `startTime` is later than `endTime`
79
- * @property {number} totalWorkMinutes - Total working time in minutes (excluding break time) (read-only)
80
- * - Calculated as the difference between `endAt` and `startAt` minus `breakMinutes`
81
- * @property {number} regularTimeWorkMinutes - Regular working time in minutes (read-only)
82
- * - The portion of `totalWorkMinutes` that is considered within the contract's `regulationWorkMinutes`.
83
- * @property {number} overtimeWorkMinutes - Overtime work in minutes (read-only)
84
- * - Calculated as `totalWorkMinutes` minus `regulationWorkMinutes`
85
- * @property {boolean} hasAgreement - Indicates if an Agreement is associated (read-only)
86
- * - `true` if `agreement` is set, otherwise `false`.
87
- * @property {string|false} isInvalid - Validation status (read-only)
88
- * - Returns false if valid.
89
- * - Returns reason code string if invalid:
90
- * - `EMPTY_BILLING_DATE`: Billing date is missing.
91
- * - `EMPTY_AGREEMENT`: Agreement is missing and `allowEmptyAgreement` is false.
92
- * @property {Object} statistics - Statistics of workers (read-only)
93
- * - Contains counts and total work minutes for base and qualified workers, including OJT breakdowns.
94
- * - Structure: { base: {...}, qualified: {...}, total: {...} }
95
- * - Each category contains: quantity, regularTimeWorkMinutes, overtimeWorkMinutes, totalWorkMinutes, breakMinutes
96
- * - Each category also has an 'ojt' subcategory with the same structure.
97
- * @property {Object} sales - Sales amounts (read-only)
98
- * - Contains sales calculations for base and qualified workers, including overtime breakdowns.
99
- * - Structure: { base: {...}, qualified: {...} }
100
- * - Each category contains: unitPrice, quantity, regularAmount, overtimeUnitPrice, overtimeMinutes, overtimeAmount, total
101
- * - Calculations respect `useAdjustedQuantity`, `billingUnitType`, and `includeBreakInBilling` settings.
102
- * @property {number} salesAmount - Total sales amount (read-only)
103
- * - Sum of sales amounts for base and qualified workers with rounding applied.
104
- * @property {number} tax - Calculated tax amount (read-only)
105
- * - Calculated using the `Tax` utility based on `salesAmount` and `date`.
106
- * @property {number} billingAmount - Total billing amount including tax (read-only)
107
- * - Sum of `salesAmount` and `tax`.
108
- * @property {string|null} billingDate - Billing date in YYYY-MM-DD format (read-only)
109
- * - Returns a string in the format YYYY-MM-DD based on `billingDateAt`.
110
- * @property {string} billingMonth - Billing month in YYYY-MM format (read-only)
111
- * @property {Array<string>} employeeIds - Array of employee IDs from `employees` (read-only)
112
- * @property {Array<string>} outsourcerIds - Array of outsourcer IDs from `outsourcers` (read-only)
113
- * @property {number} employeesCount - Count of assigned employees (read-only)
114
- * @property {number} outsourcersCount - Count of assigned outsourcers (sum of amounts) (read-only)
115
- * @property {boolean} isPersonnelShortage - Indicates if there is a shortage of personnel (read-only)
116
- * - `true` if the sum of `employeesCount` and `outsourcersCount` is less than `requiredPersonnel`
117
- *
118
- * @getter {string} groupKey - Combines `siteId`, `shiftType`, and `date` to indicate operation grouping (read-only)
119
- * @getter {boolean} isEmployeesChanged - Indicates whether the employees have changed (read-only)
120
- * - Returns true if the employee IDs have changed compared to `_beforeData`
121
- * @getter {boolean} isOutsourcersChanged - Indicates whether the outsourcers have changed (read-only)
122
- * - Returns true if the outsourcer IDs have changed compared to `_beforeData`
123
- * @getter {Array<OperationResultDetail>} addedWorkers - An array of workers that have been added (read-only)
124
- * - Workers that exist in current data but not in `_beforeData`
125
- * @getter {Array<OperationResultDetail>} removedWorkers - An array of workers that have been removed (read-only)
126
- * - Workers that exist in `_beforeData` but not in current data
127
- * @getter {Array<OperationResultDetail>} updatedWorkers - An array of workers that have been updated (read-only)
128
- * - Workers whose `startTime`, `isStartNextDay`, `endTime`, `breakMinutes`, `isQualified`, or `isOjt` have changed
129
- * @getter {number} startHour - Start hour (0-23) (read-only)
130
- * - Extracted from `startTime`.
131
- * @getter {number} startMinute - Start minute (0-59) (read-only)
132
- * - Extracted from `startTime`.
133
- * @getter {number} endHour - End hour (0-23) (read-only)
134
- * - Extracted from `endTime`.
135
- * @getter {number} endMinute - End minute (0-59) (read-only)
136
- * - Extracted from `endTime`.
137
- * @getter {boolean} isKeyChanged - Flag indicating whether the key has changed compared to previous data (read-only)
138
- * - Compares the current `key` with the `key` in `_beforeData`.
17
+ * @property {Date} dateAt - 日付 (変更されると `dayType` が自動的に更新されます)
18
+ * @property {string} shiftType - 勤務区分 (変更されると `employees` と `outsourcers` の `shiftType` が自動的に更新されます)
19
+ * @property {string} startTime - 開始時刻 (HH:MM 形式)
20
+ * @property {string} endTime - 終了時刻 (HH:MM 形式)
21
+ * @property {boolean} isStartNextDay - 翌日開始フラグ
22
+ * - `true` の場合、実際の勤務は `dateAt` の翌日であることを意味します。
23
+ * @property {number} breakMinutes - 休憩時間 (分)
24
+ * @property {string} date - `dateAt` に基づく YYYY-MM-DD 形式の日付文字列 (読み取り専用)
25
+ * - `dateAt` に基づいて YYYY-MM-DD 形式の文字列を返します。
26
+ * @property {Date} startAt - 開始日時 (Date オブジェクト) (読み取り専用)
27
+ * - `dateAt` に基づいて `startTime` を設定した Date オブジェクトを返します。
28
+ * - `isStartNextDay` true の場合、1日加算します。
29
+ * @property {Date} endAt - 終了日時 (Date オブジェクト) (読み取り専用)
30
+ * - `startAt` を起点に、最初に現れる `endTime` Date オブジェクトを返します。
31
+ * @property {boolean} isSpansNextDay - 翌日跨ぎフラグ (読み取り専用)
32
+ * - `true` の場合、`startAt` `endAt` の日付が異なることを意味します。
33
+ * @property {number} regulationWorkMinutes - 規定労働時間 (分) (変更されると `employees` `outsourcers` `regulationWorkMinutes` が自動的に更新されます)
34
+ * - `startAt` から `endAt` までの時間から `breakMinutes` を差し引いた時間のうち、
35
+ * 規定内として扱う労働時間(分)です。
36
+ * - 実際の労働時間から残業時間を算出するための基準となる値です。
37
+ * - この値があることで、取極めに柔軟な設定を行うことが可能になる他、労働基準法の 1 日の所定労働時間上限が変更された際に
38
+ * 影響を最小限に抑えることができます。
39
+ * 例) 8:00 から 17:00 までの勤務で休憩が 60 分の場合
40
+ * - 規定労働時間を 8 時間 (480 分) とし、実際の勤務が 8 時間 (480 分) を超えた分が残業時間として扱われます。
41
+ * 例) 8:00 から 16:00 までの勤務で休憩が 60 分の場合
42
+ * - 規定労働時間を 7 時間 (420 分) とすると、実際の勤務が 7 時間 (420 分) を超えた分が残業時間として扱われます。
43
+ * - 規定労働時間を 8 時間 (480 分) とすると、実際の勤務が 8 時間 (480 分) を超えた分が残業時間として扱われます。
44
+ * 例) 7:00 から 翌日 7:00 までの勤務で休憩が 60 分の場合
45
+ * - 規定労働時間を 8 時間 (480 分) とすると、実際の勤務が 8 時間 (480 分) を超えた分が残業時間として扱われます。
46
+ * この場合、最初の 8 時間までは基本単価が適用され、残りの 8 時間は残業単価が適用されるといった設定が可能になります。
47
+ * - 規定労働時間を 24 時間 (1440 分) とすると、実際の勤務が 24 時間 (1440 分) を超えた分が残業時間として扱われます。
48
+ * この場合、全ての勤務時間が基本単価で扱われるといった設定が可能になります。
49
+ * @property {string} dayType - 曜日区分
50
+ * @property {number} totalWorkMinutes - 総労働時間 (休憩時間を除く) (分) (読み取り専用)
51
+ * @property {number} regularTimeWorkMinutes - 所定労働時間 (分) (読み取り専用)
52
+ * @property {number} overtimeWorkMinutes - 残業時間 (分) (読み取り専用)
53
+ * @property {string} siteId - 現場ID (変更されると `employees` `outsourcers` の `siteId` が自動的に更新されます)
54
+ * @property {number} requiredPersonnel - 必要人数
55
+ * @property {boolean} qualificationRequired - 資格要件フラグ
56
+ * @property {string} workDescription - 作業内容
57
+ * @property {string} remarks - 備考
58
+ * @property {Array<OperationDetail>} employees - 従業員の OperationDetail インスタンスの配列
59
+ * @property {Array<OperationDetail>} outsourcers - 外注の OperationDetail インスタンスの配列
60
+ * @property {Array<string>} employeeIds - 従業員の ID の配列 (読み取り専用)
61
+ * @property {Array<string>} outsourcerIds - 外注の ID の配列 (読み取り専用)
62
+ * @property {number} employeesCount - `employees` の要素数 (読み取り専用)
63
+ * @property {number} outsourcersCount - `outsourcers` の要素数 (読み取り専用)
64
+ * @property {boolean} isPersonnelShortage - 人員不足フラグ (読み取り専用)
65
+ * @property {Array<OperationDetail>} workers - 従業員と外注を合わせた配列
66
+ * - `employees` `outsourcers` を結合した配列を返します。
67
+ * - Getter: `employees` `outsourcers` を結合した配列を返します。
68
+ * - Setter: 配列を `isEmployee` プロパティに基づいて `employees` `outsourcers` に分割します。
69
+ * @property {string} groupKey - `siteId`, `shiftType`, `date` を組み合わせたキー。(読み取り専用)
70
+ * @property {string} agreementKey - `date`, `shiftType` を組み合わせたキー。(読み取り専用)
71
+ * @property {string} orderKey - `siteId`, `shiftType` を組み合わせたキー。(読み取り専用)
72
+ * @property {string|null} siteOperationScheduleId - 現場稼働予定ID
73
+ * - このプロパティは、OperationResult が現場稼働予定に紐づいている場合に、その現場稼働予定の ID を保持します。
74
+ * @property {boolean} useAdjustedQuantity - 請求に調整済み数量を使用するかどうかのフラグ
75
+ * @property {number} adjustedQuantityBase - 基本従業員の調整済み数量
76
+ * - `useAdjustedQuantity` true の場合、基本従業員の請求に使用される数量です。
77
+ * @property {number} adjustedOvertimeBase - 基本従業員の調整済み残業時間
78
+ * - `useAdjustedQuantity` true の場合、基本従業員の請求に使用される残業時間です。
79
+ * @property {number} adjustedQuantityQualified - 資格者の調整済み数量
80
+ * - `useAdjustedQuantity` true の場合、資格者の請求に使用される数量です。
81
+ * @property {number} adjustedOvertimeQualified - 資格者の調整済み残業時間
82
+ * - `useAdjustedQuantity` true の場合、資格者の請求に使用される残業時間です。
83
+ * @property {Date} billingDateAt - 請求日
84
+ * - 請求に使用される日付です。
85
+ * @property {boolean} isLocked - ロックフラグ
86
+ * - true の場合、OperationResult OperationBilling として編集する場合を除き、編集できません。
87
+ * @property {Agreement|null} agreement - 関連する取極めオブジェクト
88
+ * - この OperationResult に関連付けられた取極めインスタンスで、価格設定や請求情報に使用されます。
89
+ * - 設定されている場合、単価や請求日などの計算に影響を与えます。
90
+ * @property {boolean} allowEmptyAgreement - 取極めが存在しない場合を許可するフラグ
91
+ * - true に設定されている場合、取極めが関連付けられていなくても OperationResult は有効と見なされます。
92
+ * @property {boolean} hasAgreement - 取極めが関連付けられているかどうかを示すフラグ (読み取り専用)
93
+ * - `agreement` が設定されている場合は `true`、それ以外の場合は `false`。
94
+ * @property {Object} statistics - 従業員の統計情報 (読み取り専用)
95
+ * - 基本従業員と資格者のカウントおよび総労働時間を含む統計情報。
96
+ * - 構造: { base: {...}, qualified: {...}, total: {...} }
97
+ * - 各カテゴリには以下が含まれます: quantity, regularTimeWorkMinutes, overtimeWorkMinutes, totalWorkMinutes, breakMinutes
98
+ * - 各カテゴリには 'ojt' サブカテゴリも同様の構造で含まれます。
99
+ * @property {Object} sales - 売上金額 (読み取り専用)
100
+ * - 基本従業員と資格者の売上計算を含む。
101
+ * - 構造: { base: {...}, qualified: {...} }
102
+ * - 各カテゴリには以下が含まれます: unitPrice, quantity, regularAmount, overtimeUnitPrice, overtimeMinutes, overtimeAmount, total
103
+ * - 計算は `useAdjustedQuantity`, `billingUnitType`, `includeBreakInBilling` の設定を考慮します。
104
+ * @property {number} salesAmount - 売上合計金額 (読み取り専用)
105
+ * - 基本従業員と資格者の売上金額の合計を返します。
106
+ * @property {number} tax - 計算された税額 (読み取り専用)
107
+ * - `salesAmount` `date` に基づいて `Tax` ユーティリティを使用して計算されます。
108
+ * @property {number} billingAmount - 税込の請求金額 (読み取り専用)
109
+ * - `salesAmount` `tax` の合計を返します。
110
+ * @property {string|null} billingDate - 請求日 (YYYY-MM-DD 形式) (読み取り専用)
111
+ * - `billingDateAt` に基づいて YYYY-MM-DD 形式の文字列を返します。
112
+ * @property {string} billingMonth - 請求月 (YYYY-MM 形式) (読み取り専用)
139
113
  *
114
+ * @method setDateAtCallback - `dateAt` が設定されたときに呼び出されるコールバック関数
115
+ * @method addWorker - `Workers` に新しい従業員または外注先を追加します。
116
+ * @method moveWorker - 従業員または外注先の位置を移動します。
117
+ * @method changeWorker - 従業員または外注先の詳細を変更します。
118
+ * @method removeWorker - 従業員または外注先を `workers` から削除します。
119
+ * @method setSiteIdCallback - `siteId` が変更された時に呼び出されるコールバック関数
120
+ * @method setShiftTypeCallback - `shiftType` が変更された時に呼び出されるコールバック関数
121
+ * @method setRegulationWorkMinutesCallback - `regulationWorkMinutes` が変更された時に呼び出されるコールバック関数
140
122
  * @method refreshBillingDateAt - Refresh billingDateAt based on dateAt and cutoffDate
141
123
  * - Updates `billingDateAt` based on the current `dateAt` and `cutoffDate` values.
142
- * @method addWorker - Adds a new worker (employee or outsourcer)
143
- * - @param {Object} options - Options for adding a worker
144
- * - @param {string} options.id - The worker ID (employeeId or outsourcerId)
145
- * - @param {boolean} [options.isEmployee=true] - Whether the worker is an employee
146
- * - @param {number} [index=0] - Insertion position. If -1, adds to the end
147
- * @method moveWorker - Moves the position of a worker (employee or outsourcer)
148
- * - @param {Object} options - Options for changing worker position
149
- * - @param {number} options.oldIndex - The original index
150
- * - @param {number} options.newIndex - The new index
151
- * - @param {boolean} [options.isEmployee=true] - True for employee, false for outsourcer
152
- * @method changeWorker - Changes the details of a worker
153
- * - @param {Object} newWorker - New worker object
154
- * @method removeWorker - Removes a worker (employee or outsourcer)
155
- * - @param {Object} options - Options for removing a worker
156
- * - @param {string} options.workerId - The ID of the employee or outsourcer
157
- * - @param {boolean} [options.isEmployee=true] - True for employee, false for outsourcer
158
- * @method setSiteIdCallback - Callback method called when `siteId` is set
159
- * - Override this method in subclasses to add custom behavior when `siteId` changes.
160
- * - By default, does nothing.
161
- * - @param {string} v - The new `siteId` value
162
- * @method setShiftTypeCallback - Callback method called when `shiftType` is set
163
- * - Override this method in subclasses to add custom behavior when `shiftType` changes.
164
- * - By default, does nothing.
165
- * - @param {string} v - The new `shiftType` value
166
- * @method setRegulationWorkMinutesCallback - Callback method called when `regulationWorkMinutes` is set
167
- * - Override this method in subclasses to add custom behavior when `regulationWorkMinutes` changes.
168
- * - By default, does nothing.
169
- * - @param {number} v - The new `regulationWorkMinutes` value
170
124
  *
171
- * @static
172
- * @method groupKeyDivider
173
- * - Returns an array dividing the key into siteId, shiftType, and date.
174
- * - @param {Object|string} key - The combined key string or object
175
- * - @returns {Array<string>} - Array containing [siteId, shiftType, date]
176
- * - @throws {Error} - If the key is invalid.
125
+ * @getter {boolean} isInvalid - クラス特有のエラーが存在するかどうかを返すプロパティ
126
+ * @getter {Array<Object>} invalidReasons - エラーコード、メッセージ、多言語メッセージ、フィールド名を含む詳細情報の配列を返すプロパティ
127
+ * @getter {boolean} isGroupKeyChanged - `groupKey` プロパティが変更されたかどうかを返すプロパティ
128
+ * @getter {boolean} isAgreementKeyChanged - `agreementKey` プロパティが変更されたかどうかを返すプロパティ
129
+ * @getter {boolean} isEmployeesChanged - 従業員が変更されたかどうかを示すフラグ (読み取り専用)
130
+ * @getter {boolean} isOutsourcersChanged - 外注が変更されたかどうかを示すフラグ (読み取り専用)
131
+ * @getter {Array<OperationDetail>} addedWorkers - 追加された従業員の配列 (読み取り専用)
132
+ * @getter {Array<OperationDetail>} removedWorkers - 削除された従業員の配列 (読み取り専用)
133
+ * @getter {Array<OperationDetail>} updatedWorkers - 更新された従業員の配列 (読み取り専用)
177
134
  *
178
- * @override
179
- * @method setDateAtCallback - Updates `billingDateAt` based on the new `dateAt` value.
180
- * @method beforeCreate - Override to sync customerId from siteId
181
- * @method beforeUpdate - Override to sync customerId from siteId when siteId changes
182
- * @method beforeDelete - Override to prevent deletion if isLocked is true
135
+ * @static SHIFT_TYPE - 勤務区分を定義する定数オブジェクト
136
+ * @static INVALID_REASON - クラス特有のエラーコードを定義する定数オブジェクト
137
+ * - `EMPTY_AGREEMENT`: 取極めが存在せず、`allowEmptyAgreement` false の場合のエラーコード
138
+ * - `EMPTY_BILLING_DATE`: 請求日が存在しない場合のエラーコード
139
+ * @static DAY_TYPE - 曜日区分を定義する定数オブジェクト
140
+ * @static BILLING_UNIT_TYPE - 請求単位区分を定義する定数オブジェクト
141
+ *
142
+ * @static
143
+ * @method groupKeyDivider - `groupKey` を構成する要素を分割して返す静的メソッド
183
144
  *****************************************************************************/
184
145
  import Operation from "./Operation.js";
185
- import Agreement from "./Agreement.js";
146
+ import AgreementV2 from "./AgreementV2.js";
186
147
  import { ContextualError } from "./utils/ContextualError.js";
187
148
  import OperationResultDetail from "./OperationResultDetail.js";
188
149
  import { defField } from "./parts/fieldDefinitions.js";
150
+ import { formatJstDate } from "./utils/index.js";
189
151
  import Tax from "./Tax.js";
190
152
  import { VALUES as BILLING_UNIT_TYPE } from "./constants/billing-unit-type.js";
191
153
  import RoundSetting from "./RoundSetting.js";
@@ -195,6 +157,14 @@ import Site from "./Site.js";
195
157
  const classProps = {
196
158
  ...Operation.classProps,
197
159
  siteOperationScheduleId: defField("oneLine", { hidden: true }),
160
+ /**
161
+ * `employees`, `outsourcers` は 継承元である `Operation` クラスで定義されているが、
162
+ * customClass が `OperationDetail` になっているため、`OperationResultDetail` で再定義する。
163
+ */
164
+ employees: defField("array", { customClass: OperationResultDetail }),
165
+ outsourcers: defField("array", {
166
+ customClass: OperationResultDetail,
167
+ }),
198
168
  useAdjustedQuantity: defField("check", {
199
169
  label: "調整数量を使用",
200
170
  default: false,
@@ -216,15 +186,11 @@ const classProps = {
216
186
  default: 0,
217
187
  }),
218
188
  billingDateAt: defField("dateAt", { label: "請求締日" }),
219
- employees: defField("array", { customClass: OperationResultDetail }),
220
- outsourcers: defField("array", {
221
- customClass: OperationResultDetail,
222
- }),
223
189
  isLocked: defField("check", {
224
190
  label: "実績確定",
225
191
  default: false,
226
192
  }),
227
- agreement: defField("object", { label: "取極め", customClass: Agreement }),
193
+ agreement: defField("object", { label: "取極め", customClass: AgreementV2 }),
228
194
  allowEmptyAgreement: defField("check", {
229
195
  label: "取極めなしを許容",
230
196
  default: false,
@@ -238,11 +204,6 @@ const classProps = {
238
204
  customerId: defField("customerId", { required: true, hidden: true }),
239
205
  };
240
206
 
241
- const INVALID_REASON = {
242
- EMPTY_BILLING_DATE: "EMPTY_BILLING_DATE",
243
- EMPTY_AGREEMENT: "EMPTY_AGREEMENT",
244
- };
245
-
246
207
  export default class OperationResult extends Operation {
247
208
  static className = "稼働実績";
248
209
  static collectionPath = "OperationResults";
@@ -250,12 +211,38 @@ export default class OperationResult extends Operation {
250
211
  static logicalDelete = false;
251
212
  static classProps = classProps;
252
213
 
214
+ static BILLING_UNIT_TYPE = BILLING_UNIT_TYPE;
215
+
216
+ /**
217
+ * INVALID_REASON
218
+ * - Operation クラスの INVALID_REASON を継承しています。
219
+ * - 以下のエラーコードを追加
220
+ * - `EMPTY_AGREEMENT`: 取極めが存在せず、`allowEmptyAgreement` が false の場合のエラーコード
221
+ * - `EMPTY_BILLING_DATE`: 請求日が存在しない場合のエラーコード
222
+ */
223
+ static INVALID_REASON = {
224
+ ...Operation.INVALID_REASON,
225
+ EMPTY_BILLING_DATE: {
226
+ code: "EMPTY_BILLING_DATE",
227
+ message: "Billing date is required.",
228
+ messages: {
229
+ ja: "請求締日は必須です。",
230
+ },
231
+ },
232
+ EMPTY_AGREEMENT: {
233
+ code: "EMPTY_AGREEMENT",
234
+ message: "Agreement is required.",
235
+ messages: {
236
+ ja: "取極めは必須です。",
237
+ },
238
+ },
239
+ };
240
+
253
241
  static headers = [
254
242
  { title: "日付", key: "dateAt" },
255
243
  { title: "現場", key: "siteId", value: "siteId" },
256
244
  ];
257
245
 
258
- static BILLING_UNIT_TYPE = BILLING_UNIT_TYPE;
259
246
  /**
260
247
  * afterInitialize
261
248
  */
@@ -264,6 +251,19 @@ export default class OperationResult extends Operation {
264
251
 
265
252
  /** Computed properties */
266
253
  Object.defineProperties(this, {
254
+ /**
255
+ * hasAgreement
256
+ * - getter 定義でも良いが、Firestore のクエリで使用する可能性があるため、
257
+ * Object.defineProperty で列挙可能プロパティとして定義する。
258
+ */
259
+ hasAgreement: {
260
+ configurable: true,
261
+ enumerable: true,
262
+ get() {
263
+ return this.agreement != null;
264
+ },
265
+ set(v) {},
266
+ },
267
267
  statistics: {
268
268
  configurable: true,
269
269
  enumerable: true,
@@ -323,6 +323,7 @@ export default class OperationResult extends Operation {
323
323
  const calculateCategorySales = (category) => {
324
324
  const isQualified = category === "qualified";
325
325
  const categoryStats = this.statistics?.[category];
326
+ const rateSet = this.agreement?.rates?.[this.dayType];
326
327
 
327
328
  // 統計データが存在しない場合は警告を出力して初期値を返す
328
329
  if (!categoryStats) {
@@ -334,7 +335,7 @@ export default class OperationResult extends Operation {
334
335
  siteId: this.siteId,
335
336
  category,
336
337
  statistics: this.statistics,
337
- }
338
+ },
338
339
  );
339
340
  return createInitialValues();
340
341
  }
@@ -374,19 +375,33 @@ export default class OperationResult extends Operation {
374
375
 
375
376
  // agreementがある場合のみ単価と金額を計算
376
377
  if (this.agreement) {
378
+ if (!rateSet) {
379
+ console.warn(
380
+ `[OperationResult] AgreementV2.rates for dayType '${this.dayType}' is missing.`,
381
+ {
382
+ docId: this.docId,
383
+ dateAt: this.dateAt,
384
+ siteId: this.siteId,
385
+ dayType: this.dayType,
386
+ agreement: this.agreement,
387
+ },
388
+ );
389
+ return result;
390
+ }
391
+
377
392
  result.unitPrice = isQualified
378
- ? this.agreement.unitPriceQualified || 0
379
- : this.agreement.unitPriceBase || 0;
393
+ ? rateSet.unitPriceQualified || 0
394
+ : rateSet.unitPriceBase || 0;
380
395
  result.overtimeUnitPrice = isQualified
381
- ? this.agreement.overtimeUnitPriceQualified || 0
382
- : this.agreement.overtimeUnitPriceBase || 0;
396
+ ? rateSet.overtimeUnitPriceQualified || 0
397
+ : rateSet.overtimeUnitPriceBase || 0;
383
398
 
384
399
  // 金額計算(RoundSettingを適用)
385
400
  result.regularAmount = RoundSetting.apply(
386
- result.quantity * result.unitPrice
401
+ result.quantity * result.unitPrice,
387
402
  );
388
403
  result.overtimeAmount = RoundSetting.apply(
389
- (result.overtimeMinutes * result.overtimeUnitPrice) / 60
404
+ (result.overtimeMinutes * result.overtimeUnitPrice) / 60,
390
405
  );
391
406
  result.total = result.regularAmount + result.overtimeAmount;
392
407
  }
@@ -438,16 +453,7 @@ export default class OperationResult extends Operation {
438
453
  configurable: true,
439
454
  enumerable: true,
440
455
  get() {
441
- if (!this.billingDateAt) return null;
442
- const jstDate = new Date(
443
- this.billingDateAt.getTime() + 9 * 60 * 60 * 1000
444
- ); /* JST補正 */
445
- const year = jstDate.getUTCFullYear();
446
- const month = jstDate.getUTCMonth() + 1;
447
- const day = jstDate.getUTCDate();
448
- return `${year}-${String(month).padStart(2, "0")}-${String(
449
- day
450
- ).padStart(2, "0")}`;
456
+ return formatJstDate(this.billingDateAt);
451
457
  },
452
458
  set(v) {},
453
459
  },
@@ -455,35 +461,7 @@ export default class OperationResult extends Operation {
455
461
  configurable: true,
456
462
  enumerable: true,
457
463
  get() {
458
- if (!this.billingDateAt) return null;
459
- const jstDate = new Date(
460
- this.billingDateAt.getTime() + 9 * 60 * 60 * 1000
461
- ); /* JST補正 */
462
- const year = jstDate.getUTCFullYear();
463
- const month = jstDate.getUTCMonth() + 1;
464
- return `${year}-${String(month).padStart(2, "0")}`;
465
- },
466
- set(v) {},
467
- },
468
- hasAgreement: {
469
- configurable: true,
470
- enumerable: true,
471
- get() {
472
- return this.agreement != null;
473
- },
474
- set(v) {},
475
- },
476
- isInvalid: {
477
- configurable: true,
478
- enumerable: true,
479
- get() {
480
- if (!this.agreement && !this.allowEmptyAgreement) {
481
- return INVALID_REASON.EMPTY_AGREEMENT;
482
- }
483
- if (!this.billingDateAt) {
484
- return INVALID_REASON.EMPTY_BILLING_DATE;
485
- }
486
- return false;
464
+ return formatJstDate(this.billingDateAt, "YYYY-MM");
487
465
  },
488
466
  set(v) {},
489
467
  },
@@ -529,7 +507,7 @@ export default class OperationResult extends Operation {
529
507
  }
530
508
  this.billingDateAt = CutoffDate.calculateBillingDateAt(
531
509
  this.dateAt,
532
- this.agreement.cutoffDate
510
+ this.agreement.cutoffDate,
533
511
  );
534
512
  }
535
513
 
@@ -557,16 +535,17 @@ export default class OperationResult extends Operation {
557
535
  docId: this.siteId,
558
536
  });
559
537
  if (!siteExists) {
560
- throw new Error(
561
- `[OperationResult] The specified siteId (${this.siteId}) does not exist.`
562
- );
538
+ const message = `[OperationResult.js] The specified siteId (${this.siteId}) does not exist.`;
539
+ throw new Error(message);
563
540
  }
564
541
  this.customerId = siteInstance.customerId;
565
- this.agreement = siteInstance.getAgreement(this);
542
+ // this.agreement = siteInstance.getAgreement(this);
543
+ this.agreement = siteInstance.getValidAgreement(this);
566
544
  }
567
545
 
568
546
  /**
569
- * Override beforeCreate to sync customerId
547
+ * ドキュメント作成前処理
548
+ * - siteId から customerId を同期し、agreement を適用する。
570
549
  * @param {Object} args - Creation options.
571
550
  * @param {string} [args.docId] - Document ID to use (optional).
572
551
  * @param {boolean} [args.useAutonumber=true] - Whether to use auto-numbering.
@@ -583,7 +562,9 @@ export default class OperationResult extends Operation {
583
562
  }
584
563
 
585
564
  /**
586
- * Override beforeUpdate to sync customerId and apply agreement if key changed
565
+ * ドキュメント更新前処理
566
+ * - 更新前および更新後の `isLocked` が true の場合は編集不可とする。
567
+ * - `groupKey` が変更された場合は `customerId` の同期と `agreement` の適用を行う。
587
568
  * @param {Object} args - Creation options.
588
569
  * @param {Object} [args.transaction] - Firestore transaction.
589
570
  * @param {Function} [args.callBack] - Callback function.
@@ -593,20 +574,16 @@ export default class OperationResult extends Operation {
593
574
  async beforeUpdate(args = {}) {
594
575
  await super.beforeUpdate(args);
595
576
 
596
- // Prevent editing if isLocked is true
597
- if (this.isLocked) {
598
- throw new Error(
599
- "[OperationResult] This OperationResult is locked and cannot be edited."
600
- );
577
+ // 更新前および更新後の `isLocked` true の場合は編集不可とする。
578
+ if (this._beforeData.isLocked && this.isLocked) {
579
+ const message = `[OperationResult.js] This OperationResult (docId: ${this.docId}) is locked and cannot be edited.`;
580
+ throw new Error(message);
601
581
  }
602
582
 
603
- // Sync customerId and apply agreement if key changed
604
- /**
605
- * 2026-01-08 `agreementKey` を実装したため、`key` の使用を避ける。
606
- */
607
- // if (this.key === this._beforeData.key) return;
608
- if (this.agreementKey === this._beforeData.agreementKey) return;
609
- await this._syncCustomerIdAndApplyAgreement();
583
+ // groupKeyが変更された場合はcustomerIdの同期とagreementの適用を行う
584
+ if (this.isGroupKeyChanged) {
585
+ await this._syncCustomerIdAndApplyAgreement();
586
+ }
610
587
  }
611
588
 
612
589
  /**
@@ -620,11 +597,37 @@ export default class OperationResult extends Operation {
620
597
  */
621
598
  async beforeDelete(args = {}) {
622
599
  await super.beforeDelete(args);
623
- // Prevent deletion if isLocked is true
624
- if (this.isLocked) {
625
- throw new Error(
626
- "[OperationResult] This OperationResult is locked and cannot be deleted."
627
- );
600
+
601
+ // 更新前および更新後の `isLocked` が true の場合は削除不可とする。
602
+ if (this._beforeData.isLocked && this.isLocked) {
603
+ const message = `[OperationResult.js] This OperationResult (docId: ${this.docId}) is locked and cannot be deleted.`;
604
+ throw new Error(message);
628
605
  }
629
606
  }
607
+
608
+ /**
609
+ * クラス特有のエラーを詳細情報付きで返す内部メソッド
610
+ * - `agreement` が存在せず、`allowEmptyAgreement` が false の場合、`EMPTY_AGREEMENT` エラーを返します。
611
+ * - `billingDateAt` が存在しない場合、`EMPTY_BILLING_DATE` エラーを返します。
612
+ * @returns {Array<Object>} エラー詳細オブジェクトの配列(統一フォーマット)
613
+ */
614
+ _getInvalidReasons() {
615
+ const result = super._getInvalidReasons();
616
+
617
+ if (!this.agreement && !this.allowEmptyAgreement) {
618
+ result.push({
619
+ ...OperationResult.INVALID_REASON.EMPTY_AGREEMENT,
620
+ field: "agreement",
621
+ });
622
+ }
623
+
624
+ if (!this.billingDateAt) {
625
+ result.push({
626
+ ...OperationResult.INVALID_REASON.EMPTY_BILLING_DATE,
627
+ field: "billingDateAt",
628
+ });
629
+ }
630
+
631
+ return result;
632
+ }
630
633
  }