@acorex-platform/module-asset-management-client 0.0.56 → 0.0.58

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 (44) hide show
  1. package/fesm2022/acorex-platform-module-asset-management-client-acorex-platform-module-asset-management-client-B7YXKaeh.mjs +2789 -0
  2. package/fesm2022/acorex-platform-module-asset-management-client-acorex-platform-module-asset-management-client-B7YXKaeh.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-asset-management-client-asset-usage-values-widget-edit.component-qauvpIMv.mjs +276 -0
  4. package/fesm2022/acorex-platform-module-asset-management-client-asset-usage-values-widget-edit.component-qauvpIMv.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-module-asset-management-client-asset-usage-values-widget-view.component-5psJebph.mjs +55 -0
  6. package/fesm2022/acorex-platform-module-asset-management-client-asset-usage-values-widget-view.component-5psJebph.mjs.map +1 -0
  7. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entities-asset-type.mjs +105 -1
  8. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entities-asset-type.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entities-asset.mjs +290 -5
  10. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entities-asset.mjs.map +1 -1
  11. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-acorex-platform-module-asset-management-client-contracts-entity-catalog--qb3bhd-.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-acorex-platform-module-asset-management-client-contracts-entity-catalog-CnuEulTO.mjs} +9 -9
  12. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-acorex-platform-module-asset-management-client-contracts-entity-catalog--qb3bhd-.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-acorex-platform-module-asset-management-client-contracts-entity-catalog-CnuEulTO.mjs.map} +1 -1
  13. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-rental-history.entity-DoXOgclo.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-rental-history.entity-Cy6qssiv.mjs} +2 -2
  14. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-rental-history.entity-DoXOgclo.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-rental-history.entity-Cy6qssiv.mjs.map} +1 -1
  15. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-assignment.entity-DodjW3aR.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-assignment.entity-BvXjVaqK.mjs} +2 -2
  16. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-assignment.entity-DodjW3aR.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-assignment.entity-BvXjVaqK.mjs.map} +1 -1
  17. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-type.entity-BNV5_Bwu.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-type.entity-DanmgSHH.mjs} +2 -2
  18. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-type.entity-BNV5_Bwu.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system-type.entity-DanmgSHH.mjs.map} +1 -1
  19. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system.entity-BBHHbwxU.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system.entity-BO2GQu2_.mjs} +2 -2
  20. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system.entity-BBHHbwxU.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-system.entity-BO2GQu2_.mjs.map} +1 -1
  21. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section-component.entity-D-P7HwQU.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section-component.entity-DumWQV-O.mjs} +2 -2
  22. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section-component.entity-D-P7HwQU.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section-component.entity-DumWQV-O.mjs.map} +1 -1
  23. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section.entity-TsV2eE47.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section.entity-B5Z8s8_4.mjs} +2 -2
  24. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section.entity-TsV2eE47.mjs.map → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type-section.entity-B5Z8s8_4.mjs.map} +1 -1
  25. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type.entity-CUZ1xIl3.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type.entity-BO3otOO_.mjs} +65 -3
  26. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type.entity-BO3otOO_.mjs.map +1 -0
  27. package/fesm2022/{acorex-platform-module-asset-management-client-contracts-entity-catalog-asset.entity-Ckx8fhZ-.mjs → acorex-platform-module-asset-management-client-contracts-entity-catalog-asset.entity-CvCBkNVZ.mjs} +250 -7
  28. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog-asset.entity-CvCBkNVZ.mjs.map +1 -0
  29. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog-asset.interval-kind-nMKvWqpx.mjs +45 -0
  30. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog-asset.interval-kind-nMKvWqpx.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog.mjs +1 -1
  32. package/fesm2022/acorex-platform-module-asset-management-client-contracts.mjs +241 -1
  33. package/fesm2022/acorex-platform-module-asset-management-client-contracts.mjs.map +1 -1
  34. package/fesm2022/{acorex-platform-module-asset-management-client-recalculate-asset-operational-status.activity-ueTauO_k.mjs → acorex-platform-module-asset-management-client-recalculate-asset-operational-status.activity-RGXS9fI1.mjs} +2 -2
  35. package/fesm2022/{acorex-platform-module-asset-management-client-recalculate-asset-operational-status.activity-ueTauO_k.mjs.map → acorex-platform-module-asset-management-client-recalculate-asset-operational-status.activity-RGXS9fI1.mjs.map} +1 -1
  36. package/fesm2022/acorex-platform-module-asset-management-client.mjs +1 -2496
  37. package/fesm2022/acorex-platform-module-asset-management-client.mjs.map +1 -1
  38. package/i18n/en-AU/asset-management.json +44 -0
  39. package/i18n/en-US/asset-management.json +44 -0
  40. package/i18n/fa-IR/asset-management.json +44 -0
  41. package/package.json +2 -2
  42. package/types/acorex-platform-module-asset-management-client-contracts.d.ts +72 -2
  43. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog-asset-type.entity-CUZ1xIl3.mjs.map +0 -1
  44. package/fesm2022/acorex-platform-module-asset-management-client-contracts-entity-catalog-asset.entity-Ckx8fhZ-.mjs.map +0 -1
@@ -0,0 +1,2789 @@
1
+ import { AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
2
+ import { AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER, AXP_STATUS_PROVIDERS, AXPSearchCommandProvider, createEntityCommandOptions } from '@acorex-platform/framework-client/common';
3
+ import { AXP_CATALOG_SCOPE_DEFINITION_PROVIDER, provideLazyProvider, AXP_FEATURE_DEFINITION_PROVIDER, AXPDataGenerator } from '@acorex-platform/framework-client/core';
4
+ import { AXP_PAGE_COMPONENT_PROVIDER, AXPStandardSectionItemsBuilderComponent } from '@acorex-platform/framework-client/layout/components';
5
+ import { AXPMiddlewareAbortError, AXP_ENTITY_STORAGE_MIDDLEWARE, AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
6
+ import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/layout/widget-core';
7
+ import { provideCommand, provideCommandSetups, AXPCommandService } from '@acorex-platform/framework-client/runtime';
8
+ import * as i0 from '@angular/core';
9
+ import { Injectable, NgModule, inject, input, output, viewChild, signal, computed, effect, ChangeDetectionStrategy, Component, untracked } from '@angular/core';
10
+ import * as contracts from '@acorex-platform/module-asset-management-client/contracts';
11
+ import { ASSET_CATALOG_SCOPE_BOOKING, AXMAssetIntervalKind, AXMAssetIntervalUnit, resolveSupportedIntervalKinds, isAXMAssetUsageKind, AXM_ASSET_USAGE_VALUES_WIDGET, RootConfig, readAssetUsageValues, resolveAssetUsageWrite, AXM_ASSET_USAGE_WRITE_ERRORS, AXMAssetManagementCommandKeys, AXMAssetManagementFeatureKeys, AXPAssetsMaintenancePermissionKeys, AXMAssetManagementMenuKeys, AXM_ASSET_STATUS_DEFINITION_KEY, AXMAssetStatus, ASSET_TYPE_COMPONENTS_PAGE_COMPONENT_KEY, AXMAssetLifecycleStatus } from '@acorex-platform/module-asset-management-client/contracts';
12
+ import { AXPWidgetGroupEnum } from '@acorex-platform/framework-shared/widget-core';
13
+ import { AXPCommonMenuKeys, AXPCommonPermissionGroupKeys } from '@acorex-platform/module-common-client/contracts';
14
+ import { AXPStatusProvider, AXPWidgetsCatalog } from '@acorex-platform/framework-shared/core';
15
+ import { merge, get, isEqual, cloneDeep, isString, defaultTo } from 'lodash';
16
+ import * as i1 from '@acorex/components/button';
17
+ import { AXButtonModule } from '@acorex/components/button';
18
+ import * as i2 from '@acorex/components/decorators';
19
+ import { AXDecoratorModule } from '@acorex/components/decorators';
20
+ import * as i4 from '@acorex/core/translation';
21
+ import { AXTranslationService, resolveMultiLanguageString, AXTranslationModule } from '@acorex/core/translation';
22
+ import { AXPLayoutBuilderService } from '@acorex-platform/framework-client/layout/builder';
23
+ import * as i3 from '@angular/common';
24
+ import { CommonModule } from '@angular/common';
25
+ import { AXPPageLayoutBaseComponent, AXPPageLayoutBase } from '@acorex-platform/framework-client/layout/views';
26
+
27
+ function _mergeNamespaces(n, m) {
28
+ m.forEach(function (e) {
29
+ e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
30
+ if (k !== 'default' && !(k in n)) {
31
+ var d = Object.getOwnPropertyDescriptor(e, k);
32
+ Object.defineProperty(n, k, d.get ? d : {
33
+ enumerable: true,
34
+ get: function () { return e[k]; }
35
+ });
36
+ }
37
+ });
38
+ });
39
+ return Object.freeze(n);
40
+ }
41
+
42
+ //#endregion
43
+ //#region ---- Constants ----
44
+ const QUESTIONNAIRE = 'AssessmentManagement.Questionnaire';
45
+ const QUESTION_BANK_ITEM = 'AssessmentManagement.QuestionBankItem';
46
+ const WORKFLOW_DEFINITION = 'WorkflowManagement.WorkflowDefinition';
47
+ const ASSET_CATALOG_TARGETS = [QUESTIONNAIRE, QUESTION_BANK_ITEM, WORKFLOW_DEFINITION];
48
+ //#endregion
49
+ //#region ---- Provider ----
50
+ class AXMAssetManagementCatalogScopeDefinitionProvider {
51
+ async items() {
52
+ return [
53
+ {
54
+ name: ASSET_CATALOG_SCOPE_BOOKING,
55
+ title: '@asset-management:catalog-scopes.booking.title',
56
+ description: '@asset-management:catalog-scopes.booking.description',
57
+ targets: [...ASSET_CATALOG_TARGETS],
58
+ icon: 'fa-light fa-calendar-check',
59
+ cssClass: 'primary-surface',
60
+ order: 25,
61
+ },
62
+ ];
63
+ }
64
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementCatalogScopeDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
65
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementCatalogScopeDefinitionProvider }); }
66
+ }
67
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementCatalogScopeDefinitionProvider, decorators: [{
68
+ type: Injectable
69
+ }] });
70
+
71
+ //#region ----- Constants -----
72
+ const AXM_ASSET_USAGE_I18N = '@asset-management:assets.entities.asset.fields.usage-values';
73
+ const CONTEXT_PATHS = ['assetType.supportedIntervalKinds'];
74
+ const USAGE_METER_KIND_ORDER = [
75
+ AXMAssetIntervalKind.Distance,
76
+ AXMAssetIntervalKind.OperatingHours,
77
+ AXMAssetIntervalKind.OperationCount,
78
+ ];
79
+ const USAGE_KIND_LABEL_KEYS = {
80
+ [AXMAssetIntervalKind.Date]: `${AXM_ASSET_USAGE_I18N}.kinds.date`,
81
+ [AXMAssetIntervalKind.Distance]: `${AXM_ASSET_USAGE_I18N}.kinds.distance`,
82
+ [AXMAssetIntervalKind.OperatingHours]: `${AXM_ASSET_USAGE_I18N}.kinds.operating-hours`,
83
+ [AXMAssetIntervalKind.OperationCount]: `${AXM_ASSET_USAGE_I18N}.kinds.operation-count`,
84
+ };
85
+ const USAGE_UNIT_LABEL_KEYS = {
86
+ [AXMAssetIntervalUnit.Kilometer]: `${AXM_ASSET_USAGE_I18N}.units.kilometer`,
87
+ [AXMAssetIntervalUnit.Mile]: `${AXM_ASSET_USAGE_I18N}.units.mile`,
88
+ [AXMAssetIntervalUnit.Hour]: `${AXM_ASSET_USAGE_I18N}.units.hour`,
89
+ [AXMAssetIntervalUnit.Operation]: `${AXM_ASSET_USAGE_I18N}.units.operation`,
90
+ };
91
+ //#endregion
92
+ //#region ----- Supported kinds -----
93
+ /** Widget option first, then the asset type already on the form. */
94
+ function readAssetUsageIntervalKinds(options, readContext) {
95
+ const record = options;
96
+ if ('supportedIntervalKinds' in record) {
97
+ return resolveSupportedIntervalKinds(record['supportedIntervalKinds']).kinds;
98
+ }
99
+ for (const path of CONTEXT_PATHS) {
100
+ const resolved = resolveSupportedIntervalKinds(readContext(path));
101
+ if (resolved.kinds.length > 0) {
102
+ return resolved.kinds;
103
+ }
104
+ }
105
+ return [];
106
+ }
107
+ function orderedUsageMeterKinds(kinds) {
108
+ return USAGE_METER_KIND_ORDER.filter((kind) => kinds.includes(kind));
109
+ }
110
+ function isUsageMeterKind(value) {
111
+ return isAXMAssetUsageKind(value);
112
+ }
113
+ //#endregion
114
+
115
+ //#region ----- Imports -----
116
+ //#endregion
117
+ //#region ----- Widget config -----
118
+ const AXMAssetUsageValuesWidget = {
119
+ name: AXM_ASSET_USAGE_VALUES_WIDGET,
120
+ title: `${AXM_ASSET_USAGE_I18N}.title`,
121
+ description: `${AXM_ASSET_USAGE_I18N}.description`,
122
+ type: 'editor',
123
+ designer: { needLabel: true },
124
+ categories: [],
125
+ groups: [AXPWidgetGroupEnum.EntityWidget],
126
+ icon: 'fa-light fa-gauge',
127
+ properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
128
+ components: {
129
+ view: {
130
+ component: () => import('./acorex-platform-module-asset-management-client-asset-usage-values-widget-view.component-5psJebph.mjs').then((c) => c.AXMAssetUsageValuesWidgetViewComponent),
131
+ },
132
+ edit: {
133
+ component: () => import('./acorex-platform-module-asset-management-client-asset-usage-values-widget-edit.component-qauvpIMv.mjs').then((c) => c.AXMAssetUsageValuesWidgetEditComponent),
134
+ },
135
+ designer: {
136
+ component: () => import('./acorex-platform-module-asset-management-client-asset-usage-values-widget-edit.component-qauvpIMv.mjs').then((c) => c.AXMAssetUsageValuesWidgetEditComponent),
137
+ },
138
+ },
139
+ };
140
+ //#endregion
141
+
142
+ //#endregion
143
+ //#region ----- Provider -----
144
+ class AXMAssetUsageValuesWidgetProvider {
145
+ getWidgets() {
146
+ return [AXMAssetUsageValuesWidget];
147
+ }
148
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetUsageValuesWidgetProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
149
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetUsageValuesWidgetProvider }); }
150
+ }
151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetUsageValuesWidgetProvider, decorators: [{
152
+ type: Injectable
153
+ }] });
154
+
155
+ //#region ---- Imports ----
156
+ //#endregion
157
+ //#region ---- Asset System Type Has Child Middleware ----
158
+ /**
159
+ * Enriches AssetSystemType query results with `hasChild` for hierarchical tree views.
160
+ * Uses `childrenCount` from the storage query pipeline when available.
161
+ */
162
+ const assetSystemTypeHasChildMiddleware = {
163
+ target: {
164
+ ops: ['query', 'queryAll'],
165
+ entity: `${RootConfig.module.name}.${RootConfig.entities.assetSystemType.name}`,
166
+ order: 10,
167
+ },
168
+ execute: async (ctx, next) => {
169
+ await next();
170
+ if (!ctx.result?.items?.length) {
171
+ return;
172
+ }
173
+ ctx.result = {
174
+ ...ctx.result,
175
+ items: ctx.result.items.map((item) => ({
176
+ ...item,
177
+ hasChild: (item.childrenCount ?? 0) > 0,
178
+ })),
179
+ };
180
+ },
181
+ };
182
+ //#endregion
183
+
184
+ //#region ---- Imports ----
185
+ //#endregion
186
+ //#region ---- Persist validation ----
187
+ function hasPartyId(value) {
188
+ return typeof value === 'string' && value.trim().length > 0;
189
+ }
190
+ function assertRentalPartyForDirection(data) {
191
+ if (data.rentalDirection === 'rentTo' && !hasPartyId(data.rentedToId)) {
192
+ throw new Error('@asset-management:assetRentalHistories.entities.assetRentalHistory.validations.rented-to-required');
193
+ }
194
+ if (data.rentalDirection === 'rentFrom' && !hasPartyId(data.rentedFromId)) {
195
+ throw new Error('@asset-management:assetRentalHistories.entities.assetRentalHistory.validations.rented-from-required');
196
+ }
197
+ if (!hasPartyId(data.rentedToId) && !hasPartyId(data.rentedFromId)) {
198
+ throw new Error('@asset-management:assetRentalHistories.entities.assetRentalHistory.validations.rental-party-required');
199
+ }
200
+ }
201
+ //#endregion
202
+
203
+ //#region ---- Imports ----
204
+ //#endregion
205
+ //#region ---- Asset Rental History Party Middleware ----
206
+ /**
207
+ * Ensures the supplier party matching rentalDirection is set, and clears the opposite party.
208
+ */
209
+ const assetRentalHistoryPartyMiddleware = {
210
+ target: {
211
+ ops: ['create', 'update'],
212
+ entity: `${RootConfig.module.name}.${RootConfig.entities.assetRentalHistory.name}`,
213
+ order: 8,
214
+ },
215
+ execute: async (ctx, next) => {
216
+ if (!ctx.data || typeof ctx.data !== 'object') {
217
+ await next();
218
+ return;
219
+ }
220
+ const incoming = ctx.data;
221
+ let previous = (ctx.previous ?? {});
222
+ if (ctx.op === 'update' && ctx.id != null && !ctx.previous) {
223
+ previous = (await ctx.backend.getOne(ctx.entityName, ctx.id).catch(() => ({})));
224
+ }
225
+ const merged = {
226
+ ...previous,
227
+ ...incoming,
228
+ };
229
+ if (merged.rentalDirection === 'rentTo') {
230
+ incoming.rentedFromId = null;
231
+ incoming.rentedFrom = undefined;
232
+ merged.rentedFromId = null;
233
+ merged.rentedFrom = undefined;
234
+ }
235
+ else if (merged.rentalDirection === 'rentFrom') {
236
+ incoming.rentedToId = null;
237
+ incoming.rentedTo = undefined;
238
+ merged.rentedToId = null;
239
+ merged.rentedTo = undefined;
240
+ }
241
+ try {
242
+ assertRentalPartyForDirection(merged);
243
+ }
244
+ catch (error) {
245
+ throw new AXPMiddlewareAbortError(error instanceof Error ? error.message : String(error), {
246
+ code: 'RENTAL_PARTY_REQUIRED',
247
+ status: 400,
248
+ });
249
+ }
250
+ await next();
251
+ },
252
+ };
253
+ //#endregion
254
+
255
+ //#region ---- Imports ----
256
+ //#endregion
257
+ //#region ---- Constants ----
258
+ const ASSET_TYPE_ENTITY$1 = `${RootConfig.module.name}.${RootConfig.entities.assetType.name}`;
259
+ const INVALID_INTERVAL_KINDS_MESSAGE = '@asset-management:assetTypes.entities.assetType.fields.supported-interval-kinds.validation.invalid';
260
+ //#endregion
261
+ //#region ---- Helpers ----
262
+ function applySupportedIntervalKinds(record, kinds) {
263
+ record['supportedIntervalKinds'] = kinds;
264
+ }
265
+ function readRecord$1(value) {
266
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
267
+ return null;
268
+ }
269
+ return value;
270
+ }
271
+ //#endregion
272
+ //#region ---- Asset type interval kinds middleware ----
273
+ /**
274
+ * Persists `supportedIntervalKinds` as a string array.
275
+ * Missing or empty input is saved and returned as `[]`. Unknown values abort the write.
276
+ */
277
+ const assetTypeIntervalKindsMiddleware = {
278
+ target: {
279
+ ops: ['create', 'update', 'upsertOne', 'getOne', 'getAll', 'query', 'queryAll', 'getMany'],
280
+ entity: ASSET_TYPE_ENTITY$1,
281
+ order: 12,
282
+ },
283
+ execute: async (ctx, next) => {
284
+ const isWrite = ctx.op === 'create' || ctx.op === 'update' || ctx.op === 'upsertOne';
285
+ if (isWrite && ctx.data && typeof ctx.data === 'object') {
286
+ const data = ctx.data;
287
+ const fieldPresent = ctx.op === 'create' || ctx.op === 'upsertOne' || 'supportedIntervalKinds' in data;
288
+ if (fieldPresent) {
289
+ const resolved = resolveSupportedIntervalKinds(data['supportedIntervalKinds']);
290
+ if (resolved.invalid) {
291
+ throw new AXPMiddlewareAbortError(INVALID_INTERVAL_KINDS_MESSAGE, {
292
+ code: 'ASSET_TYPE_INTERVAL_KIND_INVALID',
293
+ status: 400,
294
+ });
295
+ }
296
+ applySupportedIntervalKinds(data, resolved.kinds);
297
+ }
298
+ }
299
+ await next();
300
+ if (ctx.op === 'getOne') {
301
+ const record = readRecord$1(ctx.result);
302
+ if (record) {
303
+ applySupportedIntervalKinds(record, resolveSupportedIntervalKinds(record['supportedIntervalKinds']).kinds);
304
+ }
305
+ return;
306
+ }
307
+ const items = Array.isArray(ctx.result)
308
+ ? ctx.result
309
+ : Array.isArray(ctx.result?.items)
310
+ ? ctx.result.items
311
+ : null;
312
+ if (!items) {
313
+ return;
314
+ }
315
+ for (const item of items) {
316
+ const record = readRecord$1(item);
317
+ if (!record) {
318
+ continue;
319
+ }
320
+ applySupportedIntervalKinds(record, resolveSupportedIntervalKinds(record['supportedIntervalKinds']).kinds);
321
+ }
322
+ },
323
+ };
324
+ //#endregion
325
+
326
+ //#region ---- Imports ----
327
+ //#endregion
328
+ //#region ---- Constants ----
329
+ const ASSET_ENTITY = `${RootConfig.module.name}.${RootConfig.entities.asset.name}`;
330
+ const ASSET_TYPE_ENTITY = `${RootConfig.module.name}.${RootConfig.entities.assetType.name}`;
331
+ const WRITE_OPS = new Set(['create', 'update', 'upsertOne']);
332
+ //#endregion
333
+ //#region ---- Helpers ----
334
+ function readRecord(value) {
335
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
336
+ return null;
337
+ }
338
+ return value;
339
+ }
340
+ function assignUsageValues(record) {
341
+ record['usageValues'] = readAssetUsageValues(record['usageValues']);
342
+ }
343
+ async function loadStoredAsset(ctx) {
344
+ const previous = readRecord(ctx.previous);
345
+ if (previous) {
346
+ return previous;
347
+ }
348
+ if (ctx.op === 'create' || ctx.id == null || ctx.id === '') {
349
+ return null;
350
+ }
351
+ if (ctx.op === 'upsertOne') {
352
+ try {
353
+ return readRecord(await ctx.backend.getOne(ASSET_ENTITY, ctx.id));
354
+ }
355
+ catch {
356
+ return null;
357
+ }
358
+ }
359
+ return readRecord(await ctx.backend.getOne(ASSET_ENTITY, ctx.id));
360
+ }
361
+ async function loadSupportedKinds(ctx, assetTypeId) {
362
+ if (typeof assetTypeId !== 'string' || assetTypeId.length === 0) {
363
+ return [];
364
+ }
365
+ const assetType = readRecord(await ctx.backend.getOne(ASSET_TYPE_ENTITY, assetTypeId));
366
+ return resolveSupportedIntervalKinds(assetType?.['supportedIntervalKinds']).kinds;
367
+ }
368
+ //#endregion
369
+ //#region ---- Asset usage values middleware ----
370
+ /**
371
+ * Stores one current reading per meter kind.
372
+ * A missing create value is `[]`. An update replaces the same kind and keeps the others.
373
+ */
374
+ const assetUsageValuesMiddleware = {
375
+ target: {
376
+ ops: ['create', 'update', 'upsertOne', 'getOne', 'getAll', 'query', 'queryAll', 'getMany'],
377
+ entity: ASSET_ENTITY,
378
+ order: 14,
379
+ },
380
+ execute: async (ctx, next) => {
381
+ if (WRITE_OPS.has(ctx.op)) {
382
+ const data = readRecord(ctx.data);
383
+ const fieldPresent = ctx.op === 'create' || ctx.op === 'upsertOne' || (data != null && 'usageValues' in data);
384
+ if (data && fieldPresent) {
385
+ const stored = await loadStoredAsset(ctx);
386
+ const incoming = data['usageValues'];
387
+ const supportedKinds = Array.isArray(incoming) && incoming.length > 0
388
+ ? await loadSupportedKinds(ctx, data['assetTypeId'] ?? stored?.['assetTypeId'])
389
+ : [];
390
+ const resolved = resolveAssetUsageWrite(incoming, {
391
+ supportedKinds,
392
+ previous: stored?.['usageValues'],
393
+ mergeWithPrevious: stored != null && ctx.op !== 'create',
394
+ });
395
+ if (resolved.issue) {
396
+ const error = AXM_ASSET_USAGE_WRITE_ERRORS[resolved.issue];
397
+ throw new AXPMiddlewareAbortError(error.message, { code: error.code, status: 400 });
398
+ }
399
+ data['usageValues'] = resolved.values;
400
+ }
401
+ }
402
+ await next();
403
+ if (WRITE_OPS.has(ctx.op)) {
404
+ return;
405
+ }
406
+ if (ctx.op === 'getOne') {
407
+ const record = readRecord(ctx.result);
408
+ if (record) {
409
+ assignUsageValues(record);
410
+ }
411
+ return;
412
+ }
413
+ const items = Array.isArray(ctx.result)
414
+ ? ctx.result
415
+ : Array.isArray(ctx.result?.items)
416
+ ? ctx.result.items
417
+ : null;
418
+ if (!items) {
419
+ return;
420
+ }
421
+ for (const item of items) {
422
+ const record = readRecord(item);
423
+ if (record) {
424
+ assignUsageValues(record);
425
+ }
426
+ }
427
+ },
428
+ };
429
+ //#endregion
430
+
431
+ //#region ---- Middleware Exports ----
432
+ //#endregion
433
+
434
+ //#region ---- Imports ----
435
+ //#endregion
436
+ //#region ---- Module ----
437
+ class AXMAssetManagementModule {
438
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
439
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementModule }); }
440
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementModule, providers: [
441
+ {
442
+ provide: AXP_CATALOG_SCOPE_DEFINITION_PROVIDER,
443
+ useClass: AXMAssetManagementCatalogScopeDefinitionProvider,
444
+ multi: true,
445
+ },
446
+ {
447
+ provide: AXP_WIDGET_DEFINITION_PROVIDER,
448
+ useClass: AXMAssetUsageValuesWidgetProvider,
449
+ multi: true,
450
+ },
451
+ // Feature Definition Provider (lazy-loaded)
452
+ provideLazyProvider(AXP_FEATURE_DEFINITION_PROVIDER, () => Promise.resolve().then(function () { return featureDefinition_provider; }).then((m) => m.AXMAssetManagementFeatureDefinitionProvider)),
453
+ // Permission Definition Provider (lazy-loaded)
454
+ provideLazyProvider(AXP_PERMISSION_DEFINITION_PROVIDER, () => Promise.resolve().then(function () { return permissionDefinition_provider; }).then((m) => m.AXMAssetManagementPermissionDefinitionProvider)),
455
+ // Menu Provider (lazy-loaded)
456
+ provideLazyProvider(AXP_MENU_PROVIDER, () => Promise.resolve().then(function () { return menu_provider; }).then((m) => m.AXMAssetManagementMenuProvider)),
457
+ // Entity Provider (lazy-loaded)
458
+ // Search Provider (lazy-loaded)
459
+ provideLazyProvider(AXP_SEARCH_PROVIDER, () => Promise.resolve().then(function () { return searchCommand_provider; }).then((m) => m.AXMAssetManagementSearchCommandProvider)),
460
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => Promise.resolve().then(function () { return index; }).then((m) => m.AXMAssetTypeComponentsPageComponentProvider)),
461
+ provideCommand('AssetType:Components:Save', () => Promise.resolve().then(function () { return saveAssetTypeComponents_command; }).then((m) => m.AXMSaveAssetTypeComponentsCommand)),
462
+ provideCommand(AXMAssetManagementCommandKeys.AssetRentalHistory.RentFrom, () => Promise.resolve().then(function () { return createAssetRentalHistoryRent_commands; }).then((m) => m.AXMCreateAssetRentalHistoryRentFromCommand)),
463
+ provideCommand(AXMAssetManagementCommandKeys.AssetRentalHistory.RentTo, () => Promise.resolve().then(function () { return createAssetRentalHistoryRent_commands; }).then((m) => m.AXMCreateAssetRentalHistoryRentToCommand)),
464
+ provideCommandSetups([
465
+ {
466
+ key: AXMAssetManagementCommandKeys.WorkflowActivity.RecalculateOperationalStatus,
467
+ command: () => import('./acorex-platform-module-asset-management-client-recalculate-asset-operational-status.activity-RGXS9fI1.mjs').then((c) => c.RecalculateAssetOperationalStatusActivity),
468
+ },
469
+ ]),
470
+ // provideLazyProvider(AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, () =>
471
+ // import('./features/asset-status.rules').then((m) => m.AXMAssetManagementAssetStatusRulesExpressionScopeProvider),
472
+ // ),
473
+ // Status Providers
474
+ provideLazyProvider(AXP_STATUS_PROVIDERS, () => Promise.resolve().then(function () { return assetStatus_provider; }).then((m) => m.AXMAssetManagementAssetStatusProvider)),
475
+ provideLazyProvider(AXP_STATUS_PROVIDERS, () => import('./acorex-platform-module-asset-management-client-asset-rental-history-status.provider-DwhQPb0-.mjs').then((m) => m.AXMAssetManagementAssetRentalHistoryStatusProvider)),
476
+ provideLazyProvider(AXP_STATUS_PROVIDERS, () => import('./acorex-platform-module-asset-management-client-asset-lifecycle.provider-BDaCpGsv.mjs').then((m) => m.AXMAssetManagementAssetLifecycleStatusProvider)),
477
+ {
478
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
479
+ useValue: assetSystemTypeHasChildMiddleware,
480
+ multi: true,
481
+ },
482
+ {
483
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
484
+ useValue: assetRentalHistoryPartyMiddleware,
485
+ multi: true,
486
+ },
487
+ {
488
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
489
+ useValue: assetTypeIntervalKindsMiddleware,
490
+ multi: true,
491
+ },
492
+ {
493
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
494
+ useValue: assetUsageValuesMiddleware,
495
+ multi: true,
496
+ },
497
+ ] }); }
498
+ }
499
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementModule, decorators: [{
500
+ type: NgModule,
501
+ args: [{
502
+ imports: [],
503
+ providers: [
504
+ {
505
+ provide: AXP_CATALOG_SCOPE_DEFINITION_PROVIDER,
506
+ useClass: AXMAssetManagementCatalogScopeDefinitionProvider,
507
+ multi: true,
508
+ },
509
+ {
510
+ provide: AXP_WIDGET_DEFINITION_PROVIDER,
511
+ useClass: AXMAssetUsageValuesWidgetProvider,
512
+ multi: true,
513
+ },
514
+ // Feature Definition Provider (lazy-loaded)
515
+ provideLazyProvider(AXP_FEATURE_DEFINITION_PROVIDER, () => Promise.resolve().then(function () { return featureDefinition_provider; }).then((m) => m.AXMAssetManagementFeatureDefinitionProvider)),
516
+ // Permission Definition Provider (lazy-loaded)
517
+ provideLazyProvider(AXP_PERMISSION_DEFINITION_PROVIDER, () => Promise.resolve().then(function () { return permissionDefinition_provider; }).then((m) => m.AXMAssetManagementPermissionDefinitionProvider)),
518
+ // Menu Provider (lazy-loaded)
519
+ provideLazyProvider(AXP_MENU_PROVIDER, () => Promise.resolve().then(function () { return menu_provider; }).then((m) => m.AXMAssetManagementMenuProvider)),
520
+ // Entity Provider (lazy-loaded)
521
+ // Search Provider (lazy-loaded)
522
+ provideLazyProvider(AXP_SEARCH_PROVIDER, () => Promise.resolve().then(function () { return searchCommand_provider; }).then((m) => m.AXMAssetManagementSearchCommandProvider)),
523
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => Promise.resolve().then(function () { return index; }).then((m) => m.AXMAssetTypeComponentsPageComponentProvider)),
524
+ provideCommand('AssetType:Components:Save', () => Promise.resolve().then(function () { return saveAssetTypeComponents_command; }).then((m) => m.AXMSaveAssetTypeComponentsCommand)),
525
+ provideCommand(AXMAssetManagementCommandKeys.AssetRentalHistory.RentFrom, () => Promise.resolve().then(function () { return createAssetRentalHistoryRent_commands; }).then((m) => m.AXMCreateAssetRentalHistoryRentFromCommand)),
526
+ provideCommand(AXMAssetManagementCommandKeys.AssetRentalHistory.RentTo, () => Promise.resolve().then(function () { return createAssetRentalHistoryRent_commands; }).then((m) => m.AXMCreateAssetRentalHistoryRentToCommand)),
527
+ provideCommandSetups([
528
+ {
529
+ key: AXMAssetManagementCommandKeys.WorkflowActivity.RecalculateOperationalStatus,
530
+ command: () => import('./acorex-platform-module-asset-management-client-recalculate-asset-operational-status.activity-RGXS9fI1.mjs').then((c) => c.RecalculateAssetOperationalStatusActivity),
531
+ },
532
+ ]),
533
+ // provideLazyProvider(AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, () =>
534
+ // import('./features/asset-status.rules').then((m) => m.AXMAssetManagementAssetStatusRulesExpressionScopeProvider),
535
+ // ),
536
+ // Status Providers
537
+ provideLazyProvider(AXP_STATUS_PROVIDERS, () => Promise.resolve().then(function () { return assetStatus_provider; }).then((m) => m.AXMAssetManagementAssetStatusProvider)),
538
+ provideLazyProvider(AXP_STATUS_PROVIDERS, () => import('./acorex-platform-module-asset-management-client-asset-rental-history-status.provider-DwhQPb0-.mjs').then((m) => m.AXMAssetManagementAssetRentalHistoryStatusProvider)),
539
+ provideLazyProvider(AXP_STATUS_PROVIDERS, () => import('./acorex-platform-module-asset-management-client-asset-lifecycle.provider-BDaCpGsv.mjs').then((m) => m.AXMAssetManagementAssetLifecycleStatusProvider)),
540
+ {
541
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
542
+ useValue: assetSystemTypeHasChildMiddleware,
543
+ multi: true,
544
+ },
545
+ {
546
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
547
+ useValue: assetRentalHistoryPartyMiddleware,
548
+ multi: true,
549
+ },
550
+ {
551
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
552
+ useValue: assetTypeIntervalKindsMiddleware,
553
+ multi: true,
554
+ },
555
+ {
556
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
557
+ useValue: assetUsageValuesMiddleware,
558
+ multi: true,
559
+ },
560
+ ],
561
+ }]
562
+ }] });
563
+
564
+ //#region ---- Imports ----
565
+ //#endregion
566
+ //#region ---- Feature Definition Provider ----
567
+ /**
568
+ * Asset Management Feature Definition Provider.
569
+ * Provides feature definitions for the Asset Management module.
570
+ */
571
+ class AXMAssetManagementFeatureDefinitionProvider {
572
+ async provide(context) {
573
+ // Asset Management feature
574
+ context.addFeature(AXMAssetManagementFeatureKeys.AssetManagement, {
575
+ title: '@asset-management:features.asset-management.title',
576
+ description: '@asset-management:features.asset-management.description',
577
+ defaultValue: true,
578
+ type: 'boolean',
579
+ });
580
+ // // Advanced Maintenance feature
581
+ // context.addFeature(AXMAssetManagementFeatureKeys.AdvancedMaintenance, {
582
+ // title: '@asset-management:features.advanced-maintenance.title',
583
+ // description: '@asset-management:features.advanced-maintenance.description',
584
+ // defaultValue: false,
585
+ // type: 'boolean',
586
+ // });
587
+ // // Maintenance Scheduling feature
588
+ // context.addFeature(AXMAssetManagementFeatureKeys.MaintenanceScheduling, {
589
+ // title: '@asset-management:features.maintenance-scheduling.title',
590
+ // description: '@asset-management:features.maintenance-scheduling.description',
591
+ // defaultValue: true,
592
+ // type: 'boolean',
593
+ // });
594
+ // // Inspection Workflow feature
595
+ // context.addFeature(AXMAssetManagementFeatureKeys.InspectionWorkflow, {
596
+ // title: '@asset-management:features.inspection-workflow.title',
597
+ // description: '@asset-management:features.inspection-workflow.description',
598
+ // defaultValue: true,
599
+ // type: 'boolean',
600
+ // });
601
+ }
602
+ }
603
+ //#endregion
604
+
605
+ var featureDefinition_provider = /*#__PURE__*/Object.freeze({
606
+ __proto__: null,
607
+ AXMAssetManagementFeatureDefinitionProvider: AXMAssetManagementFeatureDefinitionProvider
608
+ });
609
+
610
+ //#region ---- Imports ----
611
+ //#endregion
612
+ //#region ---- Menu Provider ----
613
+ /**
614
+ * Asset Management Menu Provider.
615
+ * Provides menu items for the Asset Management module with permission and feature checks.
616
+ */
617
+ class AXMAssetManagementMenuProvider {
618
+ constructor() {
619
+ this.entityService = inject(AXPEntityService);
620
+ }
621
+ async provide(context) {
622
+ const module = RootConfig.module;
623
+ const keys = AXPAssetsMaintenancePermissionKeys;
624
+ const PLAN_EQUIPMENT_MENU_KEY = 'Configuration:Menu:PlantEquipment';
625
+ context.find(AXPCommonMenuKeys.PlantEquipment).addItems([
626
+ {
627
+ name: AXMAssetManagementMenuKeys.Assets,
628
+ text: '@asset-management:assets.menus.root.title',
629
+ path: this.entityService.createPath(module.name, RootConfig.entities.asset.name),
630
+ priority: 2,
631
+ icon: RootConfig.entities.asset.icon,
632
+ policy: {
633
+ features: [module.name],
634
+ permissions: [keys.MaintainAssets],
635
+ },
636
+ },
637
+ {
638
+ name: AXMAssetManagementMenuKeys.AssetSystems,
639
+ text: '@asset-management:assetSystems.menus.root.title',
640
+ path: this.entityService.createPath(module.name, RootConfig.entities.assetSystem.name),
641
+ priority: 3,
642
+ icon: RootConfig.entities.assetSystem.icon,
643
+ policy: {
644
+ features: [module.name],
645
+ permissions: [keys.MaintainAssets],
646
+ },
647
+ },
648
+ ]);
649
+ const mainAssetsMaintenanceDivider = context.find(AXMAssetManagementMenuKeys.MainPlanEquipmentAssetsMaintenanceDivider);
650
+ if (!mainAssetsMaintenanceDivider.exists) {
651
+ context.find(AXPCommonMenuKeys.PlantEquipment).addItems([
652
+ {
653
+ name: AXMAssetManagementMenuKeys.MainPlanEquipmentAssetsMaintenanceDivider,
654
+ text: '',
655
+ type: 'break',
656
+ priority: 10,
657
+ },
658
+ ]);
659
+ }
660
+ const planEquipmentMenu = context.find(PLAN_EQUIPMENT_MENU_KEY);
661
+ if (!planEquipmentMenu.exists) {
662
+ context.find(AXPCommonMenuKeys.Configuration).addItems([
663
+ {
664
+ name: PLAN_EQUIPMENT_MENU_KEY,
665
+ priority: 9000,
666
+ text: '@general:menus.plan-equipment.title',
667
+ icon: module.icon,
668
+ },
669
+ ]);
670
+ }
671
+ context.find(PLAN_EQUIPMENT_MENU_KEY).addItems([
672
+ {
673
+ name: AXMAssetManagementMenuKeys.AssetTypes,
674
+ text: '@asset-management:assetTypes.menus.root.title',
675
+ path: this.entityService.createPath(module.name, RootConfig.entities.assetType.name),
676
+ priority: 2,
677
+ icon: RootConfig.entities.assetType.icon,
678
+ policy: {
679
+ features: [module.name],
680
+ permissions: [keys.Setup],
681
+ },
682
+ },
683
+ {
684
+ name: AXMAssetManagementMenuKeys.AssetSystemTypes,
685
+ text: '@asset-management:assetSystemTypes.menus.root.title',
686
+ path: this.entityService.createPath(module.name, RootConfig.entities.assetSystemType.name),
687
+ priority: 3,
688
+ icon: RootConfig.entities.assetSystemType.icon,
689
+ policy: {
690
+ features: [module.name],
691
+ permissions: [keys.Setup],
692
+ },
693
+ },
694
+ ]);
695
+ const planEquipmentAssetsMaintenanceDivider = context.find(AXMAssetManagementMenuKeys.PlanEquipmentAssetsMaintenanceDivider);
696
+ if (!planEquipmentAssetsMaintenanceDivider.exists) {
697
+ context.find(PLAN_EQUIPMENT_MENU_KEY).addItems([
698
+ {
699
+ name: AXMAssetManagementMenuKeys.PlanEquipmentAssetsMaintenanceDivider,
700
+ text: '',
701
+ type: 'break',
702
+ priority: 10,
703
+ },
704
+ ]);
705
+ }
706
+ }
707
+ }
708
+ //#endregion
709
+
710
+ var menu_provider = /*#__PURE__*/Object.freeze({
711
+ __proto__: null,
712
+ AXMAssetManagementMenuProvider: AXMAssetManagementMenuProvider
713
+ });
714
+
715
+ //#endregion
716
+ //#region ----- Permission Definition Provider -----
717
+ /**
718
+ * Registers Assets & Maintenance capabilities owned by asset-management.
719
+ */
720
+ class AXMAssetManagementPermissionDefinitionProvider {
721
+ async define(context) {
722
+ const keys = AXPAssetsMaintenancePermissionKeys;
723
+ const groups = AXPCommonPermissionGroupKeys;
724
+ const P = '@common:assets-maintenance.permissions';
725
+ const G = '@common:permission-groups';
726
+ context.addGroup(groups.AssetsMaintenance.Root, `${G}.assets-maintenance.title`, `${G}.assets-maintenance.description`, { order: 70 });
727
+ context
728
+ .addGroup(groups.AssetsMaintenance.Assets, `${G}.assets-maintenance-assets.title`, `${G}.assets-maintenance-assets.description`, { parent: groups.AssetsMaintenance.Root, order: 10 })
729
+ .addPermission(keys.Access, `${P}.access.title`, `${P}.access.description`)
730
+ .endPermission()
731
+ .addPermission(keys.MaintainAssets, `${P}.maintain-assets.title`, `${P}.maintain-assets.description`)
732
+ .endPermission()
733
+ .addPermission(keys.Setup, `${P}.setup.title`, `${P}.setup.description`)
734
+ .endPermission()
735
+ .endGroup();
736
+ }
737
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
738
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementPermissionDefinitionProvider }); }
739
+ }
740
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetManagementPermissionDefinitionProvider, decorators: [{
741
+ type: Injectable
742
+ }] });
743
+
744
+ var permissionDefinition_provider = /*#__PURE__*/Object.freeze({
745
+ __proto__: null,
746
+ AXMAssetManagementPermissionDefinitionProvider: AXMAssetManagementPermissionDefinitionProvider
747
+ });
748
+
749
+ //#region ---- Imports ----
750
+ //#endregion
751
+ //#region ---- Search Command Provider ----
752
+ class AXMAssetManagementSearchCommandProvider extends AXPSearchCommandProvider {
753
+ constructor() {
754
+ super(...arguments);
755
+ this.commands = [
756
+ {
757
+ id: 'create-asset',
758
+ group: 'command',
759
+ title: '@asset-management:assets.search.create-asset.title',
760
+ icon: RootConfig.entities.asset.icon,
761
+ description: '@asset-management:assets.search.create-asset.description',
762
+ command: {
763
+ name: 'Entity:Create',
764
+ options: createEntityCommandOptions(`${RootConfig.module.name}.${RootConfig.entities.asset.name}`, {
765
+ name: RootConfig.entities.asset.name,
766
+ module: RootConfig.module.name,
767
+ title: RootConfig.entities.asset.title,
768
+ }),
769
+ },
770
+ },
771
+ ];
772
+ }
773
+ }
774
+ //#endregion
775
+
776
+ var searchCommand_provider = /*#__PURE__*/Object.freeze({
777
+ __proto__: null,
778
+ AXMAssetManagementSearchCommandProvider: AXMAssetManagementSearchCommandProvider
779
+ });
780
+
781
+ class AXMAssetManagementAssetStatusProvider extends AXPStatusProvider {
782
+ constructor() {
783
+ super(...arguments);
784
+ this.key = AXM_ASSET_STATUS_DEFINITION_KEY;
785
+ this.statuses = [
786
+ {
787
+ name: AXMAssetStatus.Available,
788
+ title: '@asset-management:assets.states.available',
789
+ icon: 'fa-light fa-circle-check',
790
+ color: 'success',
791
+ order: 1,
792
+ isInitial: true,
793
+ isFinal: false,
794
+ generateView: true,
795
+ },
796
+ {
797
+ name: AXMAssetStatus.Assigned,
798
+ title: '@asset-management:assets.states.assigned',
799
+ icon: 'fa-light fa-user-check',
800
+ color: 'info',
801
+ order: 2,
802
+ isInitial: false,
803
+ isFinal: false,
804
+ generateView: true,
805
+ },
806
+ {
807
+ name: AXMAssetStatus.UnderMaintenanceInspection,
808
+ title: '@asset-management:assets.states.under-maintenance',
809
+ icon: 'fa-light fa-toolbox',
810
+ color: 'warning',
811
+ order: 3,
812
+ isInitial: false,
813
+ isFinal: false,
814
+ generateView: true,
815
+ },
816
+ {
817
+ name: AXMAssetStatus.OutOfService,
818
+ title: '@asset-management:assets.states.out-of-service',
819
+ icon: 'fa-light fa-triangle-exclamation',
820
+ color: 'danger',
821
+ order: 4,
822
+ isInitial: false,
823
+ isFinal: false,
824
+ generateView: true,
825
+ },
826
+ {
827
+ name: AXMAssetStatus.Lost,
828
+ title: '@asset-management:assets.states.lost',
829
+ icon: 'fa-light fa-magnifying-glass-minus',
830
+ color: 'danger',
831
+ order: 5,
832
+ isInitial: false,
833
+ isFinal: false,
834
+ generateView: true,
835
+ },
836
+ ];
837
+ this.transitions = [
838
+ {
839
+ from: AXMAssetStatus.Available,
840
+ to: AXMAssetStatus.Assigned,
841
+ title: '@asset-management:assets.transitions.assign',
842
+ },
843
+ {
844
+ from: AXMAssetStatus.Assigned,
845
+ to: AXMAssetStatus.Available,
846
+ title: '@asset-management:assets.transitions.unassign',
847
+ },
848
+ {
849
+ from: AXMAssetStatus.Available,
850
+ to: AXMAssetStatus.UnderMaintenanceInspection,
851
+ title: '@asset-management:assets.transitions.start-maintenance',
852
+ },
853
+ {
854
+ from: AXMAssetStatus.Assigned,
855
+ to: AXMAssetStatus.UnderMaintenanceInspection,
856
+ title: '@asset-management:assets.transitions.start-maintenance',
857
+ },
858
+ {
859
+ from: AXMAssetStatus.OutOfService,
860
+ to: AXMAssetStatus.UnderMaintenanceInspection,
861
+ title: '@asset-management:assets.transitions.start-maintenance',
862
+ },
863
+ {
864
+ from: AXMAssetStatus.UnderMaintenanceInspection,
865
+ to: AXMAssetStatus.Available,
866
+ title: '@asset-management:assets.transitions.release-as-available',
867
+ },
868
+ {
869
+ from: AXMAssetStatus.UnderMaintenanceInspection,
870
+ to: AXMAssetStatus.Assigned,
871
+ title: '@asset-management:assets.transitions.restore-assignment',
872
+ },
873
+ {
874
+ from: AXMAssetStatus.UnderMaintenanceInspection,
875
+ to: AXMAssetStatus.OutOfService,
876
+ title: '@asset-management:assets.transitions.keep-out-of-service',
877
+ },
878
+ {
879
+ from: AXMAssetStatus.Available,
880
+ to: AXMAssetStatus.OutOfService,
881
+ title: '@asset-management:assets.transitions.mark-out-of-service',
882
+ },
883
+ {
884
+ from: AXMAssetStatus.Assigned,
885
+ to: AXMAssetStatus.OutOfService,
886
+ title: '@asset-management:assets.transitions.mark-out-of-service',
887
+ },
888
+ {
889
+ from: AXMAssetStatus.OutOfService,
890
+ to: AXMAssetStatus.Available,
891
+ title: '@asset-management:assets.transitions.restore-service',
892
+ },
893
+ {
894
+ from: AXMAssetStatus.OutOfService,
895
+ to: AXMAssetStatus.Assigned,
896
+ title: '@asset-management:assets.transitions.restore-service',
897
+ },
898
+ {
899
+ from: AXMAssetStatus.Available,
900
+ to: AXMAssetStatus.Lost,
901
+ title: '@asset-management:assets.transitions.mark-lost',
902
+ },
903
+ {
904
+ from: AXMAssetStatus.Assigned,
905
+ to: AXMAssetStatus.Lost,
906
+ title: '@asset-management:assets.transitions.mark-lost',
907
+ },
908
+ {
909
+ from: AXMAssetStatus.OutOfService,
910
+ to: AXMAssetStatus.Lost,
911
+ title: '@asset-management:assets.transitions.mark-lost',
912
+ },
913
+ {
914
+ from: AXMAssetStatus.UnderMaintenanceInspection,
915
+ to: AXMAssetStatus.Lost,
916
+ title: '@asset-management:assets.transitions.mark-lost',
917
+ },
918
+ {
919
+ from: AXMAssetStatus.Lost,
920
+ to: AXMAssetStatus.Available,
921
+ title: '@asset-management:assets.transitions.found',
922
+ },
923
+ {
924
+ from: AXMAssetStatus.Lost,
925
+ to: AXMAssetStatus.Assigned,
926
+ title: '@asset-management:assets.transitions.found',
927
+ },
928
+ {
929
+ from: AXMAssetStatus.Lost,
930
+ to: AXMAssetStatus.OutOfService,
931
+ title: '@asset-management:assets.transitions.found-out-of-service',
932
+ },
933
+ ];
934
+ // readonly transitions: AXPStatusTransition[] = [
935
+ // {
936
+ // from: AXMAssetStatus.Available,
937
+ // to: AXMAssetStatus.Assigned,
938
+ // title: '@asset-management:assets.transitions.assign',
939
+ // },
940
+ // {
941
+ // from: AXMAssetStatus.Assigned,
942
+ // to: AXMAssetStatus.Available,
943
+ // title: '@asset-management:assets.transitions.unassign',
944
+ // },
945
+ // {
946
+ // from: AXMAssetStatus.Assigned,
947
+ // to: AXMAssetStatus.UnderMaintenanceInspection,
948
+ // title: '@asset-management:assets.transitions.start-maintenance',
949
+ // },
950
+ // {
951
+ // from: AXMAssetStatus.Assigned,
952
+ // to: AXMAssetStatus.OutOfService,
953
+ // title: '@asset-management:assets.transitions.mark-out-of-service',
954
+ // },
955
+ // {
956
+ // from: AXMAssetStatus.Available,
957
+ // to: AXMAssetStatus.UnderMaintenanceInspection,
958
+ // title: '@asset-management:assets.transitions.start-maintenance',
959
+ // },
960
+ // {
961
+ // from: AXMAssetStatus.OutOfService,
962
+ // to: AXMAssetStatus.UnderMaintenanceInspection,
963
+ // title: '@asset-management:assets.transitions.start-maintenance',
964
+ // },
965
+ // {
966
+ // from: AXMAssetStatus.UnderMaintenanceInspection,
967
+ // to: AXMAssetStatus.Available,
968
+ // title: '@asset-management:assets.transitions.complete-maintenance',
969
+ // },
970
+ // {
971
+ // from: AXMAssetStatus.Available,
972
+ // to: AXMAssetStatus.OutOfService,
973
+ // title: '@asset-management:assets.transitions.mark-out-of-service',
974
+ // },
975
+ // {
976
+ // from: AXMAssetStatus.OutOfService,
977
+ // to: AXMAssetStatus.Available,
978
+ // title: '@asset-management:assets.transitions.restore-service',
979
+ // },
980
+ // {
981
+ // from: AXMAssetStatus.Available,
982
+ // to: AXMAssetStatus.Lost,
983
+ // title: '@asset-management:assets.transitions.mark-lost',
984
+ // },
985
+ // {
986
+ // from: AXMAssetStatus.Assigned,
987
+ // to: AXMAssetStatus.Lost,
988
+ // title: '@asset-management:assets.transitions.mark-lost',
989
+ // },
990
+ // {
991
+ // from: AXMAssetStatus.Lost,
992
+ // to: AXMAssetStatus.Available,
993
+ // title: '@asset-management:assets.transitions.found',
994
+ // },
995
+ // ];
996
+ this.defaultStatus = AXMAssetStatus.Available;
997
+ }
998
+ }
999
+
1000
+ var assetStatus_provider = /*#__PURE__*/Object.freeze({
1001
+ __proto__: null,
1002
+ AXMAssetManagementAssetStatusProvider: AXMAssetManagementAssetStatusProvider
1003
+ });
1004
+
1005
+ const rentalHistorySharedCreateFields = [
1006
+ 'rentalDirection',
1007
+ 'createdDate',
1008
+ 'startDate',
1009
+ 'monthlyRent',
1010
+ 'expectedReturnDate',
1011
+ 'actualReturnDate',
1012
+ 'status',
1013
+ 'description',
1014
+ ];
1015
+ //#endregion
1016
+ //#region ---- Helpers ----
1017
+ function buildRentCreateOptions(direction) {
1018
+ const isRentFrom = direction === 'rentFrom';
1019
+ return {
1020
+ includeProperties: [
1021
+ ...rentalHistorySharedCreateFields,
1022
+ isRentFrom ? 'rentedFromId' : 'rentedToId',
1023
+ ],
1024
+ excludeProperties: [isRentFrom ? 'rentedToId' : 'rentedFromId'],
1025
+ decoration: {
1026
+ header: {
1027
+ title: isRentFrom
1028
+ ? '@asset-management:assetRentalHistories.entities.assetRentalHistory.actions.rent-from.dialog-title'
1029
+ : '@asset-management:assetRentalHistories.entities.assetRentalHistory.actions.rent-to.dialog-title',
1030
+ },
1031
+ },
1032
+ process: {
1033
+ redirect: false,
1034
+ canCreateNewOne: true,
1035
+ },
1036
+ };
1037
+ }
1038
+ //#endregion
1039
+ //#region ---- Commands ----
1040
+ class AXMCreateAssetRentalHistoryRentCommandBase {
1041
+ constructor() {
1042
+ this.commandService = inject(AXPCommandService);
1043
+ }
1044
+ async execute(input) {
1045
+ const seedData = this.resolveSeedData(input);
1046
+ const createOptions = buildRentCreateOptions(this.rentalDirection);
1047
+ const result = await this.commandService.execute('Entity:Create', {
1048
+ entity: RootConfig.entities.assetRentalHistory.source,
1049
+ entityInfo: {
1050
+ name: RootConfig.entities.assetRentalHistory.name,
1051
+ module: RootConfig.module.name,
1052
+ title: RootConfig.entities.assetRentalHistory.title,
1053
+ },
1054
+ data: seedData,
1055
+ options: createOptions,
1056
+ });
1057
+ return result ?? { success: false };
1058
+ }
1059
+ resolveSeedData(input) {
1060
+ const ctx = input;
1061
+ const options = (input.options ?? ctx.options ?? {});
1062
+ const process = (options['process'] ?? {});
1063
+ const processData = process['data'];
1064
+ const contextData = ctx.data ?? input.data ?? {};
1065
+ return merge({}, typeof contextData === 'object' &&
1066
+ contextData !== null &&
1067
+ !Array.isArray(contextData)
1068
+ ? contextData
1069
+ : {}, typeof processData === 'object' &&
1070
+ processData !== null &&
1071
+ !Array.isArray(processData)
1072
+ ? processData
1073
+ : {}, { rentalDirection: this.rentalDirection });
1074
+ }
1075
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentCommandBase, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1076
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentCommandBase, providedIn: 'root' }); }
1077
+ }
1078
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentCommandBase, decorators: [{
1079
+ type: Injectable,
1080
+ args: [{ providedIn: 'root' }]
1081
+ }] });
1082
+ class AXMCreateAssetRentalHistoryRentFromCommand extends AXMCreateAssetRentalHistoryRentCommandBase {
1083
+ constructor() {
1084
+ super(...arguments);
1085
+ this.rentalDirection = 'rentFrom';
1086
+ }
1087
+ static { this.commandKey = AXMAssetManagementCommandKeys.AssetRentalHistory.RentFrom; }
1088
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentFromCommand, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1089
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentFromCommand, providedIn: 'root' }); }
1090
+ }
1091
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentFromCommand, decorators: [{
1092
+ type: Injectable,
1093
+ args: [{ providedIn: 'root' }]
1094
+ }] });
1095
+ class AXMCreateAssetRentalHistoryRentToCommand extends AXMCreateAssetRentalHistoryRentCommandBase {
1096
+ constructor() {
1097
+ super(...arguments);
1098
+ this.rentalDirection = 'rentTo';
1099
+ }
1100
+ static { this.commandKey = AXMAssetManagementCommandKeys.AssetRentalHistory.RentTo; }
1101
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentToCommand, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1102
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentToCommand, providedIn: 'root' }); }
1103
+ }
1104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCreateAssetRentalHistoryRentToCommand, decorators: [{
1105
+ type: Injectable,
1106
+ args: [{ providedIn: 'root' }]
1107
+ }] });
1108
+
1109
+ var createAssetRentalHistoryRent_commands = /*#__PURE__*/Object.freeze({
1110
+ __proto__: null,
1111
+ AXMCreateAssetRentalHistoryRentFromCommand: AXMCreateAssetRentalHistoryRentFromCommand,
1112
+ AXMCreateAssetRentalHistoryRentToCommand: AXMCreateAssetRentalHistoryRentToCommand
1113
+ });
1114
+
1115
+ function normalizeAssetTypeBuilderLocalizedField(value, fallback) {
1116
+ if (value == null || value === '') {
1117
+ return fallback;
1118
+ }
1119
+ if (typeof value === 'string') {
1120
+ const trimmed = value.trim();
1121
+ return trimmed || fallback;
1122
+ }
1123
+ if (typeof value === 'object' && !Array.isArray(value)) {
1124
+ const record = value;
1125
+ const anyLocaleText = Object.values(record).some((v) => typeof v === 'string' && String(v).trim() !== '');
1126
+ if (anyLocaleText) {
1127
+ return value;
1128
+ }
1129
+ }
1130
+ return fallback;
1131
+ }
1132
+ function createAssetTypeSectionBuilderDefaultValue(assetTypeId) {
1133
+ return {
1134
+ sections: [
1135
+ {
1136
+ id: AXPDataGenerator.uuid(),
1137
+ code: 1,
1138
+ title: 'New Section',
1139
+ assetTypeId: assetTypeId ?? '',
1140
+ description: '',
1141
+ items: [],
1142
+ },
1143
+ ],
1144
+ };
1145
+ }
1146
+ function normalizeAssetTypeSectionBuilderValue(value, assetTypeId) {
1147
+ if (!value || typeof value !== 'object') {
1148
+ return createAssetTypeSectionBuilderDefaultValue(assetTypeId);
1149
+ }
1150
+ const raw = value;
1151
+ if (!Array.isArray(raw.sections) || raw.sections.length === 0) {
1152
+ return createAssetTypeSectionBuilderDefaultValue(assetTypeId);
1153
+ }
1154
+ return {
1155
+ sections: raw.sections.map((section, sectionIndex) => {
1156
+ const sectionData = (section ?? {});
1157
+ const id = typeof sectionData.id === 'string' && sectionData.id ? sectionData.id : AXPDataGenerator.uuid();
1158
+ const sectionItems = Array.isArray(sectionData.items) ? sectionData.items : [];
1159
+ return {
1160
+ id,
1161
+ code: typeof sectionData.code === 'number' ? sectionData.code : sectionIndex + 1,
1162
+ title: normalizeAssetTypeBuilderLocalizedField(sectionData.title, `Section ${sectionIndex + 1}`),
1163
+ assetTypeId: typeof sectionData.assetTypeId === 'string' && sectionData.assetTypeId
1164
+ ? sectionData.assetTypeId
1165
+ : assetTypeId ?? '',
1166
+ description: normalizeAssetTypeBuilderLocalizedField(sectionData.description, ''),
1167
+ items: sectionItems.map((item, itemIndex) => {
1168
+ const itemData = (item ?? {});
1169
+ const rawAt = itemData.assetType;
1170
+ const assetTypeIdFromRef = rawAt &&
1171
+ typeof rawAt === 'object' &&
1172
+ typeof rawAt.id === 'string' &&
1173
+ String(rawAt.id).trim()
1174
+ ? String(rawAt.id).trim()
1175
+ : '';
1176
+ const normalizedAssetTypeId = typeof itemData.assetTypeId === 'string' && itemData.assetTypeId.trim()
1177
+ ? itemData.assetTypeId.trim()
1178
+ : assetTypeIdFromRef || (assetTypeId ?? '');
1179
+ const assetTypeRef = rawAt && typeof rawAt === 'object'
1180
+ ? {
1181
+ id: typeof rawAt.id === 'string' && String(rawAt.id).trim()
1182
+ ? String(rawAt.id).trim()
1183
+ : normalizedAssetTypeId,
1184
+ name: normalizeAssetTypeBuilderLocalizedField(rawAt.name, ''),
1185
+ }
1186
+ : {
1187
+ id: normalizedAssetTypeId,
1188
+ name: '',
1189
+ };
1190
+ return {
1191
+ id: typeof itemData.id === 'string' && itemData.id ? itemData.id : AXPDataGenerator.uuid(),
1192
+ assetTypeSectionId: typeof itemData.assetTypeSectionId === 'string' && itemData.assetTypeSectionId
1193
+ ? itemData.assetTypeSectionId
1194
+ : id,
1195
+ assetTypeSectionComponentId: typeof itemData.assetTypeSectionComponentId === 'string' && itemData.assetTypeSectionComponentId
1196
+ ? itemData.assetTypeSectionComponentId
1197
+ : undefined,
1198
+ assetTypeId: normalizedAssetTypeId,
1199
+ assetType: assetTypeRef,
1200
+ assetTypeSection: itemData.assetTypeSection,
1201
+ roleName: normalizeAssetTypeBuilderLocalizedField(itemData.roleName, ''),
1202
+ count: typeof itemData.count === 'number' ? itemData.count : 1,
1203
+ hasMaintenance: itemData.hasMaintenance === true,
1204
+ assetId: typeof itemData.assetId === 'string' && itemData.assetId ? itemData.assetId : undefined,
1205
+ asset: itemData.asset && typeof itemData.asset === 'object'
1206
+ ? {
1207
+ id: typeof itemData.asset.id === 'string'
1208
+ ? (itemData.asset.id ?? '')
1209
+ : '',
1210
+ code: typeof itemData.asset.code === 'string'
1211
+ ? itemData.asset.code
1212
+ : undefined,
1213
+ title: normalizeAssetTypeBuilderLocalizedField(itemData.asset.title, ''),
1214
+ }
1215
+ : undefined,
1216
+ };
1217
+ }),
1218
+ };
1219
+ }),
1220
+ };
1221
+ }
1222
+
1223
+ class AXMAssetTypeSectionBuilderComponent {
1224
+ constructor() {
1225
+ this.value = input(null, /* @ts-ignore */
1226
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
1227
+ this.assetTypeId = input(undefined, /* @ts-ignore */
1228
+ ...(ngDevMode ? [{ debugName: "assetTypeId" }] : /* istanbul ignore next */ []));
1229
+ this.options = input({}, /* @ts-ignore */
1230
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
1231
+ this.valueChange = output();
1232
+ this.standardRef = viewChild(AXPStandardSectionItemsBuilderComponent, /* @ts-ignore */
1233
+ ...(ngDevMode ? [{ debugName: "standardRef" }] : /* istanbul ignore next */ []));
1234
+ this.layoutBuilder = inject(AXPLayoutBuilderService);
1235
+ this.translationService = inject(AXTranslationService);
1236
+ this.disabledSectionPrompt = false;
1237
+ this.disabledAddSectionPrompt = async () => null;
1238
+ this.builderValue = signal({ sections: [] }, /* @ts-ignore */
1239
+ ...(ngDevMode ? [{ debugName: "builderValue" }] : /* istanbul ignore next */ []));
1240
+ this.standardConfig = computed(() => ({
1241
+ mapItemToView: (item, _section) => this.mapItemToView(item),
1242
+ promptAddSection: this.allowAddSection() ? (value) => this.promptAddSection(value) : this.disabledAddSectionPrompt,
1243
+ promptEditSection: this.allowEditSection()
1244
+ ? (section, value) => this.promptEditSection(section, value)
1245
+ : this.disabledSectionPrompt,
1246
+ promptAddItems: this.allowAddItems() ? (sectionId, value) => this.promptAddItems(sectionId, value) : undefined,
1247
+ promptEditItem: (item, sectionId, value) => this.linkAssetMode()
1248
+ ? this.promptEditLinkedAssetItem(item, sectionId, value)
1249
+ : this.promptEditItem(item, sectionId, value),
1250
+ confirmRemoveSection: this.linkAssetMode() ? async () => false : undefined,
1251
+ confirmRemoveItem: this.linkAssetMode()
1252
+ ? (item, sectionId) => this.confirmRemoveLinkedAssetItem(item, sectionId)
1253
+ : undefined,
1254
+ showSectionTechnicalName: false,
1255
+ allowReorderSections: this.allowReorderSections(),
1256
+ minSectionCount: this.allowAddSection() ? 1 : Number.MAX_SAFE_INTEGER,
1257
+ texts: {
1258
+ addSection: '@asset-management:assetTypeSections.entities.assetTypeSection.actions.add-section.title',
1259
+ addItem: '@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.actions.add-item.title',
1260
+ },
1261
+ }), /* @ts-ignore */
1262
+ ...(ngDevMode ? [{ debugName: "standardConfig" }] : /* istanbul ignore next */ []));
1263
+ this.hideHeaderActions = computed(() => this.options()['hideHeaderActions'] === true, /* @ts-ignore */
1264
+ ...(ngDevMode ? [{ debugName: "hideHeaderActions" }] : /* istanbul ignore next */ []));
1265
+ this.allowAddSection = computed(() => this.options()['allowAddSection'] !== false, /* @ts-ignore */
1266
+ ...(ngDevMode ? [{ debugName: "allowAddSection" }] : /* istanbul ignore next */ []));
1267
+ this.allowEditSection = computed(() => {
1268
+ if (this.linkAssetMode()) {
1269
+ return false;
1270
+ }
1271
+ return this.options()['allowEditSection'] !== false;
1272
+ }, /* @ts-ignore */
1273
+ ...(ngDevMode ? [{ debugName: "allowEditSection" }] : /* istanbul ignore next */ []));
1274
+ this.allowAddItems = computed(() => this.options()['allowAddItems'] !== false, /* @ts-ignore */
1275
+ ...(ngDevMode ? [{ debugName: "allowAddItems" }] : /* istanbul ignore next */ []));
1276
+ this.allowReorderSections = computed(() => {
1277
+ const option = this.options()['allowReorderSections'];
1278
+ return typeof option === 'boolean' ? option : true;
1279
+ }, /* @ts-ignore */
1280
+ ...(ngDevMode ? [{ debugName: "allowReorderSections" }] : /* istanbul ignore next */ []));
1281
+ this.readonly = computed(() => this.options()['readonly'] === true, /* @ts-ignore */
1282
+ ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
1283
+ this.linkAssetMode = computed(() => this.options()['linkAssetMode'] === true, /* @ts-ignore */
1284
+ ...(ngDevMode ? [{ debugName: "linkAssetMode" }] : /* istanbul ignore next */ []));
1285
+ this.#syncValueToBuilder = effect(() => {
1286
+ const raw = this.value();
1287
+ // In link mode an empty value means "template not loaded yet" — do not invent a default section.
1288
+ if (this.linkAssetMode() && (!raw || !Array.isArray(raw.sections) || raw.sections.length === 0)) {
1289
+ this.builderValue.set({ sections: [] });
1290
+ return;
1291
+ }
1292
+ const normalized = normalizeAssetTypeSectionBuilderValue(raw, this.assetTypeId());
1293
+ this.builderValue.set(this.toBuilderValue(normalized));
1294
+ }, /* @ts-ignore */
1295
+ ...(ngDevMode ? [{ debugName: "#syncValueToBuilder" }] : /* istanbul ignore next */ []));
1296
+ }
1297
+ #syncValueToBuilder;
1298
+ async addSection() {
1299
+ await this.standardRef()?.addSection();
1300
+ }
1301
+ /** Aligns section-items baseline to persisted value after save. */
1302
+ syncAfterSave(value) {
1303
+ const normalized = normalizeAssetTypeSectionBuilderValue(value, this.assetTypeId());
1304
+ this.builderValue.set(this.toBuilderValue(normalized));
1305
+ queueMicrotask(() => this.standardRef()?.markClean());
1306
+ }
1307
+ /** Re-applies the current `[value]` input and clears builder dirty state after discard. */
1308
+ resetAfterDiscard() {
1309
+ const normalized = normalizeAssetTypeSectionBuilderValue(this.value(), this.assetTypeId());
1310
+ this.builderValue.set(this.toBuilderValue(normalized));
1311
+ queueMicrotask(() => this.standardRef()?.markClean());
1312
+ }
1313
+ onBuilderValueChange(next) {
1314
+ this.builderValue.set(next);
1315
+ const value = this.fromBuilderValue(next);
1316
+ this.valueChange.emit(value);
1317
+ }
1318
+ async promptAddSection(value) {
1319
+ const seed = {
1320
+ code: this.getNextSectionCode(value),
1321
+ title: '',
1322
+ description: '',
1323
+ };
1324
+ const dialogValue = await this.promptSectionForm('create', seed, value);
1325
+ if (!dialogValue)
1326
+ return null;
1327
+ const sectionId = AXPDataGenerator.uuid();
1328
+ return {
1329
+ id: sectionId,
1330
+ name: sectionId,
1331
+ code: dialogValue.code,
1332
+ title: dialogValue.title,
1333
+ description: dialogValue.description,
1334
+ };
1335
+ }
1336
+ async promptEditSection(section, value) {
1337
+ const seed = {
1338
+ code: Number(section['code'] ?? 0) || this.getNextSectionCode(value),
1339
+ title: this.resolveLocalizedTextForDialog(section['title']),
1340
+ description: this.resolveLocalizedTextForDialog(section['description']),
1341
+ };
1342
+ const dialogValue = await this.promptSectionForm('edit', seed, value, section.id);
1343
+ if (!dialogValue)
1344
+ return null;
1345
+ return {
1346
+ ...section,
1347
+ code: dialogValue.code,
1348
+ title: dialogValue.title,
1349
+ description: dialogValue.description,
1350
+ };
1351
+ }
1352
+ async promptSectionForm(mode, seed, value, currentSectionId) {
1353
+ const title = mode === 'create'
1354
+ ? (await this.translationService.translateAsync('@asset-management:assetTypeSections.entities.assetTypeSection.actions.add-section.title')) || 'Add Section'
1355
+ : (await this.translationService.translateAsync('@general:actions.edit.title')) || 'Edit';
1356
+ const result = await this.layoutBuilder
1357
+ .create()
1358
+ .dialog((dialog) => {
1359
+ dialog
1360
+ .setTitle(title)
1361
+ .setSize('sm')
1362
+ .setCloseButton(true)
1363
+ .setContext({ ...seed })
1364
+ .content((layout) => {
1365
+ layout.mode('edit');
1366
+ layout.dynamicForm(this.buildSectionFormDefinition());
1367
+ })
1368
+ .setActions((actions) => {
1369
+ actions.cancel('@general:actions.cancel.title').submit('@general:actions.save.title');
1370
+ })
1371
+ .onAction((dialogRef) => {
1372
+ if (dialogRef.action() === 'cancel') {
1373
+ return { success: false };
1374
+ }
1375
+ const context = dialogRef.context();
1376
+ const code = Number(context.code ?? 0);
1377
+ const titleValue = String(context.title ?? '').trim();
1378
+ const description = String(context.description ?? '');
1379
+ if (!Number.isFinite(code) || code <= 0 || !titleValue) {
1380
+ return { success: false };
1381
+ }
1382
+ if (this.isDuplicateSectionCode(value, code, currentSectionId)) {
1383
+ return { success: false };
1384
+ }
1385
+ return { success: true, kind: 'object', value: {
1386
+ code,
1387
+ title: titleValue,
1388
+ description,
1389
+ },
1390
+ };
1391
+ });
1392
+ })
1393
+ .show();
1394
+ return result?.success && result.value ? result.value : null;
1395
+ }
1396
+ isDuplicateSectionCode(value, code, currentSectionId) {
1397
+ return value.sections.some((section) => {
1398
+ if (currentSectionId && section.id === currentSectionId)
1399
+ return false;
1400
+ const sectionCode = Number(section['code'] ?? 0);
1401
+ return Number.isFinite(sectionCode) && sectionCode === code;
1402
+ });
1403
+ }
1404
+ getNextSectionCode(value) {
1405
+ const maxCode = value.sections.reduce((max, section) => {
1406
+ const sectionCode = Number(section['code'] ?? 0);
1407
+ if (!Number.isFinite(sectionCode))
1408
+ return max;
1409
+ return Math.max(max, sectionCode);
1410
+ }, 0);
1411
+ return maxCode + 1;
1412
+ }
1413
+ mapItemToView(item) {
1414
+ const roleName = this.resolveLocalizedTextForDialog(item['roleName'] ?? '');
1415
+ const assetTypeName = this.resolveLocalizedTextForDialog(item['assetType']?.name ?? '');
1416
+ const count = Number(item['count'] ?? 0);
1417
+ const hasMaintenance = item['hasMaintenance'] === true;
1418
+ const linkedAsset = item['asset'];
1419
+ const linkedAssetCode = typeof linkedAsset?.code === 'string' ? linkedAsset.code : '';
1420
+ const linkedAssetTitle = this.resolveLocalizedTextForDialog(linkedAsset?.title ?? '');
1421
+ if (this.linkAssetMode()) {
1422
+ const hasLinkedAsset = !!item['assetId'];
1423
+ const linkedAssetName = linkedAssetTitle || '@asset-management:assets.entities.asset.components.asset-component.no-link';
1424
+ const linkedAssetDisplay = linkedAssetCode ? `${linkedAssetName} (${linkedAssetCode})` : linkedAssetName;
1425
+ return {
1426
+ icon: hasLinkedAsset ? 'fa-light fa-link' : 'fa-light fa-link-slash',
1427
+ iconTone: hasLinkedAsset ? 'easy' : 'hard',
1428
+ title: roleName,
1429
+ name: linkedAssetDisplay,
1430
+ badges: [
1431
+ {
1432
+ text: hasLinkedAsset
1433
+ ? '@asset-management:assets.entities.asset.components.asset-component.assigned'
1434
+ : '@asset-management:assets.entities.asset.components.asset-component.unassigned',
1435
+ variant: hasLinkedAsset ? 'success' : 'warning',
1436
+ },
1437
+ ...(hasLinkedAsset && linkedAssetTitle
1438
+ ? [
1439
+ {
1440
+ text: linkedAssetTitle,
1441
+ variant: 'neutral',
1442
+ },
1443
+ ]
1444
+ : []),
1445
+ {
1446
+ text: assetTypeName,
1447
+ variant: 'neutral',
1448
+ },
1449
+ ],
1450
+ };
1451
+ }
1452
+ return {
1453
+ icon: 'fa-light fa-cube',
1454
+ title: roleName,
1455
+ name: assetTypeName,
1456
+ badges: [
1457
+ {
1458
+ text: `x${count}`,
1459
+ variant: 'neutral',
1460
+ },
1461
+ ...(hasMaintenance
1462
+ ? [
1463
+ {
1464
+ text: '@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.fields.hasMaintenance.title',
1465
+ variant: 'success',
1466
+ },
1467
+ ]
1468
+ : []),
1469
+ ],
1470
+ };
1471
+ }
1472
+ async promptAddItems(sectionId, value) {
1473
+ const section = value.sections.find((item) => item.id === sectionId);
1474
+ if (!section)
1475
+ return null;
1476
+ const itemValue = await this.promptItemForm('create');
1477
+ if (!itemValue)
1478
+ return null;
1479
+ const nextOrder = section.items.length;
1480
+ const id = AXPDataGenerator.uuid();
1481
+ return [
1482
+ {
1483
+ id,
1484
+ order: nextOrder,
1485
+ name: itemValue.assetType.name,
1486
+ roleName: itemValue.roleName,
1487
+ count: itemValue.count,
1488
+ hasMaintenance: itemValue.hasMaintenance,
1489
+ assetType: itemValue.assetType,
1490
+ assetTypeSectionId: section.id,
1491
+ assetTypeId: itemValue.assetTypeId || this.assetTypeId() || '',
1492
+ },
1493
+ ];
1494
+ }
1495
+ async promptEditItem(item, _sectionId, _value) {
1496
+ const dialogValue = await this.promptItemForm('edit', {
1497
+ assetTypeId: String(item['assetTypeId'] ?? this.assetTypeId() ?? ''),
1498
+ assetType: item['assetType'] ?? {
1499
+ id: String(item['assetTypeId'] ?? this.assetTypeId() ?? ''),
1500
+ name: '',
1501
+ },
1502
+ roleName: this.resolveLocalizedTextForDialog(item['roleName'] ?? item['name'] ?? ''),
1503
+ count: Number(item['count'] ?? 1),
1504
+ hasMaintenance: item['hasMaintenance'] === true,
1505
+ });
1506
+ if (!dialogValue)
1507
+ return null;
1508
+ return {
1509
+ ...item,
1510
+ name: dialogValue.assetType.name,
1511
+ roleName: dialogValue.roleName,
1512
+ count: dialogValue.count,
1513
+ hasMaintenance: dialogValue.hasMaintenance,
1514
+ assetTypeId: dialogValue.assetTypeId,
1515
+ assetType: dialogValue.assetType,
1516
+ };
1517
+ }
1518
+ async promptEditLinkedAssetItem(item, _sectionId, _value) {
1519
+ const assetTypeId = this.resolveLinkedItemAssetTypeId(item);
1520
+ const seed = {
1521
+ assetId: String(item['assetId'] ?? ''),
1522
+ assetTypeId,
1523
+ asset: item['asset'] ?? {
1524
+ id: '',
1525
+ code: '',
1526
+ title: '',
1527
+ },
1528
+ };
1529
+ const result = await this.promptLinkAssetForm(seed);
1530
+ if (!result) {
1531
+ return null;
1532
+ }
1533
+ return {
1534
+ ...item,
1535
+ assetId: result.assetId || undefined,
1536
+ asset: result.assetId ? result.asset : undefined,
1537
+ };
1538
+ }
1539
+ resolveLinkedItemAssetTypeId(item) {
1540
+ const fromField = typeof item['assetTypeId'] === 'string' ? item['assetTypeId'].trim() : '';
1541
+ if (fromField) {
1542
+ return fromField;
1543
+ }
1544
+ const nested = item['assetType'];
1545
+ if (nested && typeof nested.id === 'string' && nested.id.trim()) {
1546
+ return nested.id.trim();
1547
+ }
1548
+ return '';
1549
+ }
1550
+ async promptLinkAssetForm(seed) {
1551
+ const title = (await this.translationService.translateAsync('@asset-management:assets.entities.asset.components.asset-component.actions.edit.title')) || 'Edit Component Asset';
1552
+ const result = await this.layoutBuilder
1553
+ .create()
1554
+ .dialog((dialog) => {
1555
+ dialog
1556
+ .setTitle(title)
1557
+ .setSize('sm')
1558
+ .setCloseButton(true)
1559
+ .setContext({ ...seed })
1560
+ .content((layout) => {
1561
+ layout.mode('edit');
1562
+ layout.dynamicForm(this.buildLinkAssetFormDefinition(seed.assetTypeId));
1563
+ })
1564
+ .setActions((actions) => {
1565
+ actions.cancel('@general:actions.cancel.title').submit('@general:actions.save.title');
1566
+ })
1567
+ .onAction((dialogRef) => {
1568
+ if (dialogRef.action() === 'cancel') {
1569
+ return { success: false };
1570
+ }
1571
+ const context = dialogRef.context();
1572
+ const assetId = String(context.assetId ?? '').trim();
1573
+ const asset = context.asset ?? { id: assetId, code: '', title: '' };
1574
+ return { success: true, kind: 'object', value: {
1575
+ assetId,
1576
+ assetTypeId: String(context.assetTypeId ?? seed.assetTypeId ?? ''),
1577
+ asset: {
1578
+ id: String(asset.id ?? assetId),
1579
+ code: String(asset.code ?? ''),
1580
+ title: String(asset.title ?? ''),
1581
+ },
1582
+ },
1583
+ };
1584
+ });
1585
+ })
1586
+ .show();
1587
+ return result?.success && result.value ? result.value : null;
1588
+ }
1589
+ async confirmRemoveLinkedAssetItem(item, sectionId) {
1590
+ const hasLinkedAsset = typeof item['assetId'] === 'string' && item['assetId'].length > 0;
1591
+ if (!hasLinkedAsset) {
1592
+ return false;
1593
+ }
1594
+ const deleteTitle = (await this.translationService.translateAsync('@asset-management:assets.entities.asset.components.asset-component.actions.delete.title')) || 'Remove Component Asset';
1595
+ const linkedAsset = item['asset'];
1596
+ const linkedAssetTitle = this.resolveLocalizedTextForDialog(linkedAsset?.title ?? '');
1597
+ const linkedAssetCode = typeof linkedAsset?.code === 'string' ? linkedAsset.code : '';
1598
+ const assetDisplay = linkedAssetTitle || linkedAssetCode || String(item['assetId'] ?? '');
1599
+ const assetLabel = `${assetDisplay}${linkedAssetCode && linkedAssetTitle ? ` (${linkedAssetCode})` : ''}`;
1600
+ const deleteResult = await this.layoutBuilder
1601
+ .create()
1602
+ .dialog((dialog) => {
1603
+ dialog
1604
+ .setTitle(deleteTitle)
1605
+ .setMessage('@general:workflow.confirm-delete')
1606
+ .setSize('sm')
1607
+ .setCloseButton(true)
1608
+ .setContext({ assetLabel })
1609
+ .content((layout) => {
1610
+ layout.mode('edit');
1611
+ layout.dynamicForm(this.buildRemoveLinkedAssetFormDefinition());
1612
+ })
1613
+ .setActions((actions) => {
1614
+ actions.cancel('@general:actions.cancel.title').custom({
1615
+ title: '@general:actions.delete.title',
1616
+ color: 'danger',
1617
+ command: {
1618
+ name: 'delete',
1619
+ options: {
1620
+ validate: false,
1621
+ },
1622
+ },
1623
+ });
1624
+ })
1625
+ .onAction((dialogRef) => {
1626
+ if (dialogRef.action() !== 'delete') {
1627
+ return { success: false };
1628
+ }
1629
+ return { success: true, kind: 'object', data: undefined };
1630
+ });
1631
+ })
1632
+ .show();
1633
+ if (deleteResult?.success === true) {
1634
+ this.unlinkLinkedAssetItem(item.id, sectionId);
1635
+ }
1636
+ // Prevent structural row removal; only unlink asset assignment.
1637
+ return false;
1638
+ }
1639
+ buildRemoveLinkedAssetFormDefinition() {
1640
+ const group = {
1641
+ name: 'unlink-asset',
1642
+ title: '@asset-management:assets.entities.asset.components.asset-component.title',
1643
+ parameters: [
1644
+ {
1645
+ path: 'assetLabel',
1646
+ title: '@asset-management:assets.entities.asset.title',
1647
+ widget: {
1648
+ path: 'assetLabel',
1649
+ type: AXPWidgetsCatalog.text,
1650
+ options: {
1651
+ disabled: true,
1652
+ },
1653
+ },
1654
+ },
1655
+ ],
1656
+ };
1657
+ return { groups: [group] };
1658
+ }
1659
+ unlinkLinkedAssetItem(itemId, sectionId) {
1660
+ const nextValue = {
1661
+ sections: this.builderValue().sections.map((section) => {
1662
+ if (section.id !== sectionId) {
1663
+ return section;
1664
+ }
1665
+ return {
1666
+ ...section,
1667
+ items: section.items.map((item) => {
1668
+ if (item.id !== itemId) {
1669
+ return item;
1670
+ }
1671
+ return {
1672
+ ...item,
1673
+ assetId: undefined,
1674
+ asset: undefined,
1675
+ };
1676
+ }),
1677
+ };
1678
+ }),
1679
+ };
1680
+ this.onBuilderValueChange(nextValue);
1681
+ }
1682
+ async promptItemForm(mode, seed) {
1683
+ const defaultSeed = seed ?? {
1684
+ assetTypeId: '',
1685
+ assetType: {
1686
+ id: '',
1687
+ name: '',
1688
+ },
1689
+ roleName: '',
1690
+ count: 1,
1691
+ hasMaintenance: false,
1692
+ };
1693
+ const title = mode === 'create'
1694
+ ? (await this.translationService.translateAsync('@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.actions.add-item.title')) || 'Add Component'
1695
+ : (await this.translationService.translateAsync('@general:actions.edit.title')) || 'Edit';
1696
+ const formDefinition = this.buildItemFormDefinition();
1697
+ const result = await this.layoutBuilder
1698
+ .create()
1699
+ .dialog((dialog) => {
1700
+ dialog
1701
+ .setTitle(title)
1702
+ .setSize('sm')
1703
+ .setCloseButton(true)
1704
+ .setContext({ ...defaultSeed })
1705
+ .content((layout) => {
1706
+ layout.mode('edit');
1707
+ layout.dynamicForm(formDefinition);
1708
+ })
1709
+ .setActions((actions) => {
1710
+ actions.cancel('@general:actions.cancel.title').submit('@general:actions.save.title');
1711
+ })
1712
+ .onAction((dialogRef) => {
1713
+ if (dialogRef.action() === 'cancel') {
1714
+ return { success: false };
1715
+ }
1716
+ const context = dialogRef.context();
1717
+ const assetTypeId = String(context.assetTypeId ?? '').trim();
1718
+ const assetType = context.assetType;
1719
+ const roleName = String(context.roleName ?? '').trim();
1720
+ const count = Number(context.count ?? 0);
1721
+ const hasMaintenance = context.hasMaintenance === true;
1722
+ if (!assetTypeId) {
1723
+ return { success: false };
1724
+ }
1725
+ return { success: true, kind: 'object', value: {
1726
+ assetTypeId,
1727
+ assetType: {
1728
+ id: String(assetType?.id ?? assetTypeId),
1729
+ name: String(assetType?.name ?? ''),
1730
+ },
1731
+ roleName,
1732
+ count: Number.isFinite(count) && count > 0 ? count : 1,
1733
+ hasMaintenance,
1734
+ },
1735
+ };
1736
+ });
1737
+ })
1738
+ .show();
1739
+ return result?.success && result.value ? result.value : null;
1740
+ }
1741
+ buildItemFormDefinition() {
1742
+ const excludedAssetTypeId = this.assetTypeId();
1743
+ const group = {
1744
+ name: 'component',
1745
+ title: '@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.title',
1746
+ parameters: [
1747
+ {
1748
+ path: 'assetTypeId',
1749
+ title: '@asset-management:assetTypes.entities.assetType.title',
1750
+ widget: {
1751
+ path: 'assetTypeId',
1752
+ type: AXPWidgetsCatalog.lookup,
1753
+ options: {
1754
+ entity: `${RootConfig.module.name}.${RootConfig.entities.assetType.name}`,
1755
+ textField: 'title',
1756
+ valueField: 'id',
1757
+ look: 'select',
1758
+ multiple: false,
1759
+ expose: [
1760
+ { source: 'id', target: 'assetType.id' },
1761
+ { source: 'title', target: 'assetType.name' },
1762
+ { source: 'hasMaintenance', target: 'hasMaintenance' },
1763
+ ],
1764
+ ...(excludedAssetTypeId
1765
+ ? {
1766
+ filter: { field: 'id', operator: { type: 'notEqual' }, value: excludedAssetTypeId },
1767
+ }
1768
+ : {}),
1769
+ validations: [{ rule: 'required' }],
1770
+ },
1771
+ },
1772
+ },
1773
+ this.toFieldDefinition('hasMaintenance', '@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.fields.hasMaintenance.title', AXPWidgetsCatalog.toggle),
1774
+ this.toFieldDefinition('count', '@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.fields.count.title', AXPWidgetsCatalog.number, [{ rule: 'required' }]),
1775
+ this.toFieldDefinition('roleName', '@asset-management:assetTypeSectionComponents.entities.assetTypeSectionComponent.fields.roleName.title', AXPWidgetsCatalog.largeText),
1776
+ ],
1777
+ };
1778
+ return { groups: [group] };
1779
+ }
1780
+ buildSectionFormDefinition() {
1781
+ const group = {
1782
+ name: 'section',
1783
+ title: '@asset-management:assetTypeSections.entities.assetTypeSection.title',
1784
+ parameters: [
1785
+ this.toFieldDefinition('code', '@asset-management:assetTypeSections.entities.assetTypeSection.fields.code.title', AXPWidgetsCatalog.number, [{ rule: 'required' }]),
1786
+ this.toFieldDefinition('title', '@asset-management:assetTypeSections.entities.assetTypeSection.fields.title.title', AXPWidgetsCatalog.text, [{ rule: 'required' }]),
1787
+ this.toFieldDefinition('description', '@asset-management:assetTypeSections.entities.assetTypeSection.fields.description.title', AXPWidgetsCatalog.largeText),
1788
+ ],
1789
+ };
1790
+ return { groups: [group] };
1791
+ }
1792
+ buildLinkAssetFormDefinition(requiredAssetTypeId) {
1793
+ const currentAssetId = this.options()['mainAssetId'];
1794
+ const assetTypeFilterValue = typeof requiredAssetTypeId === 'string' && requiredAssetTypeId.trim()
1795
+ ? requiredAssetTypeId.trim()
1796
+ : "{{ context.eval('assetTypeId') }}";
1797
+ const filters = [
1798
+ ...(typeof currentAssetId === 'string' && currentAssetId
1799
+ ? [{ field: 'id', operator: { type: 'notEqual' }, value: currentAssetId }]
1800
+ : []),
1801
+ {
1802
+ field: 'assetTypeId',
1803
+ operator: { type: 'equal' },
1804
+ value: assetTypeFilterValue,
1805
+ },
1806
+ ];
1807
+ const group = {
1808
+ name: 'asset-link',
1809
+ title: '@asset-management:assets.entities.asset.title',
1810
+ parameters: [
1811
+ {
1812
+ path: 'assetId',
1813
+ title: '@asset-management:assets.entities.asset.title',
1814
+ widget: {
1815
+ path: 'assetId',
1816
+ type: AXPWidgetsCatalog.lookup,
1817
+ options: {
1818
+ entity: `${RootConfig.module.name}.${RootConfig.entities.asset.name}`,
1819
+ textField: 'title',
1820
+ valueField: 'id',
1821
+ look: 'lookup',
1822
+ allowSearch: true,
1823
+ hasClearButton: true,
1824
+ columns: ['code', 'title', 'assetTypeId', 'statusId', 'locationId'],
1825
+ expose: [
1826
+ { source: 'id', target: 'asset.id' },
1827
+ { source: 'code', target: 'asset.code' },
1828
+ { source: 'title', target: 'asset.title' },
1829
+ ],
1830
+ filter: filters.length === 1 ? filters[0] : { logic: 'and', filters },
1831
+ validations: [{ rule: 'required' }],
1832
+ },
1833
+ },
1834
+ },
1835
+ ],
1836
+ };
1837
+ return { groups: [group] };
1838
+ }
1839
+ toFieldDefinition(path, title, widgetType, validations = []) {
1840
+ return {
1841
+ path,
1842
+ title,
1843
+ widget: {
1844
+ path,
1845
+ type: widgetType,
1846
+ ...(validations.length > 0 ? { options: { validations } } : {}),
1847
+ },
1848
+ };
1849
+ }
1850
+ toBuilderValue(value) {
1851
+ return {
1852
+ sections: value.sections.map((section) => ({
1853
+ id: section.id,
1854
+ order: section.code - 1,
1855
+ name: section.id,
1856
+ code: section.code,
1857
+ title: section.title,
1858
+ description: section.description,
1859
+ items: section.items.map((item, itemIndex) => ({
1860
+ id: item.id,
1861
+ order: itemIndex,
1862
+ name: this.resolveLocalizedTextForDialog(item.assetType?.name ?? ''),
1863
+ assetType: item.assetType,
1864
+ roleName: item.roleName,
1865
+ count: item.count,
1866
+ hasMaintenance: item.hasMaintenance,
1867
+ assetTypeId: item.assetTypeId,
1868
+ assetTypeSectionId: item.assetTypeSectionId || section.id,
1869
+ assetTypeSectionComponentId: item.assetTypeSectionComponentId || item.id,
1870
+ assetId: item.assetId,
1871
+ asset: item.asset,
1872
+ })),
1873
+ })),
1874
+ };
1875
+ }
1876
+ fromBuilderValue(value) {
1877
+ const assetTypeId = this.assetTypeId() ?? '';
1878
+ return {
1879
+ sections: value.sections.map((section, sectionIndex) => {
1880
+ const sectionId = section.id || AXPDataGenerator.uuid();
1881
+ const sectionCodeRaw = Number(section['code'] ?? sectionIndex + 1);
1882
+ const sectionCode = Number.isFinite(sectionCodeRaw) && sectionCodeRaw > 0 ? sectionCodeRaw : sectionIndex + 1;
1883
+ return {
1884
+ id: sectionId,
1885
+ code: sectionCode,
1886
+ title: normalizeAssetTypeBuilderLocalizedField(section['title'], `Section ${sectionCode}`),
1887
+ assetTypeId,
1888
+ description: normalizeAssetTypeBuilderLocalizedField(section['description'], ''),
1889
+ items: section.items.map((item) => this.mapBuilderItemToDomain(item, sectionId, assetTypeId)),
1890
+ };
1891
+ }),
1892
+ };
1893
+ }
1894
+ mapBuilderItemToDomain(item, sectionId, assetTypeId) {
1895
+ const rawAt = item['assetType'];
1896
+ const normalizedAssetTypeId = (() => {
1897
+ const fromField = typeof item['assetTypeId'] === 'string' ? String(item['assetTypeId']).trim() : '';
1898
+ if (fromField)
1899
+ return fromField;
1900
+ const fromRef = typeof rawAt?.id === 'string' ? String(rawAt.id).trim() : '';
1901
+ if (fromRef)
1902
+ return fromRef;
1903
+ return String(assetTypeId ?? '');
1904
+ })();
1905
+ return {
1906
+ id: item.id || AXPDataGenerator.uuid(),
1907
+ assetTypeSectionId: String(item['assetTypeSectionId'] ?? sectionId),
1908
+ assetTypeId: normalizedAssetTypeId,
1909
+ assetType: {
1910
+ id: String(rawAt?.id ?? normalizedAssetTypeId),
1911
+ name: normalizeAssetTypeBuilderLocalizedField(rawAt?.name, ''),
1912
+ },
1913
+ roleName: normalizeAssetTypeBuilderLocalizedField(item['roleName'], ''),
1914
+ count: Number(item['count'] ?? 1),
1915
+ hasMaintenance: item['hasMaintenance'] === true,
1916
+ assetTypeSectionComponentId: String(item['assetTypeSectionComponentId'] ?? ''),
1917
+ assetId: typeof item['assetId'] === 'string' ? item['assetId'] : undefined,
1918
+ asset: item['asset'] && typeof item['asset'] === 'object'
1919
+ ? {
1920
+ id: String(item['asset'].id ?? ''),
1921
+ code: typeof item['asset'].code === 'string'
1922
+ ? (item['asset'].code ?? '')
1923
+ : undefined,
1924
+ title: normalizeAssetTypeBuilderLocalizedField(item['asset'].title, ''),
1925
+ }
1926
+ : undefined,
1927
+ };
1928
+ }
1929
+ resolveLocalizedTextForDialog(value) {
1930
+ if (value == null || value === '') {
1931
+ return '';
1932
+ }
1933
+ if (typeof value === 'string') {
1934
+ return value;
1935
+ }
1936
+ return resolveMultiLanguageString(value, this.translationService.getActiveLang());
1937
+ }
1938
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeSectionBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1939
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMAssetTypeSectionBuilderComponent, isStandalone: true, selector: "axm-asset-type-section-builder", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, assetTypeId: { classPropertyName: "assetTypeId", publicName: "assetTypeId", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, viewQueries: [{ propertyName: "standardRef", first: true, predicate: AXPStandardSectionItemsBuilderComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"axm-asset-type-section-builder\">\n @if (!readonly() && !hideHeaderActions() && allowAddSection()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n <ax-button\n class=\"ax-sm\"\n [text]=\"'@asset-management:assetTypeSections.entities.assetTypeSection.actions.add-section.title' | translate | async\"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n class=\"block min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\" />\n</div>\n", styles: [".axm-asset-type-section-builder .__header{margin-bottom:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:space-between}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStandardSectionItemsBuilderComponent, selector: "axp-standard-section-items-builder", inputs: ["value", "config", "readonly"], outputs: ["valueChange"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1940
+ }
1941
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeSectionBuilderComponent, decorators: [{
1942
+ type: Component,
1943
+ args: [{ selector: 'axm-asset-type-section-builder', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1944
+ CommonModule,
1945
+ AXButtonModule,
1946
+ AXDecoratorModule,
1947
+ AXTranslationModule,
1948
+ AXPStandardSectionItemsBuilderComponent,
1949
+ ], template: "<div class=\"axm-asset-type-section-builder\">\n @if (!readonly() && !hideHeaderActions() && allowAddSection()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n <ax-button\n class=\"ax-sm\"\n [text]=\"'@asset-management:assetTypeSections.entities.assetTypeSection.actions.add-section.title' | translate | async\"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n class=\"block min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\" />\n</div>\n", styles: [".axm-asset-type-section-builder .__header{margin-bottom:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:space-between}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
1950
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], assetTypeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "assetTypeId", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], standardRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPStandardSectionItemsBuilderComponent), { isSignal: true }] }] } });
1951
+
1952
+ const ASSET_TYPE_COMPONENTS_SAVE_COMMAND = 'AssetType:Components:Save';
1953
+ class AXMSaveAssetTypeComponentsCommand {
1954
+ constructor() {
1955
+ this.entityService = inject(AXPEntityService);
1956
+ this.translationService = inject(AXTranslationService);
1957
+ }
1958
+ async execute(input) {
1959
+ const id = input?.id;
1960
+ const entityRef = input?.entity || `${RootConfig.module.name}.${RootConfig.entities.assetType.name}`;
1961
+ const field = input?.field || 'components';
1962
+ const value = input?.value ?? { sections: [] };
1963
+ if (!id) {
1964
+ return {
1965
+ success: false,
1966
+ message: {
1967
+ text: await this.translationService.translateAsync('@general:messages.entity.invalid-data'),
1968
+ },
1969
+ };
1970
+ }
1971
+ try {
1972
+ const payload = { [field]: value };
1973
+ const isAssetTypeComponentsUpdate = entityRef === `${RootConfig.module.name}.${RootConfig.entities.assetType.name}` && field === 'components';
1974
+ if (isAssetTypeComponentsUpdate) {
1975
+ payload['name'] = this.ensureLatinName(input.name, {
1976
+ fallback: input.title,
1977
+ id,
1978
+ });
1979
+ }
1980
+ await this.entityService.withEntity(entityRef).data().update(id, payload);
1981
+ return { success: true, kind: 'object',
1982
+ data: { id, field, value },
1983
+ message: {
1984
+ text: await this.translationService.translateAsync('@general:messages.generic.success.description'),
1985
+ },
1986
+ };
1987
+ }
1988
+ catch (error) {
1989
+ const message = error instanceof Error
1990
+ ? error.message
1991
+ : await this.translationService.translateAsync('@general:messages.generic.error.description');
1992
+ return {
1993
+ success: false,
1994
+ message: {
1995
+ text: message,
1996
+ },
1997
+ };
1998
+ }
1999
+ }
2000
+ ensureLatinName(raw, context) {
2001
+ const fromRaw = this.toLatinIdentifier(raw);
2002
+ if (fromRaw) {
2003
+ return fromRaw;
2004
+ }
2005
+ const fromTitle = this.toLatinIdentifier(context?.fallback);
2006
+ if (fromTitle) {
2007
+ return fromTitle;
2008
+ }
2009
+ const fromId = this.toLatinIdentifier(context?.id);
2010
+ if (fromId) {
2011
+ return fromId;
2012
+ }
2013
+ return 'asset_type';
2014
+ }
2015
+ toLatinIdentifier(value) {
2016
+ if (typeof value !== 'string') {
2017
+ return '';
2018
+ }
2019
+ return value
2020
+ .replace(/[^A-Za-z0-9_-]+/g, '_')
2021
+ .replace(/^_+|_+$/g, '')
2022
+ .replace(/_{2,}/g, '_');
2023
+ }
2024
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSaveAssetTypeComponentsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2025
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSaveAssetTypeComponentsCommand, providedIn: 'root' }); }
2026
+ }
2027
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSaveAssetTypeComponentsCommand, decorators: [{
2028
+ type: Injectable,
2029
+ args: [{
2030
+ providedIn: 'root',
2031
+ }]
2032
+ }] });
2033
+
2034
+ var saveAssetTypeComponents_command = /*#__PURE__*/Object.freeze({
2035
+ __proto__: null,
2036
+ ASSET_TYPE_COMPONENTS_SAVE_COMMAND: ASSET_TYPE_COMPONENTS_SAVE_COMMAND,
2037
+ AXMSaveAssetTypeComponentsCommand: AXMSaveAssetTypeComponentsCommand
2038
+ });
2039
+
2040
+ const ASSET_TYPE_SECTIONS_ADD_SECTION_COMMAND = 'AssetType:Sections:AddSection';
2041
+ const ASSET_TYPE_SECTIONS_DISCARD_COMMAND = 'AssetType:Sections:Discard';
2042
+ const ASSET_TYPE_SECTIONS_SAVE_COMMAND = 'AssetType:Sections:Save';
2043
+ class AXMAssetTypeSectionBuilderPageComponent extends AXPPageLayoutBaseComponent {
2044
+ constructor() {
2045
+ super(...arguments);
2046
+ /** Default `{}`: required inputs throw (NG0950) if read before `AXPPageComponentRendererDirective` calls `setInput` after `createComponent`. */
2047
+ this.rootContext = input({}, /* @ts-ignore */
2048
+ ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
2049
+ this.pageConfig = input(/* @ts-ignore */
2050
+ ...(ngDevMode ? [undefined, { debugName: "pageConfig" }] : /* istanbul ignore next */ []));
2051
+ this.options = input({}, /* @ts-ignore */
2052
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2053
+ this.builderRef = viewChild('builderRef', /* @ts-ignore */
2054
+ ...(ngDevMode ? [{ debugName: "builderRef" }] : /* istanbul ignore next */ []));
2055
+ this.commandService = inject(AXPCommandService);
2056
+ this.entityService = inject(AXPEntityService);
2057
+ this.hostPageLayout = inject(AXPPageLayoutBase, { optional: true, skipSelf: true });
2058
+ this.baselineValue = signal(null, /* @ts-ignore */
2059
+ ...(ngDevMode ? [{ debugName: "baselineValue" }] : /* istanbul ignore next */ []));
2060
+ this.committedValue = signal(null, /* @ts-ignore */
2061
+ ...(ngDevMode ? [{ debugName: "committedValue" }] : /* istanbul ignore next */ []));
2062
+ this.config = computed(() => ({
2063
+ ...(this.pageConfig() ?? {}),
2064
+ ...(this.options() ?? {}),
2065
+ }), /* @ts-ignore */
2066
+ ...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
2067
+ this.fieldName = computed(() => {
2068
+ const field = this.readStringConfig('field');
2069
+ return field || 'components';
2070
+ }, /* @ts-ignore */
2071
+ ...(ngDevMode ? [{ debugName: "fieldName" }] : /* istanbul ignore next */ []));
2072
+ this.sourceFieldName = computed(() => {
2073
+ const field = this.readStringConfig('sourceField');
2074
+ return field || this.fieldName();
2075
+ }, /* @ts-ignore */
2076
+ ...(ngDevMode ? [{ debugName: "sourceFieldName" }] : /* istanbul ignore next */ []));
2077
+ this.sourceIdPath = computed(() => {
2078
+ const path = this.readStringConfig('sourceIdPath');
2079
+ return path || 'id';
2080
+ }, /* @ts-ignore */
2081
+ ...(ngDevMode ? [{ debugName: "sourceIdPath" }] : /* istanbul ignore next */ []));
2082
+ this.targetIdPath = computed(() => {
2083
+ const path = this.readStringConfig('targetIdPath');
2084
+ return path || this.sourceIdPath();
2085
+ }, /* @ts-ignore */
2086
+ ...(ngDevMode ? [{ debugName: "targetIdPath" }] : /* istanbul ignore next */ []));
2087
+ this.sourceEntityRef = computed(() => {
2088
+ const entity = this.readStringConfig('sourceEntity');
2089
+ return entity || `${RootConfig.module.name}.${RootConfig.entities.assetType.name}`;
2090
+ }, /* @ts-ignore */
2091
+ ...(ngDevMode ? [{ debugName: "sourceEntityRef" }] : /* istanbul ignore next */ []));
2092
+ this.targetEntityRef = computed(() => {
2093
+ const entity = this.readStringConfig('targetEntity');
2094
+ return entity || this.sourceEntityRef();
2095
+ }, /* @ts-ignore */
2096
+ ...(ngDevMode ? [{ debugName: "targetEntityRef" }] : /* istanbul ignore next */ []));
2097
+ this.context = computed(() => this.rootContext(), /* @ts-ignore */
2098
+ ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
2099
+ this.sourceRecordId = computed(() => {
2100
+ const ctx = this.context();
2101
+ const id = get(ctx, this.sourceIdPath());
2102
+ if (typeof id === 'string' && id.length > 0) {
2103
+ return id;
2104
+ }
2105
+ // Lookup expose often hydrates nested `assetType.id` before/without top-level assetTypeId.
2106
+ if (this.sourceIdPath() === 'assetTypeId') {
2107
+ const nested = get(ctx, 'assetType.id');
2108
+ if (typeof nested === 'string' && nested.length > 0) {
2109
+ return nested;
2110
+ }
2111
+ }
2112
+ return undefined;
2113
+ }, /* @ts-ignore */
2114
+ ...(ngDevMode ? [{ debugName: "sourceRecordId" }] : /* istanbul ignore next */ []));
2115
+ this.targetRecordId = computed(() => {
2116
+ const id = get(this.context(), this.targetIdPath());
2117
+ return typeof id === 'string' ? id : undefined;
2118
+ }, /* @ts-ignore */
2119
+ ...(ngDevMode ? [{ debugName: "targetRecordId" }] : /* istanbul ignore next */ []));
2120
+ this.readonly = computed(() => this.readBooleanConfig('readonly'), /* @ts-ignore */
2121
+ ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
2122
+ this.linkAssetMode = computed(() => this.readBooleanConfig('linkAssetMode'), /* @ts-ignore */
2123
+ ...(ngDevMode ? [{ debugName: "linkAssetMode" }] : /* istanbul ignore next */ []));
2124
+ this.allowAddSection = computed(() => this.readBooleanConfig('allowAddSection', true), /* @ts-ignore */
2125
+ ...(ngDevMode ? [{ debugName: "allowAddSection" }] : /* istanbul ignore next */ []));
2126
+ this.allowAddItems = computed(() => this.readBooleanConfig('allowAddItems', true), /* @ts-ignore */
2127
+ ...(ngDevMode ? [{ debugName: "allowAddItems" }] : /* istanbul ignore next */ []));
2128
+ this.allowEditSection = computed(() => this.readBooleanConfig('allowEditSection', true), /* @ts-ignore */
2129
+ ...(ngDevMode ? [{ debugName: "allowEditSection" }] : /* istanbul ignore next */ []));
2130
+ this.allowReorderSections = computed(() => this.readBooleanConfig('allowReorderSections', true), /* @ts-ignore */
2131
+ ...(ngDevMode ? [{ debugName: "allowReorderSections" }] : /* istanbul ignore next */ []));
2132
+ this.builderOptions = computed(() => ({
2133
+ hideHeaderActions: true,
2134
+ readonly: this.readonly(),
2135
+ linkAssetMode: this.linkAssetMode(),
2136
+ mainAssetId: this.targetRecordId(),
2137
+ allowAddSection: this.allowAddSection(),
2138
+ allowEditSection: this.allowEditSection(),
2139
+ allowAddItems: this.allowAddItems(),
2140
+ allowReorderSections: this.allowReorderSections(),
2141
+ }), /* @ts-ignore */
2142
+ ...(ngDevMode ? [{ debugName: "builderOptions" }] : /* istanbul ignore next */ []));
2143
+ this.isDirty = computed(() => {
2144
+ const baseline = this.baselineValue();
2145
+ const committed = this.committedValue();
2146
+ return !isEqual(baseline ?? null, committed ?? null);
2147
+ }, /* @ts-ignore */
2148
+ ...(ngDevMode ? [{ debugName: "isDirty" }] : /* istanbul ignore next */ []));
2149
+ this.#syncFromContext = effect((onCleanup) => {
2150
+ const ctx = this.context();
2151
+ const id = this.sourceRecordId();
2152
+ const linkMode = this.linkAssetMode();
2153
+ const fieldName = this.fieldName();
2154
+ const sourceField = this.sourceFieldName();
2155
+ const value = get(ctx, fieldName);
2156
+ const linkedFromContext = get(ctx, fieldName);
2157
+ if (!linkMode) {
2158
+ const immediateValue = (value ?? null);
2159
+ this.baselineValue.set(immediateValue);
2160
+ this.committedValue.set(immediateValue);
2161
+ untracked(() => this.recompute());
2162
+ if (!id) {
2163
+ return;
2164
+ }
2165
+ let cancelled = false;
2166
+ const sourceEntityRef = this.sourceEntityRef();
2167
+ const load = async () => {
2168
+ try {
2169
+ const sourceRecord = await this.entityService.withEntity(sourceEntityRef).data().byKey(id);
2170
+ if (cancelled)
2171
+ return;
2172
+ const fallbackValue = get(sourceRecord, sourceField);
2173
+ const resolved = this.hasSections(value) ? value : (fallbackValue ?? null);
2174
+ this.baselineValue.set(resolved);
2175
+ this.committedValue.set(resolved);
2176
+ untracked(() => this.recompute());
2177
+ }
2178
+ catch {
2179
+ if (cancelled)
2180
+ return;
2181
+ this.baselineValue.set(immediateValue);
2182
+ this.committedValue.set(immediateValue);
2183
+ untracked(() => this.recompute());
2184
+ }
2185
+ };
2186
+ void load();
2187
+ onCleanup(() => {
2188
+ cancelled = true;
2189
+ });
2190
+ return;
2191
+ }
2192
+ // ----- linkAssetMode: template from source entity (AssetType), links on target (Asset) -----
2193
+ // Never use target context's `components` (or empty defaults) as the structure template.
2194
+ if (!id) {
2195
+ const empty = this.buildLinkedAssetValue(null, this.pickPersistedComponentLinks(linkedFromContext, undefined));
2196
+ this.baselineValue.set(empty);
2197
+ this.committedValue.set(empty);
2198
+ untracked(() => this.recompute());
2199
+ return;
2200
+ }
2201
+ let cancelled = false;
2202
+ const sourceEntityRef = this.sourceEntityRef();
2203
+ const targetEntityRef = this.targetEntityRef();
2204
+ const targetRecordId = this.targetRecordId();
2205
+ const shouldFetchPersistedLinksFromTarget = typeof targetRecordId === 'string' &&
2206
+ targetRecordId.length > 0 &&
2207
+ targetEntityRef !== sourceEntityRef;
2208
+ const load = async () => {
2209
+ try {
2210
+ const [sourceRecord, targetRecord] = await Promise.all([
2211
+ this.entityService.withEntity(sourceEntityRef).data().byKey(id),
2212
+ shouldFetchPersistedLinksFromTarget
2213
+ ? this.entityService.withEntity(targetEntityRef).data().byKey(targetRecordId)
2214
+ : Promise.resolve(null),
2215
+ ]);
2216
+ if (cancelled)
2217
+ return;
2218
+ const template = get(sourceRecord, sourceField);
2219
+ const recordLinksUnknown = shouldFetchPersistedLinksFromTarget
2220
+ ? get(targetRecord, fieldName)
2221
+ : get(sourceRecord, fieldName);
2222
+ const resolved = this.buildLinkedAssetValue(this.hasSections(template) ? (template ?? null) : null, this.pickPersistedComponentLinks(linkedFromContext, recordLinksUnknown));
2223
+ this.baselineValue.set(resolved);
2224
+ this.committedValue.set(resolved);
2225
+ untracked(() => this.recompute());
2226
+ }
2227
+ catch {
2228
+ if (cancelled)
2229
+ return;
2230
+ // Keep whatever is already shown; do not wipe with an empty target-context template.
2231
+ untracked(() => this.recompute());
2232
+ }
2233
+ };
2234
+ void load();
2235
+ onCleanup(() => {
2236
+ cancelled = true;
2237
+ });
2238
+ }, /* @ts-ignore */
2239
+ ...(ngDevMode ? [{ debugName: "#syncFromContext" }] : /* istanbul ignore next */ []));
2240
+ }
2241
+ #syncFromContext;
2242
+ onValueChange(value) {
2243
+ this.committedValue.set(value);
2244
+ this.updateRootContextField(this.fieldName(), this.linkAssetMode() ? this.toAssetComponentValue(value) : value);
2245
+ this.recompute();
2246
+ }
2247
+ getWizardStepContext() {
2248
+ const field = this.fieldName();
2249
+ const value = this.committedValue();
2250
+ if (!field || value == null) {
2251
+ return null;
2252
+ }
2253
+ const ctxValue = this.linkAssetMode() ? this.toAssetComponentValue(value) : value;
2254
+ return { [field]: cloneDeep(ctxValue) };
2255
+ }
2256
+ hasUnsavedChanges() {
2257
+ return this.isDirty();
2258
+ }
2259
+ async getPrimaryMenuItems() {
2260
+ if (this.readonly()) {
2261
+ return [];
2262
+ }
2263
+ const addSectionTitle = (await this.translateService.translateAsync('@asset-management:assetTypeSections.entities.assetTypeSection.actions.add-section.title')) || 'Add Section';
2264
+ const discardTitle = (await this.translateService.translateAsync('@general:actions.discard.title')) || 'Discard';
2265
+ const saveTitle = (await this.translateService.translateAsync('@general:actions.save.title')) || 'Save';
2266
+ return [
2267
+ ...(this.allowAddSection()
2268
+ ? [
2269
+ {
2270
+ title: addSectionTitle,
2271
+ icon: 'fa-light fa-layer-group',
2272
+ zone: 'header',
2273
+ priority: 'primary',
2274
+ color: 'primary',
2275
+ command: { name: ASSET_TYPE_SECTIONS_ADD_SECTION_COMMAND, options: {} },
2276
+ },
2277
+ ]
2278
+ : []),
2279
+ {
2280
+ title: discardTitle,
2281
+ icon: 'fa-light fa-rotate-left',
2282
+ zone: 'footer',
2283
+ priority: 'secondary',
2284
+ color: 'default',
2285
+ visible: this.isDirty(),
2286
+ command: { name: ASSET_TYPE_SECTIONS_DISCARD_COMMAND, options: {} },
2287
+ },
2288
+ {
2289
+ title: saveTitle,
2290
+ icon: 'fa-light fa-floppy-disk',
2291
+ zone: 'footer',
2292
+ priority: 'primary',
2293
+ color: 'primary',
2294
+ visible: this.isDirty(),
2295
+ command: { name: ASSET_TYPE_SECTIONS_SAVE_COMMAND, options: {} },
2296
+ },
2297
+ ];
2298
+ }
2299
+ async execute(command) {
2300
+ if (command.name === ASSET_TYPE_SECTIONS_ADD_SECTION_COMMAND) {
2301
+ await this.builderRef()?.addSection();
2302
+ return;
2303
+ }
2304
+ if (command.name === ASSET_TYPE_SECTIONS_DISCARD_COMMAND) {
2305
+ this.handleDiscard();
2306
+ return;
2307
+ }
2308
+ if (command.name !== ASSET_TYPE_SECTIONS_SAVE_COMMAND)
2309
+ return;
2310
+ await this.handleSave({ silent: false });
2311
+ }
2312
+ async handleSave(options) {
2313
+ const silent = options?.silent === true;
2314
+ const id = this.targetRecordId();
2315
+ const entity = this.targetEntityRef();
2316
+ const field = this.fieldName();
2317
+ const value = this.committedValue();
2318
+ if (!id || !entity || !field) {
2319
+ if (!silent) {
2320
+ this.toastService.show({
2321
+ color: 'danger',
2322
+ title: await this.translateService.translateAsync('@general:messages.error.title'),
2323
+ content: await this.translateService.translateAsync('@general:messages.entity.invalid-data'),
2324
+ });
2325
+ }
2326
+ return;
2327
+ }
2328
+ const root = (this.rootContext() ?? {});
2329
+ const result = await this.commandService.execute(ASSET_TYPE_COMPONENTS_SAVE_COMMAND, {
2330
+ id,
2331
+ entity,
2332
+ field,
2333
+ value: this.linkAssetMode() ? this.toAssetComponentValue(value ?? { sections: [] }) : (value ?? { sections: [] }),
2334
+ name: root['name'],
2335
+ title: root['title'],
2336
+ });
2337
+ if (result?.success) {
2338
+ const saved = value ?? { sections: [] };
2339
+ this.baselineValue.set(saved);
2340
+ this.committedValue.set(saved);
2341
+ this.updateRootContextField(field, this.linkAssetMode() ? this.toAssetComponentValue(saved) : saved);
2342
+ this.builderRef()?.syncAfterSave(saved);
2343
+ this.recompute();
2344
+ if (!silent) {
2345
+ this.toastService.show({
2346
+ color: 'success',
2347
+ title: await this.translateService.translateAsync('@general:messages.generic.success.title'),
2348
+ content: await this.translateService.translateAsync('@general:messages.generic.success.description'),
2349
+ });
2350
+ }
2351
+ return;
2352
+ }
2353
+ this.toastService.show({
2354
+ color: 'danger',
2355
+ title: await this.translateService.translateAsync('@general:messages.error.title'),
2356
+ content: await this.translateService.translateAsync('@general:messages.entity.update-failed'),
2357
+ });
2358
+ }
2359
+ recompute() {
2360
+ super.recompute();
2361
+ const layout = this.hostPageLayout;
2362
+ layout?.recompute?.();
2363
+ }
2364
+ handleDiscard() {
2365
+ const baseline = this.baselineValue() ?? { sections: [] };
2366
+ const field = this.fieldName();
2367
+ this.committedValue.set(baseline);
2368
+ this.updateRootContextField(field, this.linkAssetMode() ? this.toAssetComponentValue(baseline) : baseline);
2369
+ this.builderRef()?.resetAfterDiscard();
2370
+ this.recompute();
2371
+ }
2372
+ /** Keeps details-view `rootContext` in sync so sidebar navigation remounts with latest data. */
2373
+ updateRootContextField(field, value) {
2374
+ const ctx = this.rootContext();
2375
+ if (!ctx || typeof ctx !== 'object') {
2376
+ return;
2377
+ }
2378
+ ctx[field] = cloneDeep(value);
2379
+ }
2380
+ buildLinkedAssetValue(source, links) {
2381
+ if (!source || !Array.isArray(source.sections)) {
2382
+ return { sections: [] };
2383
+ }
2384
+ const groupedLinks = new Map();
2385
+ for (const link of links ?? []) {
2386
+ const key = String(link.assetTypeSectionComponentId ?? '');
2387
+ if (!key)
2388
+ continue;
2389
+ if (!groupedLinks.has(key))
2390
+ groupedLinks.set(key, []);
2391
+ groupedLinks.get(key).push(link);
2392
+ }
2393
+ return {
2394
+ sections: source.sections.map((section) => ({
2395
+ ...section,
2396
+ items: (section.items ?? []).flatMap((item) => {
2397
+ const componentId = String(item.id ?? '');
2398
+ const count = Math.max(1, Number(item.count ?? 1));
2399
+ const existing = groupedLinks.get(componentId) ?? [];
2400
+ return Array.from({ length: count }).map((_, index) => {
2401
+ const linked = existing[index];
2402
+ return {
2403
+ ...item,
2404
+ id: `${componentId}__slot_${index + 1}`,
2405
+ count: 1,
2406
+ assetTypeSectionComponentId: componentId,
2407
+ roleName: this.withSlotSuffix(item.roleName, index + 1),
2408
+ assetId: linked?.assetId,
2409
+ asset: linked?.asset
2410
+ ? {
2411
+ id: linked.asset.id,
2412
+ code: linked.asset.code,
2413
+ title: linked.asset.title,
2414
+ }
2415
+ : undefined,
2416
+ };
2417
+ });
2418
+ }),
2419
+ })),
2420
+ };
2421
+ }
2422
+ withSlotSuffix(value, slotIndex) {
2423
+ const normalized = normalizeAssetTypeBuilderLocalizedField(value, '');
2424
+ const suffix = `#${slotIndex}`;
2425
+ if (typeof normalized === 'string') {
2426
+ const base = normalized.trim();
2427
+ return base ? `${base} ${suffix}` : suffix;
2428
+ }
2429
+ return Object.fromEntries(Object.entries(normalized).map(([locale, text]) => {
2430
+ const trimmed = typeof text === 'string' ? text.trim() : '';
2431
+ return [locale, trimmed ? `${trimmed} ${suffix}` : suffix];
2432
+ }));
2433
+ }
2434
+ toAssetComponentValue(value) {
2435
+ const mainAssetId = this.targetRecordId() ?? '';
2436
+ return value.sections.flatMap((section) => (section.items ?? [])
2437
+ .filter((item) => typeof item.assetId === 'string' && item.assetId)
2438
+ .map((item) => ({
2439
+ id: item.id,
2440
+ assetId: String(item.assetId),
2441
+ asset: {
2442
+ id: String(item.asset?.id ?? item.assetId),
2443
+ code: String(item.asset?.code ?? ''),
2444
+ title: String(item.asset?.title ?? ''),
2445
+ },
2446
+ mainAssetId,
2447
+ mainAsset: {
2448
+ id: mainAssetId,
2449
+ code: '',
2450
+ title: '',
2451
+ },
2452
+ assetTypeSectionComponentId: String(item.assetTypeSectionComponentId ?? ''),
2453
+ assetTypeSectionComponent: {
2454
+ id: String(item.assetTypeSectionComponentId ?? ''),
2455
+ code: String(item.assetTypeSectionId ?? ''),
2456
+ title: String(item.roleName ?? ''),
2457
+ assetTypeId: String(item.assetTypeId ?? ''),
2458
+ assetType: {
2459
+ id: String(item.assetType?.id ?? String(item.assetTypeId ?? '')),
2460
+ name: item.assetType?.name ?? '',
2461
+ },
2462
+ },
2463
+ })));
2464
+ }
2465
+ readStringConfig(key) {
2466
+ const rootValue = this.config()[key];
2467
+ if (typeof rootValue === 'string') {
2468
+ return rootValue;
2469
+ }
2470
+ return '';
2471
+ }
2472
+ readBooleanConfig(key, defaultValue = false) {
2473
+ const rootValue = this.config()[key];
2474
+ if (typeof rootValue === 'boolean') {
2475
+ return rootValue;
2476
+ }
2477
+ return defaultValue;
2478
+ }
2479
+ hasSections(value) {
2480
+ return !!value && Array.isArray(value.sections) && value.sections.length > 0;
2481
+ }
2482
+ /**
2483
+ * Prefer links loaded with the record (`byKey`). Context often holds `assetComponents: []` from a
2484
+ * partial row merge; `[] ?? serverLinks` would keep the empty array and hide persisted assignments.
2485
+ */
2486
+ pickPersistedComponentLinks(contextLinks, recordLinks) {
2487
+ if (recordLinks !== undefined) {
2488
+ return Array.isArray(recordLinks) ? recordLinks : [];
2489
+ }
2490
+ return Array.isArray(contextLinks) ? contextLinks : null;
2491
+ }
2492
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeSectionBuilderPageComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2493
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.8", type: AXMAssetTypeSectionBuilderPageComponent, isStandalone: true, selector: "axm-asset-type-section-builder-page", inputs: { rootContext: { classPropertyName: "rootContext", publicName: "rootContext", isSignal: true, isRequired: false, transformFunction: null }, pageConfig: { classPropertyName: "pageConfig", publicName: "pageConfig", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.axp-page-layout-base": "true" } }, providers: [
2494
+ {
2495
+ provide: AXPPageLayoutBase,
2496
+ useExisting: AXMAssetTypeSectionBuilderPageComponent,
2497
+ },
2498
+ ], viewQueries: [{ propertyName: "builderRef", first: true, predicate: ["builderRef"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
2499
+ <axm-asset-type-section-builder
2500
+ #builderRef
2501
+ [value]="committedValue()"
2502
+ [assetTypeId]="sourceRecordId()"
2503
+ [options]="builderOptions()"
2504
+ (valueChange)="onValueChange($event)"
2505
+ />
2506
+ `, isInline: true, dependencies: [{ kind: "component", type: AXMAssetTypeSectionBuilderComponent, selector: "axm-asset-type-section-builder", inputs: ["value", "assetTypeId", "options"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2507
+ }
2508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeSectionBuilderPageComponent, decorators: [{
2509
+ type: Component,
2510
+ args: [{
2511
+ selector: 'axm-asset-type-section-builder-page',
2512
+ standalone: true,
2513
+ imports: [AXMAssetTypeSectionBuilderComponent],
2514
+ providers: [
2515
+ {
2516
+ provide: AXPPageLayoutBase,
2517
+ useExisting: AXMAssetTypeSectionBuilderPageComponent,
2518
+ },
2519
+ ],
2520
+ template: `
2521
+ <axm-asset-type-section-builder
2522
+ #builderRef
2523
+ [value]="committedValue()"
2524
+ [assetTypeId]="sourceRecordId()"
2525
+ [options]="builderOptions()"
2526
+ (valueChange)="onValueChange($event)"
2527
+ />
2528
+ `,
2529
+ host: {
2530
+ '[class.axp-page-layout-base]': 'true',
2531
+ },
2532
+ changeDetection: ChangeDetectionStrategy.OnPush,
2533
+ }]
2534
+ }], propDecorators: { rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: false }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], builderRef: [{ type: i0.ViewChild, args: ['builderRef', { isSignal: true }] }] } });
2535
+
2536
+ var assetTypeSectionBuilderPage_component = /*#__PURE__*/Object.freeze({
2537
+ __proto__: null,
2538
+ AXMAssetTypeSectionBuilderPageComponent: AXMAssetTypeSectionBuilderPageComponent
2539
+ });
2540
+
2541
+ class AXMAssetTypeComponentsPageComponentProvider {
2542
+ async components() {
2543
+ return [
2544
+ {
2545
+ key: ASSET_TYPE_COMPONENTS_PAGE_COMPONENT_KEY,
2546
+ loader: () => Promise.resolve().then(function () { return assetTypeSectionBuilderPage_component; }).then((m) => m.AXMAssetTypeSectionBuilderPageComponent),
2547
+ },
2548
+ ];
2549
+ }
2550
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeComponentsPageComponentProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2551
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeComponentsPageComponentProvider }); }
2552
+ }
2553
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetTypeComponentsPageComponentProvider, decorators: [{
2554
+ type: Injectable
2555
+ }] });
2556
+
2557
+ var index = /*#__PURE__*/_mergeNamespaces({
2558
+ __proto__: null,
2559
+ ASSET_TYPE_COMPONENTS_SAVE_COMMAND: ASSET_TYPE_COMPONENTS_SAVE_COMMAND,
2560
+ AXMAssetTypeComponentsPageComponentProvider: AXMAssetTypeComponentsPageComponentProvider,
2561
+ AXMAssetTypeSectionBuilderComponent: AXMAssetTypeSectionBuilderComponent,
2562
+ AXMAssetTypeSectionBuilderPageComponent: AXMAssetTypeSectionBuilderPageComponent,
2563
+ AXMSaveAssetTypeComponentsCommand: AXMSaveAssetTypeComponentsCommand,
2564
+ createAssetTypeSectionBuilderDefaultValue: createAssetTypeSectionBuilderDefaultValue,
2565
+ normalizeAssetTypeBuilderLocalizedField: normalizeAssetTypeBuilderLocalizedField,
2566
+ normalizeAssetTypeSectionBuilderValue: normalizeAssetTypeSectionBuilderValue
2567
+ }, [contracts]);
2568
+
2569
+ //#region ---- Imports ----
2570
+ //#endregion
2571
+ //#region ---- Constants ----
2572
+ const BLOCKING_WORK_ORDER_STATUSES = new Set(['in-progress', 'completed']);
2573
+ const PROTECTED_LIFECYCLE_STATUSES = new Set([AXMAssetLifecycleStatus.Retired, AXMAssetLifecycleStatus.Disposed]);
2574
+ const PROTECTED_OPERATIONAL_STATUSES = new Set([AXMAssetStatus.Lost]);
2575
+ //#endregion
2576
+ /**
2577
+ * Central policy for asset operational status changes driven by maintenance work orders.
2578
+ * Callers must not set `Asset.statusId` directly from workflows — use {@link recalculate} only.
2579
+ */
2580
+ class AXMAssetOperationalStatusService {
2581
+ constructor() {
2582
+ //#region ---- Services & Dependencies ----
2583
+ this.entityService = inject(AXPEntityService);
2584
+ }
2585
+ //#endregion
2586
+ //#region ---- Public API ----
2587
+ async recalculate(assetIdRaw, trigger, context = {}) {
2588
+ const assetId = assetIdRaw?.trim();
2589
+ if (!assetId) {
2590
+ return {
2591
+ assetId: '',
2592
+ previousStatusId: null,
2593
+ statusId: null,
2594
+ changed: false,
2595
+ reason: 'assetId is required',
2596
+ };
2597
+ }
2598
+ const asset = (await this.entityService.withEntity('AssetManagement', 'Asset').data().byKey(assetId));
2599
+ if (!asset?.id) {
2600
+ return {
2601
+ assetId,
2602
+ previousStatusId: null,
2603
+ statusId: null,
2604
+ changed: false,
2605
+ reason: 'Asset not found',
2606
+ };
2607
+ }
2608
+ const previousStatusId = isString(asset.statusId) ? asset.statusId.trim() : null;
2609
+ const lifecycleStatusId = isString(asset.lifecycleStatusId) ? asset.lifecycleStatusId.trim() : null;
2610
+ if (lifecycleStatusId && PROTECTED_LIFECYCLE_STATUSES.has(lifecycleStatusId)) {
2611
+ return {
2612
+ assetId,
2613
+ previousStatusId,
2614
+ statusId: previousStatusId,
2615
+ changed: false,
2616
+ reason: `${trigger}: asset lifecycle is protected`,
2617
+ };
2618
+ }
2619
+ if (previousStatusId && PROTECTED_OPERATIONAL_STATUSES.has(previousStatusId)) {
2620
+ return {
2621
+ assetId,
2622
+ previousStatusId,
2623
+ statusId: previousStatusId,
2624
+ changed: false,
2625
+ reason: `${trigger}: asset status is protected`,
2626
+ };
2627
+ }
2628
+ const maintenanceTypeId = await this.resolveMaintenanceTypeId(assetId, context);
2629
+ const shouldBlock = await this.shouldBlockAssetForMaintenance(assetId, maintenanceTypeId);
2630
+ let nextStatusId = previousStatusId;
2631
+ const update = {};
2632
+ if (trigger === 'work-started') {
2633
+ if (shouldBlock) {
2634
+ nextStatusId = AXMAssetStatus.UnderMaintenanceInspection;
2635
+ if (previousStatusId === AXMAssetStatus.Available || previousStatusId === AXMAssetStatus.Assigned) {
2636
+ update.statusBeforeInterruptionId = previousStatusId;
2637
+ }
2638
+ }
2639
+ }
2640
+ if (trigger === 'work-completed') {
2641
+ const hasBlockingWork = await this.hasBlockingWorkOrders(assetId);
2642
+ if (hasBlockingWork) {
2643
+ nextStatusId = AXMAssetStatus.UnderMaintenanceInspection;
2644
+ }
2645
+ // Do not release the asset here — completed work still awaits sign-off.
2646
+ }
2647
+ if (trigger === 'work-signed-off') {
2648
+ const hasBlockingWork = await this.hasBlockingWorkOrders(assetId);
2649
+ if (hasBlockingWork) {
2650
+ nextStatusId = AXMAssetStatus.UnderMaintenanceInspection;
2651
+ }
2652
+ else {
2653
+ nextStatusId = this.resolveRestoredStatus(asset);
2654
+ update.statusBeforeInterruptionId = null;
2655
+ }
2656
+ }
2657
+ const changed = !!nextStatusId && nextStatusId !== previousStatusId;
2658
+ const hasFieldUpdates = update.statusBeforeInterruptionId !== undefined;
2659
+ if ((changed && nextStatusId) || hasFieldUpdates) {
2660
+ await this.entityService
2661
+ .withEntity('AssetManagement', 'Asset')
2662
+ .data()
2663
+ .update(assetId, {
2664
+ ...update,
2665
+ ...(changed && nextStatusId ? { statusId: nextStatusId } : {}),
2666
+ });
2667
+ }
2668
+ return {
2669
+ assetId,
2670
+ previousStatusId,
2671
+ statusId: nextStatusId,
2672
+ changed,
2673
+ reason: changed ? `${trigger}: status recalculated` : `${trigger}: status unchanged`,
2674
+ };
2675
+ }
2676
+ //#endregion
2677
+ //#region ---- Policy helpers ----
2678
+ async resolveMaintenanceTypeId(assetId, context) {
2679
+ const fromContext = context.maintenanceTypeId?.trim();
2680
+ if (fromContext) {
2681
+ return fromContext;
2682
+ }
2683
+ const workOrderId = context.workOrderId?.trim();
2684
+ if (workOrderId) {
2685
+ const workOrder = (await this.entityService
2686
+ .withEntity('MaintenanceManagement', 'WorkOrder')
2687
+ .data()
2688
+ .byKey(workOrderId));
2689
+ const fromWorkOrder = workOrder?.maintenanceTypeId?.trim();
2690
+ if (fromWorkOrder) {
2691
+ return fromWorkOrder;
2692
+ }
2693
+ }
2694
+ const page = await this.entityService
2695
+ .withEntity('MaintenanceManagement', 'WorkOrder')
2696
+ .data()
2697
+ .query({
2698
+ skip: 0,
2699
+ take: 1,
2700
+ filter: {
2701
+ logic: 'and',
2702
+ filters: [
2703
+ { field: 'assetId', operator: { type: 'equal' }, value: assetId },
2704
+ { field: 'statusId', operator: { type: 'equal' }, value: 'in-progress' },
2705
+ ],
2706
+ },
2707
+ });
2708
+ const row = defaultTo(get(page, 'items[0]'), null);
2709
+ return row?.maintenanceTypeId?.trim() ?? '';
2710
+ }
2711
+ /**
2712
+ * Inspection-like maintenance types keep the asset blocked under the combined operational status.
2713
+ * TODO: replace title/code heuristic with an explicit MaintenanceType classification field when available.
2714
+ */
2715
+ async shouldBlockAssetForMaintenance(_assetId, maintenanceTypeId) {
2716
+ if (!maintenanceTypeId) {
2717
+ return true;
2718
+ }
2719
+ const maintenanceType = (await this.entityService
2720
+ .withEntity('MaintenanceManagement', 'MaintenanceType')
2721
+ .data()
2722
+ .byKey(maintenanceTypeId));
2723
+ if (!maintenanceType) {
2724
+ return true;
2725
+ }
2726
+ const code = maintenanceType.code?.toLowerCase() ?? '';
2727
+ const titleText = this.resolveDisplayText(maintenanceType.title).toLowerCase();
2728
+ const isInspection = code.includes('inspect') || titleText.includes('inspect');
2729
+ if (isInspection) {
2730
+ return true;
2731
+ }
2732
+ // Non-inspection maintenance that does not block the asset is not modeled yet.
2733
+ // TODO: honor MaintenanceType.blocksAsset (or equivalent) when introduced.
2734
+ return true;
2735
+ }
2736
+ async hasBlockingWorkOrders(assetId) {
2737
+ const page = await this.entityService
2738
+ .withEntity('MaintenanceManagement', 'WorkOrder')
2739
+ .data()
2740
+ .query({
2741
+ skip: 0,
2742
+ take: 100,
2743
+ filter: {
2744
+ logic: 'and',
2745
+ filters: [{ field: 'assetId', operator: { type: 'equal' }, value: assetId }],
2746
+ },
2747
+ });
2748
+ const items = defaultTo(get(page, 'items'), []);
2749
+ return items.some((row) => {
2750
+ const statusId = row.statusId?.trim();
2751
+ return !!statusId && BLOCKING_WORK_ORDER_STATUSES.has(statusId);
2752
+ });
2753
+ }
2754
+ resolveRestoredStatus(asset) {
2755
+ const saved = isString(asset.statusBeforeInterruptionId) ? asset.statusBeforeInterruptionId.trim() : null;
2756
+ if (saved) {
2757
+ return saved;
2758
+ }
2759
+ return AXMAssetStatus.Available;
2760
+ }
2761
+ resolveDisplayText(value) {
2762
+ if (isString(value)) {
2763
+ return value;
2764
+ }
2765
+ if (value && typeof value === 'object') {
2766
+ const record = value;
2767
+ return record['en-US'] ?? record['fa-IR'] ?? Object.values(record)[0] ?? '';
2768
+ }
2769
+ return '';
2770
+ }
2771
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetOperationalStatusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2772
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetOperationalStatusService, providedIn: 'root' }); }
2773
+ }
2774
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAssetOperationalStatusService, decorators: [{
2775
+ type: Injectable,
2776
+ args: [{ providedIn: 'root' }]
2777
+ }] });
2778
+
2779
+ //#region ---- Types ----
2780
+ //#endregion
2781
+
2782
+ // export * from './asset-status.provider';
2783
+
2784
+ /**
2785
+ * Generated bundle index. Do not edit.
2786
+ */
2787
+
2788
+ export { AXMAssetOperationalStatusService as A, USAGE_UNIT_LABEL_KEYS as U, AXM_ASSET_USAGE_I18N as a, USAGE_KIND_LABEL_KEYS as b, USAGE_METER_KIND_ORDER as c, ASSET_TYPE_COMPONENTS_SAVE_COMMAND as d, AXMAssetManagementAssetStatusProvider as e, AXMAssetManagementFeatureDefinitionProvider as f, AXMAssetManagementMenuProvider as g, AXMAssetManagementModule as h, isUsageMeterKind as i, AXMAssetManagementPermissionDefinitionProvider as j, AXMAssetManagementSearchCommandProvider as k, AXMAssetTypeComponentsPageComponentProvider as l, AXMAssetTypeSectionBuilderComponent as m, AXMAssetTypeSectionBuilderPageComponent as n, orderedUsageMeterKinds as o, AXMCreateAssetRentalHistoryRentFromCommand as p, AXMCreateAssetRentalHistoryRentToCommand as q, readAssetUsageIntervalKinds as r, AXMSaveAssetTypeComponentsCommand as s, assertRentalPartyForDirection as t, createAssetTypeSectionBuilderDefaultValue as u, normalizeAssetTypeBuilderLocalizedField as v, normalizeAssetTypeSectionBuilderValue as w };
2789
+ //# sourceMappingURL=acorex-platform-module-asset-management-client-acorex-platform-module-asset-management-client-B7YXKaeh.mjs.map