@shisyamo4131/air-guard-v2-schemas 2.4.2-dev.4 → 2.4.2-dev.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shisyamo4131/air-guard-v2-schemas",
3
- "version": "2.4.2-dev.4",
3
+ "version": "2.4.2-dev.6",
4
4
  "description": "Schemas for AirGuard V2",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/src/Operation.js CHANGED
@@ -57,11 +57,13 @@
57
57
  * - Setter: Splits array into employees and outsourcers based on `isEmployee` property
58
58
  *
59
59
  * @property {string} key - `siteId`, `date`, `dayType`, `shiftType` を組み合わせたキー。(読み取り専用)
60
- * - 2026-01-07 現在使用していないプロパティ。
61
- * - `dayType` は請求時の単価情報を取得するために必要な情報であるため含める必要がないと思われる。
60
+ * - `WorkingResult.key` をオーバーライドして `siteId` を含めるように定義されているが、未使用。
61
+ *
62
+ * @property {string} agreementKey - `siteId`, `date`, `dayType`, `shiftType` を組み合わせたキー。(読み取り専用)
63
+ * - 適用する取極めを特定するためのキーとして使用される。
62
64
  *
63
65
  * @property {string} orderKey - `siteId`, `shiftType` を組み合わせたキー。(読み取り専用)
64
- * - `siteOrder` の `key` プロパティに対応するキー。
66
+ * - `siteOrder` の `key` プロパティに対応するキー。稼働予測や配置管理で使用される。
65
67
  *
66
68
  * @getter {string} groupKey - Combines `siteId`, `shiftType`, and `date` to indicate operation grouping (read-only)
67
69
  * @getter {boolean} isEmployeesChanged - Indicates whether the employees have changed (read-only)
@@ -283,6 +285,19 @@ export default class Operation extends WorkingResult {
283
285
  set() {},
284
286
  },
285
287
 
288
+ /**
289
+ * `siteId`, `date`, `dayType`, `shiftType` を組み合わせたキー。(読み取り専用)
290
+ * - 適用する取極めを特定するためのキーとして使用される。
291
+ */
292
+ agreementKey: {
293
+ configurable: true,
294
+ enumberable: true,
295
+ get() {
296
+ return `${this.siteId}-${this.date}-${this.dayType}-${this.shiftType}`;
297
+ },
298
+ set() {},
299
+ },
300
+
286
301
  /**
287
302
  * `siteId`, `shiftType` を組み合わせたキー。(読み取り専用)
288
303
  * - `siteOrder` の `key` プロパティに対応するキー。
@@ -1,6 +1,5 @@
1
1
  /*****************************************************************************
2
2
  * OperationResult Model
3
- * @version 1.2.0 - 2025-11-19 Add `agreement`, `hasAgreement`, `isValid` properties.
4
3
  * @author shisyamo4131
5
4
  *
6
5
  * - Extends Operation class to represent the result of an operation.
@@ -12,6 +11,8 @@
12
11
  *
13
12
  * @property { string } key - {@link Operation#key}
14
13
  *
14
+ * @property {string} agreementKey - {@link Operation#agreementKey}
15
+ *
15
16
  * @property {string} orderKey - {@link Operation#orderKey}
16
17
  *
17
18
  * @property {string} siteId - Site document ID (trigger property)
@@ -544,7 +545,6 @@ export default class OperationResult extends Operation {
544
545
  /**
545
546
  * Synchronize customerId and apply (re-apply) agreement from siteId
546
547
  * @param {Object} [args.transaction] - Firestore transaction.
547
- * @param {Function} [args.callBack] - Callback function.
548
548
  * @param {string} [args.prefix] - Path prefix.
549
549
  * @returns {Promise<void>}
550
550
  * @throws {Error} If the specified siteId does not exist
@@ -601,7 +601,11 @@ export default class OperationResult extends Operation {
601
601
  }
602
602
 
603
603
  // Sync customerId and apply agreement if key changed
604
- if (this.key === this._beforeData.key) return;
604
+ /**
605
+ * 2026-01-08 `agreementKey` を実装したため、`key` の使用を避ける。
606
+ */
607
+ // if (this.key === this._beforeData.key) return;
608
+ if (this.agreementKey === this._beforeData.agreementKey) return;
605
609
  await this._syncCustomerIdAndApplyAgreement();
606
610
  }
607
611
 
package/src/Site.js CHANGED
@@ -1,16 +1,17 @@
1
1
  /**
2
2
  * @file src/Site.js
3
3
  * @author shisyamo4131
4
- * @version 1.1.0
5
- * @update 2025-11-20 version 0.2.0-bata
6
- * - Prevent changing customer reference on update.
7
- * - Move `customer` property to the top of classProps for better visibility.
8
4
  *
9
- * NOTE: `customer` プロパティについて
10
- * 自身の従属先データを持たせる場合に `XxxxxMinimal` クラスを使用するが、アプリ側でオブジェクト選択を行う場合に
11
- * `Xxxxx` クラスにするのか `XxxxxMinimal` クラスにするのかを判断できないため、docId を持たせて
12
- * `beforeCreate` フックでオブジェクトを取得するようにする。
13
- * 尚、取引先は変更できない仕様。
5
+ * NOTE: `customerId`, `customer` プロパティについて
6
+ * - 仮登録
7
+ * - 取引先未定での現場登録のシチュエーションを考慮して現場情報は仮登録を可能とする。
8
+ * - 仮登録状態の現場は `isTemporary` プロパティが `true` となる。
9
+ * - 但し、一度取引先を設定した後に未設定に戻すことはできない。
10
+ * - 取引先未設定の場合に、`Site` インスタンスから取引先名を参照する必要があるケースに備えて
11
+ * `customerName` プロパティを設ける。
12
+ * - 自身の従属先データを持たせる場合に `XxxxxMinimal` クラスを使用するが、アプリ側でオブジェクト選択を行う場合に
13
+ * `Xxxxx` クラスにするのか `XxxxxMinimal` クラスにするのかを判断できないため、docId を持たせて
14
+ * `beforeCreate` フックでオブジェクトを取得するようにする。
14
15
  */
15
16
  import { default as FireModel } from "@shisyamo4131/air-firebase-v2";
16
17
  import { defField } from "./parts/fieldDefinitions.js";
@@ -21,17 +22,35 @@ import { VALUES } from "./constants/site-status.js";
21
22
  import { GeocodableMixin } from "./mixins/GeocodableMixin.js";
22
23
 
23
24
  const classProps = {
25
+ // customerId: defField("customerId", {
26
+ // required: true,
27
+ // component: {
28
+ // attrs: {
29
+ // disabled: ({ editMode }) => {
30
+ // return editMode !== "CREATE";
31
+ // },
32
+ // },
33
+ // },
34
+ // }),
24
35
  customerId: defField("customerId", {
25
- required: true,
26
36
  component: {
27
37
  attrs: {
28
- disabled: ({ editMode }) => {
29
- return editMode !== "CREATE";
38
+ /**
39
+ * `_beforeData.customerId` が存在する場合(本登録後の編集時を表す)には `customerId` を必須とする。
40
+ */
41
+ required: ({ item }) => {
42
+ return !!item._beforeData.customerId;
30
43
  },
31
44
  },
32
45
  },
33
46
  }),
34
47
  customer: defField("customer", { hidden: true, customClass: Customer }),
48
+ customerName: defField("name", {
49
+ label: "取引先名",
50
+ required: ({ item }) => {
51
+ return !item.customerId; // isTemporary プロパティでの判定でも良いか?
52
+ },
53
+ }),
35
54
  code: defField("code", { label: "現場コード" }),
36
55
  name: defField("name", {
37
56
  label: "現場名",
@@ -55,24 +74,34 @@ const classProps = {
55
74
  };
56
75
 
57
76
  /*****************************************************************************
58
- * @props {string} code - Site code.
59
- * @props {string} name - Site name.
60
- * @props {string} nameKana - Site name in Kana.
61
- * @props {string} zipcode - Postal code.
62
- * @props {string} prefCode - Prefecture code.
63
- * @props {string} city - City name.
64
- * @props {string} address - Address details.
65
- * @props {string} building - Building name.
66
- * @props {object} location - Geographical location.
67
- * @props {object} customer - Associated customer (CustomerMinimal).
68
- * @props {string} remarks - Additional remarks.
69
- * @props {array} agreements - List of agreements (Agreement).
77
+ * @property {string} customerId - 取引先ドキュメントID
78
+ *
79
+ * @property {object} customer - 取引先オブジェクト
80
+ * - `beforeCreate`, `beforeUpdate` `customerId` に該当する `Customer` オブジェクトと自動的に同期されます。
81
+ * - `Customer` が更新された場合は Cloud Functions で同期される必要があります。
82
+ *
83
+ * @property {string} code - Site code.
84
+ * @property {string} name - Site name.
85
+ * @property {string} nameKana - Site name in Kana.
86
+ * @property {string} zipcode - Postal code.
87
+ * @property {string} prefCode - Prefecture code.
88
+ *
89
+ * @property {string} prefecture - Prefecture name derived from `prefCode` (read-only)
90
+ *
91
+ * @property {string} city - City name.
92
+ * @property {string} address - Address details.
93
+ * @property {string} building - Building name.
94
+ *
95
+ * @property {string} fullAddress - Full address combining prefecture, city, and address (read-only)
96
+ *
97
+ * @property {object} location - Geographical location.
98
+ * @property {string} remarks - Additional remarks.
99
+ * @property {array} agreements - List of agreements (Agreement).
70
100
  * - Enhanced with custom methods: `add()`, `change()`, `remove()`
71
- * @props {string} status - Site status.
72
101
  *
73
- * @computed {string} customerId - ID of the associated customer (read-only)
74
- * @computed {string} fullAddress - Full address combining prefecture, city, and address (read-only)
75
- * @computed {string} prefecture - Prefecture name derived from `prefCode` (read-only)
102
+ * @property {string} status - Site status.
103
+ *
104
+ * @property {boolean} isTemporary - 仮登録状態かどうかを表すフラグ
76
105
  *
77
106
  * @function getAgreement
78
107
  * Gets applicable agreement based on date, dayType, and shiftType.
@@ -127,31 +156,51 @@ export default class Site extends GeocodableMixin(FireModel) {
127
156
  static STATUS_TERMINATED = VALUES.TERMINATED.value;
128
157
 
129
158
  /**
130
- * Overrides to fetch and set the customer object before creation.
131
- * @param {Object} args - Creation options.
132
- * @param {string} [args.docId] - Document ID to use (optional).
133
- * @param {boolean} [args.useAutonumber=true] - Whether to use auto-numbering.
134
- * @param {Object} [args.transaction] - Firestore transaction.
135
- * @param {Function} [args.callBack] - Callback function.
136
- * @param {string} [args.prefix] - Path prefix.
159
+ * `customerId` に該当する `Customer` インスタンスを取得して `customer` プロパティにセットします。
160
+ * - `customerId` が未設定の場合は何もしません。
137
161
  * @returns {Promise<void>}
162
+ * @throws {Error} `Customer` が存在しない場合にスローされます。
138
163
  */
139
- async beforeCreate(args = {}) {
140
- await super.beforeCreate(args);
164
+ async _setCustomer() {
141
165
  if (!this.customerId) return;
142
166
  const customerInstance = new Customer();
143
167
  const isExist = await customerInstance.fetch({
144
- ...args,
145
168
  docId: this.customerId,
146
169
  });
147
170
  if (!isExist) {
148
- return Promise.reject(
149
- new Error("Invalid customerId: Customer does not exist.")
150
- );
171
+ throw new Error("Customer does not exist.");
151
172
  }
152
173
  this.customer = customerInstance;
153
174
  }
154
175
 
176
+ /**
177
+ * ドキュメント作成直前の処理です。
178
+ * - `customerId` に該当する `Customer` インスタンスを取得して `customer` プロパティにセットします。
179
+ * @param {Object} args - Creation options.
180
+ * @param {string} [args.docId] - Document ID to use (optional).
181
+ * @param {boolean} [args.useAutonumber=true] - Whether to use auto-numbering.
182
+ * @param {Object} [args.transaction] - Firestore transaction.
183
+ * @param {Function} [args.callBack] - Callback function.
184
+ * @param {string} [args.prefix] - Path prefix.
185
+ * @returns {Promise<void>}
186
+ */
187
+ async beforeCreate(args = {}) {
188
+ await super.beforeCreate(args);
189
+ // if (!this.customerId) return;
190
+ // const customerInstance = new Customer();
191
+ // const isExist = await customerInstance.fetch({
192
+ // ...args,
193
+ // docId: this.customerId,
194
+ // });
195
+ // if (!isExist) {
196
+ // return Promise.reject(
197
+ // new Error("Invalid customerId: Customer does not exist.")
198
+ // );
199
+ // }
200
+ // this.customer = customerInstance;
201
+ await this._setCustomer();
202
+ }
203
+
155
204
  /**
156
205
  * Override beforeUpdate to prevent changing customer reference.
157
206
  * @param {Object} args - Creation options.
@@ -162,10 +211,21 @@ export default class Site extends GeocodableMixin(FireModel) {
162
211
  */
163
212
  async beforeUpdate(args = {}) {
164
213
  await super.beforeUpdate(args);
165
- if (this.customer.docId !== this._beforeData.customer.docId) {
166
- return Promise.reject(
167
- new Error("Not allowed to change customer reference.")
168
- );
214
+
215
+ // if (this.customer.docId !== this._beforeData.customer.docId) {
216
+ // return Promise.reject(
217
+ // new Error("Not allowed to change customer reference.")
218
+ // );
219
+ // }
220
+
221
+ // 取引先を未設定に戻すことはできない。
222
+ if (this._beforeData.customerId && !this.customerId) {
223
+ throw new Error("Cannot unset customerId once it is set.");
224
+ }
225
+
226
+ // 取引先が変更されていた場合は `customer` プロパティを更新する。
227
+ if (this.customerId !== this._beforeData.customerId) {
228
+ await this._setCustomer();
169
229
  }
170
230
  }
171
231
 
@@ -173,12 +233,26 @@ export default class Site extends GeocodableMixin(FireModel) {
173
233
  super.afterInitialize(item);
174
234
 
175
235
  Object.defineProperties(this, {
176
- // customerId: defAccessor("customerId"),
177
236
  fullAddress: defAccessor("fullAddress"),
178
237
  prefecture: defAccessor("prefecture"),
238
+ isTemporary: {
239
+ configurable: true,
240
+ enumerable: true,
241
+ get() {
242
+ return !!this.customerId;
243
+ },
244
+ set() {},
245
+ },
179
246
  });
180
247
 
181
248
  const self = this;
249
+
250
+ /**
251
+ * `Agreement` プロパティに対するカスタムメソッドを定義します。
252
+ * - add(agreement): `Agreement` インスタンスを追加します。
253
+ * - change(newAgreement): `key` プロパティを基に既存の `Agreement` を置き換えます。
254
+ * - remove(agreement): `key` プロパティを基に `Agreement` を削除します。
255
+ */
182
256
  Object.defineProperties(this.agreements, {
183
257
  add: {
184
258
  value: function (agreement) {
@@ -20,6 +20,8 @@
20
20
  *
21
21
  * @property { string } key - {@link Operation#key}
22
22
  *
23
+ * @property {string} agreementKey - {@link Operation#agreementKey}
24
+ *
23
25
  * @property {string} orderKey - {@link Operation#orderKey}
24
26
  *
25
27
  * @property {string|null} operationResultId - Associated OperationResult document ID
@@ -27,7 +27,7 @@
27
27
  * - The maximum working time defined by `unitPriceBase` (or `unitPriceQualified`).
28
28
  * - Exceeding this time is considered overtime.
29
29
  *
30
- * @property {string} key - `date`, `dayType`, `shifType` を組み合わせたユニークキー。(読み取り専用)
30
+ * @property {string} key - `date`, `dayType`, `shiftType` を組み合わせたユニークキー。(読み取り専用)
31
31
  * - 継承先である `Agreement` でデータを一意に識別するためのキーとして使用されます。
32
32
  *
33
33
  * @property {string} date - Date string in YYYY-MM-DD format based on `dateAt` (read-only)