@shisyamo4131/air-guard-v2-schemas 2.3.8-dev.2 → 2.4.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 CHANGED
@@ -6,6 +6,7 @@ export { default as Company } from "./src/Company.js";
6
6
  export { default as Customer, CustomerMinimal } from "./src/Customer.js";
7
7
  export { default as CutoffDate } from "./src/utils/CutoffDate.js";
8
8
  export { default as Employee } from "./src/Employee.js";
9
+ export { GeocodableMixin } from "./src/mixins/GeocodableMixin.js";
9
10
  export { default as OperationBilling } from "./src/OperationBilling.js";
10
11
  export { default as OperationResult } from "./src/OperationResult.js";
11
12
  export { default as OperationResultDetail } from "./src/OperationResultDetail.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shisyamo4131/air-guard-v2-schemas",
3
- "version": "2.3.8-dev.2",
3
+ "version": "2.4.0",
4
4
  "description": "Schemas for AirGuard V2",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/src/Company.js CHANGED
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * Company Model
3
- * @version 1.4.0
3
+ * @version 1.0.0
4
4
  * @author shisyamo4131
5
- * @update 2025-12-02 Add maintenance information properties.
6
- * @update 2025-12-01 Add Stripe integration fields (stripeCustomerId, subscription).
7
- * @update 2025-11-27 Add bank information fields for billing.
8
- * @update 2025-11-23 Set `usePrefix` to false.
5
+ * @update 2025-12-29 - Add `isCompleteRequiredFields` computed property.
6
+ * @update 2025-12-02 - Add maintenance information properties.
7
+ * @update 2025-12-01 - Add Stripe integration fields (stripeCustomerId, subscription).
8
+ * @update 2025-11-27 - Add bank information fields for billing.
9
+ * @update 2025-11-23 - Set `usePrefix` to false.
9
10
  */
10
11
  import FireModel from "@shisyamo4131/air-firebase-v2";
11
12
  import { defField } from "./parts/fieldDefinitions.js";
@@ -149,6 +150,25 @@ export default class Company extends FireModel {
149
150
  },
150
151
  set() {},
151
152
  },
153
+
154
+ // Check if all `required` fields are filled.
155
+ // Used for validating whether the Company info is complete.
156
+ isCompleteRequiredFields: {
157
+ enumerable: true,
158
+ configurable: true,
159
+ get() {
160
+ return !!(
161
+ this.companyName &&
162
+ this.companyNameKana &&
163
+ this.zipcode &&
164
+ this.prefCode &&
165
+ this.city &&
166
+ this.address &&
167
+ this.tel
168
+ );
169
+ },
170
+ set() {},
171
+ },
152
172
  });
153
173
 
154
174
  /*************************************************************************
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @file src/mixins/GeocodableMixin.js
3
+ * @description Geocoding 機能を提供する Mixin
4
+ */
5
+
6
+ /**
7
+ * Geocoding 機能を提供する Mixin
8
+ * @param {Class} BaseClass - 継承元のクラス
9
+ * @returns {Class} Geocoding 機能を持つクラス
10
+ */
11
+ export function GeocodableMixin(BaseClass) {
12
+ return class extends BaseClass {
13
+ /**
14
+ * Firestore 用のコンバーターを提供します。
15
+ * - location から geopoint を自動生成して Firestore に保存します。
16
+ * - toObject() は純粋なプレーンオブジェクトを返すため、コンポーネント側で安全に使用できます。
17
+ * @override
18
+ */
19
+ static converter() {
20
+ const superConverter = super.converter();
21
+ return {
22
+ toFirestore: (instance) => {
23
+ const obj = superConverter.toFirestore(instance);
24
+
25
+ // location から geopoint を生成
26
+ if (obj.location?.lat && obj.location?.lng) {
27
+ try {
28
+ const adapter = this.getAdapter();
29
+ const GeoPoint = adapter.GeoPoint;
30
+
31
+ if (GeoPoint) {
32
+ obj.geopoint = new GeoPoint(obj.location.lat, obj.location.lng);
33
+ }
34
+ } catch (error) {
35
+ console.warn(
36
+ `[${this.className}.converter] GeoPoint generation failed:`,
37
+ error
38
+ );
39
+ obj.geopoint = null;
40
+ }
41
+ } else {
42
+ obj.geopoint = null;
43
+ }
44
+
45
+ return obj;
46
+ },
47
+ fromFirestore: superConverter.fromFirestore,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * 新しいドキュメントが作成される前に `location` を取得してセットします。
53
+ * @param {Object} args - Creation options.
54
+ * @param {boolean} [args.skipGeocoding=false] - Skip geocoding process.
55
+ * @returns {Promise<void>}
56
+ */
57
+ async beforeCreate(args = {}) {
58
+ await super.beforeCreate(args);
59
+
60
+ if (!args.skipGeocoding) {
61
+ await this._geocodeAndSetLocation("beforeCreate");
62
+ }
63
+ }
64
+
65
+ /**
66
+ * ドキュメントが更新される前に `location` を取得してセットします。
67
+ * 住所に変更がない場合はジオコーディングをスキップします。
68
+ * @param {Object} args - Update options.
69
+ * @param {boolean} [args.skipGeocoding=false] - Skip geocoding process.
70
+ * @returns {Promise<void>}
71
+ */
72
+ async beforeUpdate(args = {}) {
73
+ await super.beforeUpdate(args);
74
+
75
+ const currentFullAddress = this.fullAddress;
76
+ const previousFullAddress = this._beforeData?.fullAddress;
77
+
78
+ // 住所に変更がない場合、またはskipGeocodingがtrueの場合はスキップ
79
+ if (
80
+ args.skipGeocoding ||
81
+ (this._beforeData && currentFullAddress === previousFullAddress)
82
+ ) {
83
+ return;
84
+ }
85
+
86
+ await this._geocodeAndSetLocation("beforeUpdate");
87
+ }
88
+
89
+ /**
90
+ * ジオコーディング処理
91
+ * fullAddress から緯度・経度・正規化された住所を取得し、location に設定
92
+ * @private
93
+ * @param {string} context - 呼び出し元のコンテキスト('beforeCreate' | 'beforeUpdate')
94
+ */
95
+ async _geocodeAndSetLocation(context) {
96
+ const address = this.fullAddress;
97
+
98
+ if (!address || address.trim() === "") {
99
+ this.location = null;
100
+ return;
101
+ }
102
+
103
+ if (!GeocodableMixin._geocodingFunction) {
104
+ console.warn(
105
+ `[${this.constructor.className}.${context}] Geocoding function not set. Skipping geocoding.`
106
+ );
107
+ this.location = null;
108
+ return;
109
+ }
110
+
111
+ try {
112
+ const coordinates = await GeocodableMixin._geocodingFunction(address);
113
+
114
+ if (coordinates && coordinates.lat && coordinates.lng) {
115
+ this.location = {
116
+ formattedAddress: coordinates.formattedAddress || address,
117
+ lat: coordinates.lat,
118
+ lng: coordinates.lng,
119
+ };
120
+ } else {
121
+ this.location = null;
122
+ }
123
+ } catch (error) {
124
+ console.warn(
125
+ `[${this.constructor.className}.${context}] Geocoding failed:`,
126
+ error
127
+ );
128
+ this.location = null;
129
+ }
130
+ }
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Geocoding 処理を行う関数(外部から注入)
136
+ * @type {Function|null}
137
+ * @static
138
+ */
139
+ GeocodableMixin._geocodingFunction = null;
140
+
141
+ /**
142
+ * Geocoding 関数を設定します。
143
+ * すべての GeocodableMixin を継承したクラスで共有されます。
144
+ * @param {Function} fn - 住所文字列を受け取り、{ lat, lng, formattedAddress } を返す非同期関数
145
+ * @static
146
+ */
147
+ GeocodableMixin.setGeocodingFunction = function (fn) {
148
+ GeocodableMixin._geocodingFunction = fn;
149
+ };