@acorex-platform/module-timesheet-management-client 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-module-timesheet-management-client-admin-adjust-timesheet-period.command-8lA7h4rI.mjs +57 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-admin-adjust-timesheet-period.command-8lA7h4rI.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-approval-inbox.query-Wyz_jjxb.mjs +49 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-approval-inbox.query-Wyz_jjxb.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-approve-timesheet-period.command-DlAeGANo.mjs +54 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-approve-timesheet-period.command-DlAeGANo.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-compare-attendance-vs-timesheet.query-ZZym5nSx.mjs +91 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-compare-attendance-vs-timesheet.query-ZZym5nSx.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-contracts.mjs +200 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-create-time-entry.command-DS2EVLym.mjs +59 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-create-time-entry.command-DS2EVLym.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-delete-time-entry.command-5_ItHpnx.mjs +59 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-delete-time-entry.command-5_ItHpnx.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-lock-timesheet-period.command-D7V7SWUK.mjs +50 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-lock-timesheet-period.command-D7V7SWUK.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-my-timesheet-grid.query-DlDY3tdF.mjs +90 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-my-timesheet-grid.query-DlDY3tdF.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-reject-timesheet-period.command-CONxKPNm.mjs +56 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-reject-timesheet-period.command-CONxKPNm.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-reopen-timesheet-period.command-DRr_c67L.mjs +56 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-reopen-timesheet-period.command-DRr_c67L.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-report-billable-summary.query-BeLk4Of7.mjs +57 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-report-billable-summary.query-BeLk4Of7.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-report-hours-by-project.query-Sp8cLnTC.mjs +69 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-report-hours-by-project.query-Sp8cLnTC.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-report-hours-by-work-item.query-C8RU9Uc0.mjs +70 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-report-hours-by-work-item.query-C8RU9Uc0.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-submit-timesheet-period.command-C2qlQVIC.mjs +51 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-submit-timesheet-period.command-C2qlQVIC.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-team-timesheets.query-B0QpkVEI.mjs +51 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-team-timesheets.query-B0QpkVEI.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-timesheet-validation.service-DMrJn3HU.mjs +263 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-timesheet-validation.service-DMrJn3HU.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-update-time-entry.command-Do6s9OrI.mjs +60 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-update-time-entry.command-Do6s9OrI.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-work-item-search.query-BA2kvF-S.mjs +68 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-work-item-search.query-BA2kvF-S.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-workforce-exception-report.query-0q-AITic.mjs +40 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client-workforce-exception-report.query-0q-AITic.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client.mjs +891 -0
- package/fesm2022/acorex-platform-module-timesheet-management-client.mjs.map +1 -0
- package/package.json +28 -0
- package/types/acorex-platform-module-timesheet-management-client-contracts.d.ts +305 -0
- package/types/acorex-platform-module-timesheet-management-client.d.ts +54 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { AXPSystemStatusType } from '@acorex-platform/framework-shared/core';
|
|
2
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, Injectable } from '@angular/core';
|
|
5
|
+
import { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';
|
|
6
|
+
import { A as AXMTimesheetValidationService } from './acorex-platform-module-timesheet-management-client-timesheet-validation.service-DMrJn3HU.mjs';
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
/**
|
|
10
|
+
* Submits a draft timesheet period for approval.
|
|
11
|
+
*/
|
|
12
|
+
class SubmitTimesheetPeriodCommand {
|
|
13
|
+
constructor() {
|
|
14
|
+
//#region ---- Services & Dependencies ----
|
|
15
|
+
this.entityService = inject(AXPEntityService);
|
|
16
|
+
this.validationService = inject(AXMTimesheetValidationService);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region ---- Command Implementation ----
|
|
20
|
+
async execute(input) {
|
|
21
|
+
try {
|
|
22
|
+
const dataAccessor = this.entityService
|
|
23
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)
|
|
24
|
+
.data();
|
|
25
|
+
const period = await dataAccessor.byKey(input.id);
|
|
26
|
+
if (!period) {
|
|
27
|
+
return { success: false, message: { text: 'Timesheet period not found.' } };
|
|
28
|
+
}
|
|
29
|
+
this.validationService.assertCanSubmit(period);
|
|
30
|
+
await dataAccessor.update(input.id, {
|
|
31
|
+
statusId: AXPSystemStatusType.WaitingApproval,
|
|
32
|
+
submittedAt: new Date().toISOString(),
|
|
33
|
+
});
|
|
34
|
+
return { success: true, kind: 'object', data: undefined };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : 'Failed to submit timesheet period.';
|
|
38
|
+
console.error('[SubmitTimesheetPeriodCommand] Error:', error);
|
|
39
|
+
return { success: false, message: { text: message } };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SubmitTimesheetPeriodCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
43
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SubmitTimesheetPeriodCommand, providedIn: 'root' }); }
|
|
44
|
+
}
|
|
45
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SubmitTimesheetPeriodCommand, decorators: [{
|
|
46
|
+
type: Injectable,
|
|
47
|
+
args: [{ providedIn: 'root' }]
|
|
48
|
+
}] });
|
|
49
|
+
|
|
50
|
+
export { SubmitTimesheetPeriodCommand };
|
|
51
|
+
//# sourceMappingURL=acorex-platform-module-timesheet-management-client-submit-timesheet-period.command-C2qlQVIC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-platform-module-timesheet-management-client-submit-timesheet-period.command-C2qlQVIC.mjs","sources":["../../../../libs/modules/timesheet-management/client/src/lib/features/timesheet-period/commands/submit-timesheet-period.command.ts"],"sourcesContent":["\n\nimport { AXPCommand, type AXPCommandExecuteResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport { AXPRuntimeCommandResult, AXPSystemStatusType } from '@acorex-platform/framework-shared/core';\nimport { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';\n\nimport { Injectable, inject } from '@angular/core';\nimport { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementTimesheetPeriodEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport { AXMTimesheetValidationService } from '../timesheet-validation.service';\n\n//#region ---- Types ----\n\nexport interface SubmitTimesheetPeriodInput {\n id: string;\n}\n\n//#endregion\n\n/**\n * Submits a draft timesheet period for approval.\n */\n@Injectable({ providedIn: 'root' })\nexport class SubmitTimesheetPeriodCommand implements AXPCommand<SubmitTimesheetPeriodInput, void> {\n //#region ---- Services & Dependencies ----\n\n private readonly entityService = inject(AXPEntityService);\n private readonly validationService = inject(AXMTimesheetValidationService);\n\n //#endregion\n\n //#region ---- Command Implementation ----\n\n async execute(input: SubmitTimesheetPeriodInput): AXPCommandExecuteResultPromise<void> {\n try {\n const dataAccessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)\n .data<string, AXMTimesheetManagementTimesheetPeriodEntityModel>();\n\n const period = await dataAccessor.byKey(input.id);\n if (!period) {\n return { success: false, message: { text: 'Timesheet period not found.' } };\n }\n\n this.validationService.assertCanSubmit(period);\n\n await dataAccessor.update(input.id, {\n statusId: AXPSystemStatusType.WaitingApproval,\n submittedAt: new Date().toISOString(),\n });\n\n return { success: true, kind: 'object', data: undefined };\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : 'Failed to submit timesheet period.';\n console.error('[SubmitTimesheetPeriodCommand] Error:', error);\n return { success: false, message: { text: message } };\n }\n }\n\n //#endregion\n}\n"],"names":[],"mappings":";;;;;;;AAiBA;AAEA;;AAEG;MAEU,4BAA4B,CAAA;AADzC,IAAA,WAAA,GAAA;;AAImB,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACxC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,6BAA6B,CAAC;AAiC3E,IAAA;;;IA3BC,MAAM,OAAO,CAAC,KAAiC,EAAA;AAC7C,QAAA,IAAI;AACF,YAAA,MAAM,YAAY,GAAG,IAAI,CAAC;AACvB,iBAAA,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI;AAC3E,iBAAA,IAAI,EAA4D;YAEnE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,EAAE;AACX,gBAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,6BAA6B,EAAE,EAAE;YAC7E;AAEA,YAAA,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,MAAM,CAAC;AAE9C,YAAA,MAAM,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE;gBAClC,QAAQ,EAAE,mBAAmB,CAAC,eAAe;AAC7C,gBAAA,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACtC,aAAA,CAAC;AAEF,YAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;QAC3D;QAAE,OAAO,KAAc,EAAE;AACvB,YAAA,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,oCAAoC;AAC7F,YAAA,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC;AAC7D,YAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QACvD;IACF;8GAlCW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAA5B,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,4BAA4B,cADf,MAAM,EAAA,CAAA,CAAA;;2FACnB,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBADxC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { runtimeQuerySuccessCollection, runtimeQueryFailure } from '@acorex-platform/framework-shared/core';
|
|
2
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, Injectable } from '@angular/core';
|
|
5
|
+
import { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';
|
|
6
|
+
|
|
7
|
+
//#endregion
|
|
8
|
+
/**
|
|
9
|
+
* Lists timesheet periods for direct reports or team members.
|
|
10
|
+
*/
|
|
11
|
+
class AXMTeamTimesheetsQuery {
|
|
12
|
+
constructor() {
|
|
13
|
+
//#region ---- Services & Dependencies ----
|
|
14
|
+
this.entityService = inject(AXPEntityService);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region ---- Query Execution ----
|
|
18
|
+
async fetch(input) {
|
|
19
|
+
try {
|
|
20
|
+
const opts = input ?? {};
|
|
21
|
+
const periodAccessor = this.entityService
|
|
22
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)
|
|
23
|
+
.data();
|
|
24
|
+
const filters = [];
|
|
25
|
+
if (opts.statusId) {
|
|
26
|
+
filters.push({ field: 'statusId', operator: { type: 'equal' }, value: opts.statusId });
|
|
27
|
+
}
|
|
28
|
+
const result = await periodAccessor.query({
|
|
29
|
+
skip: opts.skip ?? 0,
|
|
30
|
+
take: opts.take ?? 50,
|
|
31
|
+
sort: [{ field: 'startDate', dir: 'desc' }],
|
|
32
|
+
...(filters.length
|
|
33
|
+
? { filter: { logic: 'and', filters } }
|
|
34
|
+
: {}),
|
|
35
|
+
});
|
|
36
|
+
return runtimeQuerySuccessCollection({ items: result.items, total: result.total });
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return runtimeQueryFailure(error instanceof Error ? error.message : 'Failed to load team timesheets.');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTeamTimesheetsQuery, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
43
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTeamTimesheetsQuery, providedIn: 'root' }); }
|
|
44
|
+
}
|
|
45
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTeamTimesheetsQuery, decorators: [{
|
|
46
|
+
type: Injectable,
|
|
47
|
+
args: [{ providedIn: 'root' }]
|
|
48
|
+
}] });
|
|
49
|
+
|
|
50
|
+
export { AXMTeamTimesheetsQuery };
|
|
51
|
+
//# sourceMappingURL=acorex-platform-module-timesheet-management-client-team-timesheets.query-B0QpkVEI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-platform-module-timesheet-management-client-team-timesheets.query-B0QpkVEI.mjs","sources":["../../../../libs/modules/timesheet-management/client/src/lib/features/reporting/queries/team-timesheets.query.ts"],"sourcesContent":["import { AXPQuery, type AXPQueryFetchResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport type { AXDataSourceFilterOption } from '@acorex/cdk/common';\nimport {\n runtimeQueryFailure,\n runtimeQuerySuccessCollection,\n type AXPRuntimeQueryResult,\n} from '@acorex-platform/framework-shared/core';\nimport { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';\n\nimport { Injectable, inject } from '@angular/core';\nimport { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementTimesheetPeriodEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\n\n//#region ---- Types ----\n\nexport interface AXMTeamTimesheetsQueryInput {\n managerEmployeeId?: string;\n statusId?: string;\n skip?: number;\n take?: number;\n}\n\n//#endregion\n\n/**\n * Lists timesheet periods for direct reports or team members.\n */\n@Injectable({ providedIn: 'root' })\nexport class AXMTeamTimesheetsQuery\n implements AXPQuery<AXMTeamTimesheetsQueryInput, AXMTimesheetManagementTimesheetPeriodEntityModel>\n{\n //#region ---- Services & Dependencies ----\n\n private readonly entityService = inject(AXPEntityService);\n\n //#endregion\n\n //#region ---- Query Execution ----\n\n async fetch(\n input?: AXMTeamTimesheetsQueryInput | null,\n ): AXPQueryFetchResultPromise<AXMTimesheetManagementTimesheetPeriodEntityModel> {\n try {\n const opts = input ?? {};\n const periodAccessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)\n .data<string, AXMTimesheetManagementTimesheetPeriodEntityModel>();\n\n const filters: AXDataSourceFilterOption[] = [];\n if (opts.statusId) {\n filters.push({ field: 'statusId', operator: { type: 'equal' }, value: opts.statusId });\n }\n\n const result = await periodAccessor.query({\n skip: opts.skip ?? 0,\n take: opts.take ?? 50,\n sort: [{ field: 'startDate', dir: 'desc' }],\n ...(filters.length\n ? { filter: { logic: 'and', filters } }\n : {}),\n });\n\n return runtimeQuerySuccessCollection({ items: result.items, total: result.total });\n } catch (error) {\n return runtimeQueryFailure(\n error instanceof Error ? error.message : 'Failed to load team timesheets.',\n );\n }\n }\n\n //#endregion\n}\n"],"names":[],"mappings":";;;;;;AAsBA;AAEA;;AAEG;MAEU,sBAAsB,CAAA;AADnC,IAAA,WAAA,GAAA;;AAMmB,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAsC1D,IAAA;;;IAhCC,MAAM,KAAK,CACT,KAA0C,EAAA;AAE1C,QAAA,IAAI;AACF,YAAA,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;AACxB,YAAA,MAAM,cAAc,GAAG,IAAI,CAAC;AACzB,iBAAA,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI;AAC3E,iBAAA,IAAI,EAA4D;YAEnE,MAAM,OAAO,GAA+B,EAAE;AAC9C,YAAA,IAAI,IAAI,CAAC,QAAQ,EAAE;gBACjB,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxF;AAEA,YAAA,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC;AACxC,gBAAA,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC;AACpB,gBAAA,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;gBACrB,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;gBAC3C,IAAI,OAAO,CAAC;sBACR,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;sBACnC,EAAE,CAAC;AACR,aAAA,CAAC;AAEF,YAAA,OAAO,6BAA6B,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QACpF;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,mBAAmB,CACxB,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,iCAAiC,CAC3E;QACH;IACF;8GAxCW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAtB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cADT,MAAM,EAAA,CAAA,CAAA;;2FACnB,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBADlC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { AXPSystemStatusType } from '@acorex-platform/framework-shared/core';
|
|
2
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, Injectable } from '@angular/core';
|
|
5
|
+
import { defaultTo, isEmpty, get, isNil } from 'lodash';
|
|
6
|
+
import { AXMTimesheetPeriodLockedStatusIds, RootConfig, AXMTimesheetPeriodOpenStatusIds } from '@acorex-platform/module-timesheet-management-client/contracts';
|
|
7
|
+
|
|
8
|
+
//#region ---- Imports ----
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region ---- Timesheet Validation Service ----
|
|
11
|
+
/**
|
|
12
|
+
* Domain validation service for timesheet period and time entry business rules.
|
|
13
|
+
*/
|
|
14
|
+
class AXMTimesheetValidationService {
|
|
15
|
+
constructor() {
|
|
16
|
+
//#region ---- Services & Dependencies ----
|
|
17
|
+
this.entityService = inject(AXPEntityService);
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region ---- Entry Validation ----
|
|
21
|
+
/**
|
|
22
|
+
* Validates that a time entry date falls within policy and period constraints.
|
|
23
|
+
*/
|
|
24
|
+
validateEntryDates(entry, period, policy) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
const entryDate = entry.entryDate?.slice(0, 10);
|
|
27
|
+
const periodStart = period.startDate?.slice(0, 10);
|
|
28
|
+
const periodEnd = period.endDate?.slice(0, 10);
|
|
29
|
+
if (entryDate && periodStart && entryDate < periodStart) {
|
|
30
|
+
issues.push({
|
|
31
|
+
code: 'entry-before-period',
|
|
32
|
+
field: 'entryDate',
|
|
33
|
+
message: 'Entry date is before the period start date.',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (entryDate && periodEnd && entryDate > periodEnd) {
|
|
37
|
+
issues.push({
|
|
38
|
+
code: 'entry-after-period',
|
|
39
|
+
field: 'entryDate',
|
|
40
|
+
message: 'Entry date is after the period end date.',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (!defaultTo(policy?.allowFutureDates, false)) {
|
|
44
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
45
|
+
if (entryDate && entryDate > today) {
|
|
46
|
+
issues.push({
|
|
47
|
+
code: 'future-entry-date',
|
|
48
|
+
field: 'entryDate',
|
|
49
|
+
message: 'Future entry dates are not allowed by the active policy.',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (entry.startedAt && entry.endedAt) {
|
|
54
|
+
const started = Date.parse(entry.startedAt);
|
|
55
|
+
const ended = Date.parse(entry.endedAt);
|
|
56
|
+
if (!Number.isNaN(started) && !Number.isNaN(ended) && ended < started) {
|
|
57
|
+
issues.push({
|
|
58
|
+
code: 'ended-before-started',
|
|
59
|
+
field: 'endedAt',
|
|
60
|
+
message: 'End time must be after start time.',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { valid: isEmpty(issues), issues };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validates that a time entry does not overlap existing entries for the same employee.
|
|
68
|
+
*/
|
|
69
|
+
validateNoOverlap(entry, existingEntries, policy) {
|
|
70
|
+
const issues = [];
|
|
71
|
+
const overlapPolicy = defaultTo(policy?.overlapPolicy, 'reject');
|
|
72
|
+
if (!entry.startedAt || !entry.endedAt) {
|
|
73
|
+
return { valid: true, issues };
|
|
74
|
+
}
|
|
75
|
+
const start = Date.parse(entry.startedAt);
|
|
76
|
+
const end = Date.parse(entry.endedAt);
|
|
77
|
+
if (Number.isNaN(start) || Number.isNaN(end)) {
|
|
78
|
+
return { valid: true, issues };
|
|
79
|
+
}
|
|
80
|
+
const overlapping = existingEntries.filter((candidate) => {
|
|
81
|
+
if (candidate.id === entry.id || candidate.employeeId !== entry.employeeId) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (!candidate.startedAt || !candidate.endedAt) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const candidateStart = Date.parse(candidate.startedAt);
|
|
88
|
+
const candidateEnd = Date.parse(candidate.endedAt);
|
|
89
|
+
if (Number.isNaN(candidateStart) || Number.isNaN(candidateEnd)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return start < candidateEnd && end > candidateStart;
|
|
93
|
+
});
|
|
94
|
+
if (!isEmpty(overlapping)) {
|
|
95
|
+
issues.push({
|
|
96
|
+
code: overlapPolicy === 'warn' ? 'entry-overlap-warning' : 'entry-overlap',
|
|
97
|
+
field: 'startedAt',
|
|
98
|
+
message: overlapPolicy === 'warn'
|
|
99
|
+
? 'This entry overlaps another entry for the same employee.'
|
|
100
|
+
: 'Overlapping time entries are not allowed.',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
valid: overlapPolicy === 'warn' ? true : isEmpty(issues),
|
|
105
|
+
issues,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region ---- Period Validation ----
|
|
110
|
+
/**
|
|
111
|
+
* Validates that a timesheet period can still be edited.
|
|
112
|
+
*/
|
|
113
|
+
validatePeriodEditable(period) {
|
|
114
|
+
const statusId = period.statusId;
|
|
115
|
+
const isLocked = AXMTimesheetPeriodLockedStatusIds.includes(statusId);
|
|
116
|
+
if (isLocked) {
|
|
117
|
+
return {
|
|
118
|
+
valid: false,
|
|
119
|
+
issues: [
|
|
120
|
+
{
|
|
121
|
+
code: 'period-locked',
|
|
122
|
+
field: 'statusId',
|
|
123
|
+
message: 'This timesheet period is locked and cannot be edited.',
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return { valid: true, issues: [] };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Validates that a period is complete enough for submission.
|
|
132
|
+
*/
|
|
133
|
+
validateSubmissionCompleteness(period, entries, policy) {
|
|
134
|
+
const issues = [];
|
|
135
|
+
if (period.statusId !== AXPSystemStatusType.Draft) {
|
|
136
|
+
issues.push({
|
|
137
|
+
code: 'period-not-draft',
|
|
138
|
+
field: 'statusId',
|
|
139
|
+
message: 'Only draft periods can be submitted.',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (isEmpty(entries)) {
|
|
143
|
+
issues.push({
|
|
144
|
+
code: 'no-entries',
|
|
145
|
+
message: 'At least one time entry is required before submission.',
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (defaultTo(policy?.requireDescription, false)) {
|
|
149
|
+
const missingDescription = entries.some((entry) => isEmpty(get(entry, 'description')));
|
|
150
|
+
if (missingDescription) {
|
|
151
|
+
issues.push({
|
|
152
|
+
code: 'missing-description',
|
|
153
|
+
field: 'description',
|
|
154
|
+
message: 'All time entries must include a description before submission.',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const totalSeconds = defaultTo(period.totalSeconds, 0);
|
|
159
|
+
if (totalSeconds <= 0 && !isEmpty(entries)) {
|
|
160
|
+
issues.push({
|
|
161
|
+
code: 'zero-total',
|
|
162
|
+
field: 'totalSeconds',
|
|
163
|
+
message: 'Submitted periods must have a positive total duration.',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return { valid: isEmpty(issues), issues };
|
|
167
|
+
}
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region ---- Assertion Helpers ----
|
|
170
|
+
assertPeriodAllowsTimeEntryEdits(period) {
|
|
171
|
+
const result = this.validatePeriodEditable(period);
|
|
172
|
+
if (!result.valid) {
|
|
173
|
+
throw new Error(result.issues[0]?.message ?? 'This timesheet period cannot be edited.');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
assertCanSubmit(period, entries = [], policy) {
|
|
177
|
+
const result = this.validateSubmissionCompleteness(period, entries, policy);
|
|
178
|
+
if (!result.valid) {
|
|
179
|
+
throw new Error(result.issues[0]?.message ?? 'Timesheet period cannot be submitted.');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
assertCanApprove(period) {
|
|
183
|
+
if (period.statusId !== AXPSystemStatusType.WaitingApproval) {
|
|
184
|
+
throw new Error('Only submitted periods can be approved.');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
assertCanReject(period) {
|
|
188
|
+
if (period.statusId !== AXPSystemStatusType.WaitingApproval) {
|
|
189
|
+
throw new Error('Only submitted periods can be rejected.');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
assertCanReopen(period) {
|
|
193
|
+
if (period.statusId !== AXPSystemStatusType.Rejected) {
|
|
194
|
+
throw new Error('Only rejected periods can be reopened.');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
assertCanLock(period) {
|
|
198
|
+
if (period.statusId !== AXPSystemStatusType.Approved) {
|
|
199
|
+
throw new Error('Only approved periods can be locked.');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
assertCanAdminAdjust(period) {
|
|
203
|
+
const isLocked = AXMTimesheetPeriodLockedStatusIds.includes(period.statusId);
|
|
204
|
+
if (!isLocked && period.statusId !== AXPSystemStatusType.Approved) {
|
|
205
|
+
throw new Error('Only approved or locked periods can be adjusted by an administrator.');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region ---- Period Resolution ----
|
|
210
|
+
/**
|
|
211
|
+
* Finds an existing open draft period or creates a new draft period for the employee.
|
|
212
|
+
*/
|
|
213
|
+
async getOrCreateDraftPeriod(input) {
|
|
214
|
+
const periodAccessor = this.entityService
|
|
215
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)
|
|
216
|
+
.data();
|
|
217
|
+
const existing = await periodAccessor.query({
|
|
218
|
+
skip: 0,
|
|
219
|
+
take: 1,
|
|
220
|
+
filter: {
|
|
221
|
+
logic: 'and',
|
|
222
|
+
filters: [
|
|
223
|
+
{ field: 'employeeId', operator: { type: 'equal' }, value: input.employeeId },
|
|
224
|
+
{ field: 'periodType', operator: { type: 'equal' }, value: input.periodType },
|
|
225
|
+
{ field: 'startDate', operator: { type: 'equal' }, value: input.startDate },
|
|
226
|
+
{ field: 'endDate', operator: { type: 'equal' }, value: input.endDate },
|
|
227
|
+
{
|
|
228
|
+
field: 'statusId',
|
|
229
|
+
operator: { type: 'in' },
|
|
230
|
+
value: [...AXMTimesheetPeriodOpenStatusIds],
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
const match = get(existing, 'items[0]');
|
|
236
|
+
if (!isNil(match)) {
|
|
237
|
+
return match;
|
|
238
|
+
}
|
|
239
|
+
const createdId = await periodAccessor.create({
|
|
240
|
+
employeeId: input.employeeId,
|
|
241
|
+
periodType: input.periodType,
|
|
242
|
+
startDate: input.startDate,
|
|
243
|
+
endDate: input.endDate,
|
|
244
|
+
timezone: input.timezone,
|
|
245
|
+
statusId: AXPSystemStatusType.Draft,
|
|
246
|
+
totalSeconds: 0,
|
|
247
|
+
});
|
|
248
|
+
const created = await periodAccessor.byKey(createdId);
|
|
249
|
+
if (isNil(created)) {
|
|
250
|
+
throw new Error('Failed to load the newly created draft timesheet period.');
|
|
251
|
+
}
|
|
252
|
+
return created;
|
|
253
|
+
}
|
|
254
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTimesheetValidationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
255
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTimesheetValidationService, providedIn: 'root' }); }
|
|
256
|
+
}
|
|
257
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTimesheetValidationService, decorators: [{
|
|
258
|
+
type: Injectable,
|
|
259
|
+
args: [{ providedIn: 'root' }]
|
|
260
|
+
}] });
|
|
261
|
+
|
|
262
|
+
export { AXMTimesheetValidationService as A };
|
|
263
|
+
//# sourceMappingURL=acorex-platform-module-timesheet-management-client-timesheet-validation.service-DMrJn3HU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-platform-module-timesheet-management-client-timesheet-validation.service-DMrJn3HU.mjs","sources":["../../../../libs/modules/timesheet-management/client/src/lib/features/timesheet-period/timesheet-validation.service.ts"],"sourcesContent":["//#region ---- Imports ----\n\nimport { AXPSystemStatusType } from '@acorex-platform/framework-shared/core';\nimport { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';\nimport { inject, Injectable } from '@angular/core';\nimport { defaultTo, get, isEmpty, isNil } from 'lodash';\nimport {\n AXMTimesheetPeriodLockedStatusIds,\n AXMTimesheetPeriodOpenStatusIds,\n RootConfig,\n} from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementTimeEntryEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type {\n AXMTimesheetManagementTimesheetPeriodEntityModel,\n AXMTimesheetPeriodType,\n} from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementTimesheetPolicyEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\n\n//#endregion\n\n//#region ---- Types ----\n\nexport interface AXMTimesheetValidationIssue {\n code: string;\n message: string;\n field?: string;\n}\n\nexport interface AXMTimesheetValidationResult {\n valid: boolean;\n issues: AXMTimesheetValidationIssue[];\n}\n\nexport interface AXMTimesheetGetOrCreateDraftPeriodInput {\n employeeId: string;\n periodType: AXMTimesheetPeriodType;\n startDate: string;\n endDate: string;\n timezone: string;\n}\n\n//#endregion\n\n//#region ---- Timesheet Validation Service ----\n\n/**\n * Domain validation service for timesheet period and time entry business rules.\n */\n@Injectable({ providedIn: 'root' })\nexport class AXMTimesheetValidationService {\n //#region ---- Services & Dependencies ----\n\n private readonly entityService = inject(AXPEntityService);\n\n //#endregion\n\n //#region ---- Entry Validation ----\n\n /**\n * Validates that a time entry date falls within policy and period constraints.\n */\n validateEntryDates(\n entry: Pick<AXMTimesheetManagementTimeEntryEntityModel, 'entryDate' | 'startedAt' | 'endedAt'>,\n period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'startDate' | 'endDate'>,\n policy?: Pick<AXMTimesheetManagementTimesheetPolicyEntityModel, 'allowFutureDates'>,\n ): AXMTimesheetValidationResult {\n const issues: AXMTimesheetValidationIssue[] = [];\n const entryDate = entry.entryDate?.slice(0, 10);\n const periodStart = period.startDate?.slice(0, 10);\n const periodEnd = period.endDate?.slice(0, 10);\n\n if (entryDate && periodStart && entryDate < periodStart) {\n issues.push({\n code: 'entry-before-period',\n field: 'entryDate',\n message: 'Entry date is before the period start date.',\n });\n }\n\n if (entryDate && periodEnd && entryDate > periodEnd) {\n issues.push({\n code: 'entry-after-period',\n field: 'entryDate',\n message: 'Entry date is after the period end date.',\n });\n }\n\n if (!defaultTo(policy?.allowFutureDates, false)) {\n const today = new Date().toISOString().slice(0, 10);\n if (entryDate && entryDate > today) {\n issues.push({\n code: 'future-entry-date',\n field: 'entryDate',\n message: 'Future entry dates are not allowed by the active policy.',\n });\n }\n }\n\n if (entry.startedAt && entry.endedAt) {\n const started = Date.parse(entry.startedAt);\n const ended = Date.parse(entry.endedAt);\n if (!Number.isNaN(started) && !Number.isNaN(ended) && ended < started) {\n issues.push({\n code: 'ended-before-started',\n field: 'endedAt',\n message: 'End time must be after start time.',\n });\n }\n }\n\n return { valid: isEmpty(issues), issues };\n }\n\n /**\n * Validates that a time entry does not overlap existing entries for the same employee.\n */\n validateNoOverlap(\n entry: Pick<AXMTimesheetManagementTimeEntryEntityModel, 'id' | 'employeeId' | 'startedAt' | 'endedAt'>,\n existingEntries: Array<Pick<AXMTimesheetManagementTimeEntryEntityModel, 'id' | 'employeeId' | 'startedAt' | 'endedAt'>>,\n policy?: Pick<AXMTimesheetManagementTimesheetPolicyEntityModel, 'overlapPolicy'>,\n ): AXMTimesheetValidationResult {\n const issues: AXMTimesheetValidationIssue[] = [];\n const overlapPolicy = defaultTo(policy?.overlapPolicy, 'reject');\n\n if (!entry.startedAt || !entry.endedAt) {\n return { valid: true, issues };\n }\n\n const start = Date.parse(entry.startedAt);\n const end = Date.parse(entry.endedAt);\n if (Number.isNaN(start) || Number.isNaN(end)) {\n return { valid: true, issues };\n }\n\n const overlapping = existingEntries.filter((candidate) => {\n if (candidate.id === entry.id || candidate.employeeId !== entry.employeeId) {\n return false;\n }\n if (!candidate.startedAt || !candidate.endedAt) {\n return false;\n }\n const candidateStart = Date.parse(candidate.startedAt);\n const candidateEnd = Date.parse(candidate.endedAt);\n if (Number.isNaN(candidateStart) || Number.isNaN(candidateEnd)) {\n return false;\n }\n return start < candidateEnd && end > candidateStart;\n });\n\n if (!isEmpty(overlapping)) {\n issues.push({\n code: overlapPolicy === 'warn' ? 'entry-overlap-warning' : 'entry-overlap',\n field: 'startedAt',\n message:\n overlapPolicy === 'warn'\n ? 'This entry overlaps another entry for the same employee.'\n : 'Overlapping time entries are not allowed.',\n });\n }\n\n return {\n valid: overlapPolicy === 'warn' ? true : isEmpty(issues),\n issues,\n };\n }\n\n //#endregion\n\n //#region ---- Period Validation ----\n\n /**\n * Validates that a timesheet period can still be edited.\n */\n validatePeriodEditable(\n period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>,\n ): AXMTimesheetValidationResult {\n const statusId = period.statusId;\n const isLocked = (AXMTimesheetPeriodLockedStatusIds as readonly string[]).includes(statusId);\n\n if (isLocked) {\n return {\n valid: false,\n issues: [\n {\n code: 'period-locked',\n field: 'statusId',\n message: 'This timesheet period is locked and cannot be edited.',\n },\n ],\n };\n }\n\n return { valid: true, issues: [] };\n }\n\n /**\n * Validates that a period is complete enough for submission.\n */\n validateSubmissionCompleteness(\n period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId' | 'totalSeconds'>,\n entries: Array<Pick<AXMTimesheetManagementTimeEntryEntityModel, 'description'>>,\n policy?: Pick<AXMTimesheetManagementTimesheetPolicyEntityModel, 'requireDescription'>,\n ): AXMTimesheetValidationResult {\n const issues: AXMTimesheetValidationIssue[] = [];\n\n if (period.statusId !== AXPSystemStatusType.Draft) {\n issues.push({\n code: 'period-not-draft',\n field: 'statusId',\n message: 'Only draft periods can be submitted.',\n });\n }\n\n if (isEmpty(entries)) {\n issues.push({\n code: 'no-entries',\n message: 'At least one time entry is required before submission.',\n });\n }\n\n if (defaultTo(policy?.requireDescription, false)) {\n const missingDescription = entries.some((entry) => isEmpty(get(entry, 'description')));\n if (missingDescription) {\n issues.push({\n code: 'missing-description',\n field: 'description',\n message: 'All time entries must include a description before submission.',\n });\n }\n }\n\n const totalSeconds = defaultTo(period.totalSeconds, 0);\n if (totalSeconds <= 0 && !isEmpty(entries)) {\n issues.push({\n code: 'zero-total',\n field: 'totalSeconds',\n message: 'Submitted periods must have a positive total duration.',\n });\n }\n\n return { valid: isEmpty(issues), issues };\n }\n\n //#endregion\n\n //#region ---- Assertion Helpers ----\n\n assertPeriodAllowsTimeEntryEdits(\n period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>,\n ): void {\n const result = this.validatePeriodEditable(period);\n if (!result.valid) {\n throw new Error(result.issues[0]?.message ?? 'This timesheet period cannot be edited.');\n }\n }\n\n assertCanSubmit(\n period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId' | 'totalSeconds'>,\n entries: Array<Pick<AXMTimesheetManagementTimeEntryEntityModel, 'description'>> = [],\n policy?: Pick<AXMTimesheetManagementTimesheetPolicyEntityModel, 'requireDescription'>,\n ): void {\n const result = this.validateSubmissionCompleteness(period, entries, policy);\n if (!result.valid) {\n throw new Error(result.issues[0]?.message ?? 'Timesheet period cannot be submitted.');\n }\n }\n\n assertCanApprove(period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>): void {\n if (period.statusId !== AXPSystemStatusType.WaitingApproval) {\n throw new Error('Only submitted periods can be approved.');\n }\n }\n\n assertCanReject(period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>): void {\n if (period.statusId !== AXPSystemStatusType.WaitingApproval) {\n throw new Error('Only submitted periods can be rejected.');\n }\n }\n\n assertCanReopen(period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>): void {\n if (period.statusId !== AXPSystemStatusType.Rejected) {\n throw new Error('Only rejected periods can be reopened.');\n }\n }\n\n assertCanLock(period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>): void {\n if (period.statusId !== AXPSystemStatusType.Approved) {\n throw new Error('Only approved periods can be locked.');\n }\n }\n\n assertCanAdminAdjust(period: Pick<AXMTimesheetManagementTimesheetPeriodEntityModel, 'statusId'>): void {\n const isLocked = (AXMTimesheetPeriodLockedStatusIds as readonly string[]).includes(period.statusId);\n if (!isLocked && period.statusId !== AXPSystemStatusType.Approved) {\n throw new Error('Only approved or locked periods can be adjusted by an administrator.');\n }\n }\n\n //#endregion\n\n //#region ---- Period Resolution ----\n\n /**\n * Finds an existing open draft period or creates a new draft period for the employee.\n */\n async getOrCreateDraftPeriod(\n input: AXMTimesheetGetOrCreateDraftPeriodInput,\n ): Promise<AXMTimesheetManagementTimesheetPeriodEntityModel> {\n const periodAccessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)\n .data<string, AXMTimesheetManagementTimesheetPeriodEntityModel>();\n\n const existing = await periodAccessor.query({\n skip: 0,\n take: 1,\n filter: {\n logic: 'and',\n filters: [\n { field: 'employeeId', operator: { type: 'equal' }, value: input.employeeId },\n { field: 'periodType', operator: { type: 'equal' }, value: input.periodType },\n { field: 'startDate', operator: { type: 'equal' }, value: input.startDate },\n { field: 'endDate', operator: { type: 'equal' }, value: input.endDate },\n {\n field: 'statusId',\n operator: { type: 'in' },\n value: [...AXMTimesheetPeriodOpenStatusIds],\n },\n ],\n },\n });\n\n const match = get(existing, 'items[0]') as AXMTimesheetManagementTimesheetPeriodEntityModel | undefined;\n if (!isNil(match)) {\n return match;\n }\n\n const createdId = await periodAccessor.create({\n employeeId: input.employeeId,\n periodType: input.periodType,\n startDate: input.startDate,\n endDate: input.endDate,\n timezone: input.timezone,\n statusId: AXPSystemStatusType.Draft,\n totalSeconds: 0,\n });\n\n const created = await periodAccessor.byKey(createdId);\n if (isNil(created)) {\n throw new Error('Failed to load the newly created draft timesheet period.');\n }\n\n return created;\n }\n\n //#endregion\n}\n\n//#endregion\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, Injectable } from '@angular/core';
|
|
4
|
+
import { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';
|
|
5
|
+
import { A as AXMTimesheetValidationService } from './acorex-platform-module-timesheet-management-client-timesheet-validation.service-DMrJn3HU.mjs';
|
|
6
|
+
|
|
7
|
+
//#endregion
|
|
8
|
+
/**
|
|
9
|
+
* Updates a time entry after validating the parent timesheet period is editable.
|
|
10
|
+
*/
|
|
11
|
+
class UpdateTimeEntryCommand {
|
|
12
|
+
constructor() {
|
|
13
|
+
//#region ---- Services & Dependencies ----
|
|
14
|
+
this.entityService = inject(AXPEntityService);
|
|
15
|
+
this.validationService = inject(AXMTimesheetValidationService);
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region ---- Command Implementation ----
|
|
19
|
+
async execute(input) {
|
|
20
|
+
try {
|
|
21
|
+
const dataAccessor = this.entityService
|
|
22
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.timeEntry.name)
|
|
23
|
+
.data();
|
|
24
|
+
const existing = await dataAccessor.byKey(input.id);
|
|
25
|
+
if (!existing) {
|
|
26
|
+
return { success: false, message: { text: 'Time entry not found.' } };
|
|
27
|
+
}
|
|
28
|
+
const periodId = input.data.periodId ?? existing.periodId;
|
|
29
|
+
await this.assertPeriodEditable(periodId);
|
|
30
|
+
const updated = await dataAccessor.update(input.id, input.data);
|
|
31
|
+
return { success: true, kind: 'object', data: updated };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : 'Failed to update time entry.';
|
|
35
|
+
console.error('[UpdateTimeEntryCommand] Error:', error);
|
|
36
|
+
return { success: false, message: { text: message } };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region ---- Private helpers ----
|
|
41
|
+
async assertPeriodEditable(periodId) {
|
|
42
|
+
const periodAccessor = this.entityService
|
|
43
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)
|
|
44
|
+
.data();
|
|
45
|
+
const period = await periodAccessor.byKey(periodId);
|
|
46
|
+
if (!period) {
|
|
47
|
+
throw new Error('Timesheet period not found.');
|
|
48
|
+
}
|
|
49
|
+
this.validationService.assertPeriodAllowsTimeEntryEdits(period);
|
|
50
|
+
}
|
|
51
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UpdateTimeEntryCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
52
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UpdateTimeEntryCommand, providedIn: 'root' }); }
|
|
53
|
+
}
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UpdateTimeEntryCommand, decorators: [{
|
|
55
|
+
type: Injectable,
|
|
56
|
+
args: [{ providedIn: 'root' }]
|
|
57
|
+
}] });
|
|
58
|
+
|
|
59
|
+
export { UpdateTimeEntryCommand };
|
|
60
|
+
//# sourceMappingURL=acorex-platform-module-timesheet-management-client-update-time-entry.command-Do6s9OrI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-platform-module-timesheet-management-client-update-time-entry.command-Do6s9OrI.mjs","sources":["../../../../libs/modules/timesheet-management/client/src/lib/features/time-entry/commands/update-time-entry.command.ts"],"sourcesContent":["import { AXPCommand, type AXPCommandExecuteResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport { AXPRuntimeCommandResult } from '@acorex-platform/framework-shared/core';\nimport { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';\n\nimport { Injectable, inject } from '@angular/core';\nimport { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementTimeEntryEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementTimesheetPeriodEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport { AXMTimesheetValidationService } from '../../timesheet-period/timesheet-validation.service';\n\n//#region ---- Types ----\n\nexport interface UpdateTimeEntryInput {\n id: string;\n data: Partial<Omit<AXMTimesheetManagementTimeEntryEntityModel, 'id'>>;\n}\n\n//#endregion\n\n/**\n * Updates a time entry after validating the parent timesheet period is editable.\n */\n@Injectable({ providedIn: 'root' })\nexport class UpdateTimeEntryCommand implements AXPCommand<UpdateTimeEntryInput, AXMTimesheetManagementTimeEntryEntityModel> {\n //#region ---- Services & Dependencies ----\n\n private readonly entityService = inject(AXPEntityService);\n private readonly validationService = inject(AXMTimesheetValidationService);\n\n //#endregion\n\n //#region ---- Command Implementation ----\n\n async execute(\n input: UpdateTimeEntryInput,\n ): AXPCommandExecuteResultPromise<AXMTimesheetManagementTimeEntryEntityModel> {\n try {\n const dataAccessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.timeEntry.name)\n .data<string, AXMTimesheetManagementTimeEntryEntityModel>();\n\n const existing = await dataAccessor.byKey(input.id);\n if (!existing) {\n return { success: false, message: { text: 'Time entry not found.' } };\n }\n\n const periodId = input.data.periodId ?? existing.periodId;\n await this.assertPeriodEditable(periodId);\n\n const updated = await dataAccessor.update(input.id, input.data);\n return { success: true, kind: 'object', data: updated };\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : 'Failed to update time entry.';\n console.error('[UpdateTimeEntryCommand] Error:', error);\n return { success: false, message: { text: message } };\n }\n }\n\n //#endregion\n\n //#region ---- Private helpers ----\n\n private async assertPeriodEditable(periodId: string): Promise<void> {\n const periodAccessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.timesheetPeriod.name)\n .data<string, AXMTimesheetManagementTimesheetPeriodEntityModel>();\n\n const period = await periodAccessor.byKey(periodId);\n if (!period) {\n throw new Error('Timesheet period not found.');\n }\n this.validationService.assertPeriodAllowsTimeEntryEdits(period);\n }\n\n //#endregion\n}\n"],"names":[],"mappings":";;;;;;AAiBA;AAEA;;AAEG;MAEU,sBAAsB,CAAA;AADnC,IAAA,WAAA,GAAA;;AAImB,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACxC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,6BAA6B,CAAC;AAgD3E,IAAA;;;IA1CC,MAAM,OAAO,CACX,KAA2B,EAAA;AAE3B,QAAA,IAAI;AACF,YAAA,MAAM,YAAY,GAAG,IAAI,CAAC;AACvB,iBAAA,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI;AACrE,iBAAA,IAAI,EAAsD;YAE7D,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,QAAQ,EAAE;AACb,gBAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,uBAAuB,EAAE,EAAE;YACvE;YAEA,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;AACzD,YAAA,MAAM,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC;AAEzC,YAAA,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC;AAC/D,YAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;QACzD;QAAE,OAAO,KAAc,EAAE;AACvB,YAAA,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,8BAA8B;AACvF,YAAA,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC;AACvD,YAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QACvD;IACF;;;IAMQ,MAAM,oBAAoB,CAAC,QAAgB,EAAA;AACjD,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC;AACzB,aAAA,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI;AAC3E,aAAA,IAAI,EAA4D;QAEnE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC;QACnD,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC;QAChD;AACA,QAAA,IAAI,CAAC,iBAAiB,CAAC,gCAAgC,CAAC,MAAM,CAAC;IACjE;8GAjDW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAtB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cADT,MAAM,EAAA,CAAA,CAAA;;2FACnB,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBADlC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { resolveMultiLanguageString } from '@acorex/core/translation';
|
|
2
|
+
import { runtimeQuerySuccessCollection, runtimeQueryFailure } from '@acorex-platform/framework-shared/core';
|
|
3
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { inject, Injectable } from '@angular/core';
|
|
6
|
+
import { isEmpty } from 'lodash';
|
|
7
|
+
import { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
/**
|
|
11
|
+
* Searches work items for timesheet entry pickers.
|
|
12
|
+
*/
|
|
13
|
+
class AXMWorkItemSearchQuery {
|
|
14
|
+
constructor() {
|
|
15
|
+
//#region ---- Services & Dependencies ----
|
|
16
|
+
this.entityService = inject(AXPEntityService);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region ---- Query Execution ----
|
|
20
|
+
async fetch(input) {
|
|
21
|
+
try {
|
|
22
|
+
const opts = input ?? {};
|
|
23
|
+
const workItemAccessor = this.entityService
|
|
24
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.workItem.name)
|
|
25
|
+
.data();
|
|
26
|
+
const filters = [];
|
|
27
|
+
if (opts.employeeId) {
|
|
28
|
+
filters.push({ field: 'employeeId', operator: { type: 'equal' }, value: opts.employeeId });
|
|
29
|
+
}
|
|
30
|
+
if (opts.isActive != null) {
|
|
31
|
+
filters.push({ field: 'isActive', operator: { type: 'equal' }, value: opts.isActive });
|
|
32
|
+
}
|
|
33
|
+
if (!isEmpty(opts.searchText?.trim())) {
|
|
34
|
+
filters.push({
|
|
35
|
+
field: 'code',
|
|
36
|
+
operator: { type: 'contains' },
|
|
37
|
+
value: opts.searchText.trim(),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const result = await workItemAccessor.query({
|
|
41
|
+
skip: opts.skip ?? 0,
|
|
42
|
+
take: opts.take ?? 25,
|
|
43
|
+
sort: [{ field: 'code', dir: 'asc' }],
|
|
44
|
+
...(filters.length ? { filter: { logic: 'and', filters } } : {}),
|
|
45
|
+
});
|
|
46
|
+
const items = result.items.map((row) => ({
|
|
47
|
+
id: row.id,
|
|
48
|
+
code: row.code,
|
|
49
|
+
title: resolveMultiLanguageString(row.title, 'en-US'),
|
|
50
|
+
sourceType: row.sourceType,
|
|
51
|
+
isBillableDefault: row.isBillableDefault,
|
|
52
|
+
}));
|
|
53
|
+
return runtimeQuerySuccessCollection({ items, total: result.total });
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return runtimeQueryFailure(error instanceof Error ? error.message : 'Failed to search work items.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMWorkItemSearchQuery, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
60
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMWorkItemSearchQuery, providedIn: 'root' }); }
|
|
61
|
+
}
|
|
62
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMWorkItemSearchQuery, decorators: [{
|
|
63
|
+
type: Injectable,
|
|
64
|
+
args: [{ providedIn: 'root' }]
|
|
65
|
+
}] });
|
|
66
|
+
|
|
67
|
+
export { AXMWorkItemSearchQuery };
|
|
68
|
+
//# sourceMappingURL=acorex-platform-module-timesheet-management-client-work-item-search.query-BA2kvF-S.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-platform-module-timesheet-management-client-work-item-search.query-BA2kvF-S.mjs","sources":["../../../../libs/modules/timesheet-management/client/src/lib/features/reporting/queries/work-item-search.query.ts"],"sourcesContent":["import { AXPQuery, type AXPQueryFetchResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport type { AXDataSourceFilterOption } from '@acorex/cdk/common';\nimport { resolveMultiLanguageString } from '@acorex/core/translation';\nimport {\n runtimeQueryFailure,\n runtimeQuerySuccessCollection,\n type AXPRuntimeQueryResult,\n} from '@acorex-platform/framework-shared/core';\nimport { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';\n\nimport { Injectable, inject } from '@angular/core';\nimport { isEmpty } from 'lodash';\nimport { RootConfig } from '@acorex-platform/module-timesheet-management-client/contracts';\nimport type { AXMTimesheetManagementWorkItemEntityModel } from '@acorex-platform/module-timesheet-management-client/contracts';\n\n//#region ---- Types ----\n\nexport interface AXMWorkItemSearchQueryInput {\n searchText?: string;\n employeeId?: string;\n isActive?: boolean;\n skip?: number;\n take?: number;\n}\n\nexport interface AXMWorkItemSearchQueryItem {\n id: string;\n code: string;\n title: string;\n sourceType: string;\n isBillableDefault: boolean;\n}\n\n//#endregion\n\n/**\n * Searches work items for timesheet entry pickers.\n */\n@Injectable({ providedIn: 'root' })\nexport class AXMWorkItemSearchQuery\n implements AXPQuery<AXMWorkItemSearchQueryInput, AXMWorkItemSearchQueryItem>\n{\n //#region ---- Services & Dependencies ----\n\n private readonly entityService = inject(AXPEntityService);\n\n //#endregion\n\n //#region ---- Query Execution ----\n\n async fetch(\n input?: AXMWorkItemSearchQueryInput | null,\n ): AXPQueryFetchResultPromise<AXMWorkItemSearchQueryItem> {\n try {\n const opts = input ?? {};\n const workItemAccessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.workItem.name)\n .data<string, AXMTimesheetManagementWorkItemEntityModel>();\n\n const filters: AXDataSourceFilterOption[] = [];\n if (opts.employeeId) {\n filters.push({ field: 'employeeId', operator: { type: 'equal' }, value: opts.employeeId });\n }\n if (opts.isActive != null) {\n filters.push({ field: 'isActive', operator: { type: 'equal' }, value: opts.isActive });\n }\n if (!isEmpty(opts.searchText?.trim())) {\n filters.push({\n field: 'code',\n operator: { type: 'contains' },\n value: opts.searchText!.trim(),\n });\n }\n\n const result = await workItemAccessor.query({\n skip: opts.skip ?? 0,\n take: opts.take ?? 25,\n sort: [{ field: 'code', dir: 'asc' }],\n ...(filters.length ? { filter: { logic: 'and', filters } } : {}),\n });\n\n const items = result.items.map((row) => ({\n id: row.id,\n code: row.code,\n title: resolveMultiLanguageString(row.title, 'en-US'),\n sourceType: row.sourceType,\n isBillableDefault: row.isBillableDefault,\n }));\n\n return runtimeQuerySuccessCollection({ items, total: result.total });\n } catch (error) {\n return runtimeQueryFailure(\n error instanceof Error ? error.message : 'Failed to search work items.',\n );\n }\n }\n\n //#endregion\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { runtimeQueryPayloadData, runtimeQueryFailure, runtimeQuerySuccessObject } from '@acorex-platform/framework-shared/core';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, Injectable } from '@angular/core';
|
|
4
|
+
import { AXMCompareAttendanceVsTimesheetQuery } from './acorex-platform-module-timesheet-management-client-compare-attendance-vs-timesheet.query-ZZym5nSx.mjs';
|
|
5
|
+
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region ---- Query ----
|
|
8
|
+
/**
|
|
9
|
+
* Returns only dates where attendance vs timesheet variance exceeds the threshold.
|
|
10
|
+
*/
|
|
11
|
+
class AXMWorkforceExceptionReportQuery {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.compareQuery = inject(AXMCompareAttendanceVsTimesheetQuery);
|
|
14
|
+
}
|
|
15
|
+
async fetch(input) {
|
|
16
|
+
const result = await this.compareQuery.fetch(input);
|
|
17
|
+
const payload = runtimeQueryPayloadData(result);
|
|
18
|
+
if (!payload) {
|
|
19
|
+
return runtimeQueryFailure(result.message ?? 'Failed to load workforce exception report.');
|
|
20
|
+
}
|
|
21
|
+
const exceptions = payload.rows
|
|
22
|
+
.filter((row) => row.exceedsThreshold)
|
|
23
|
+
.map((row) => ({
|
|
24
|
+
date: row.date,
|
|
25
|
+
attendanceWorkedSeconds: row.attendanceWorkedSeconds,
|
|
26
|
+
timesheetLoggedSeconds: row.timesheetLoggedSeconds,
|
|
27
|
+
varianceSeconds: row.varianceSeconds,
|
|
28
|
+
}));
|
|
29
|
+
return runtimeQuerySuccessObject({ exceptions });
|
|
30
|
+
}
|
|
31
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMWorkforceExceptionReportQuery, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
32
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMWorkforceExceptionReportQuery, providedIn: 'root' }); }
|
|
33
|
+
}
|
|
34
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMWorkforceExceptionReportQuery, decorators: [{
|
|
35
|
+
type: Injectable,
|
|
36
|
+
args: [{ providedIn: 'root' }]
|
|
37
|
+
}] });
|
|
38
|
+
|
|
39
|
+
export { AXMWorkforceExceptionReportQuery };
|
|
40
|
+
//# sourceMappingURL=acorex-platform-module-timesheet-management-client-workforce-exception-report.query-0q-AITic.mjs.map
|