@simitgroup/simpleapp-generator 1.0.32 → 1.0.35
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/.vscode/settings.json +3 -0
- package/README.md +185 -16
- package/buildinschemas copy/autoincreament.autoinc.jsonschema.json +39 -0
- package/buildinschemas copy/branch.branch.jsonschema.json +41 -0
- package/buildinschemas copy/docnoformat.docno.jsonschema.json +41 -0
- package/buildinschemas copy/organization.org.jsonschema.json +50 -0
- package/buildinschemas copy/permission.perm.jsonschema.json +23 -0
- package/buildinschemas copy/permission.perm.jsonschema.try.json +25 -0
- package/buildinschemas copy/tenant.tenant.jsonschema.json +21 -0
- package/buildinschemas copy/tenant.tenant.jsonschema.try.json +27 -0
- package/buildinschemas copy/user.user.jsonschema.json +31 -0
- package/dist/buildinschemas/autoincreament.d.ts +3 -0
- package/dist/buildinschemas/autoincreament.d.ts.map +1 -0
- package/dist/buildinschemas/autoincreament.js +36 -0
- package/dist/buildinschemas/autoincreament.js.map +1 -0
- package/dist/buildinschemas/branch.d.ts +3 -0
- package/dist/buildinschemas/branch.d.ts.map +1 -0
- package/dist/buildinschemas/branch.js +41 -0
- package/dist/buildinschemas/branch.js.map +1 -0
- package/dist/buildinschemas/docnoformat.d.ts +3 -0
- package/dist/buildinschemas/docnoformat.d.ts.map +1 -0
- package/dist/buildinschemas/docnoformat.js +60 -0
- package/dist/buildinschemas/docnoformat.js.map +1 -0
- package/dist/buildinschemas/index.d.ts +8 -0
- package/dist/buildinschemas/index.d.ts.map +1 -0
- package/dist/buildinschemas/index.js +18 -0
- package/dist/buildinschemas/index.js.map +1 -0
- package/dist/buildinschemas/organization.d.ts +3 -0
- package/dist/buildinschemas/organization.d.ts.map +1 -0
- package/dist/buildinschemas/organization.js +34 -0
- package/dist/buildinschemas/organization.js.map +1 -0
- package/dist/buildinschemas/permission.d.ts +3 -0
- package/dist/buildinschemas/permission.d.ts.map +1 -0
- package/dist/buildinschemas/permission.js +34 -0
- package/dist/buildinschemas/permission.js.map +1 -0
- package/dist/buildinschemas/tenant.d.ts +3 -0
- package/dist/buildinschemas/tenant.d.ts.map +1 -0
- package/dist/buildinschemas/tenant.js +41 -0
- package/dist/buildinschemas/tenant.js.map +1 -0
- package/dist/buildinschemas/user.d.ts +3 -0
- package/dist/buildinschemas/user.d.ts.map +1 -0
- package/dist/buildinschemas/user.js +31 -0
- package/dist/buildinschemas/user.js.map +1 -0
- package/dist/constant.d.ts +4 -0
- package/dist/constant.d.ts.map +1 -0
- package/dist/constant.js +2 -1
- package/dist/constant.js.map +1 -1
- package/dist/framework.d.ts +10 -0
- package/dist/framework.d.ts.map +1 -0
- package/dist/framework.js +120 -68
- package/dist/framework.js.map +1 -1
- package/dist/generate-allow-changebackend.js +305 -0
- package/dist/generate-allow-changebackend.js.map +1 -0
- package/dist/generate.d.ts +2 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +310 -230
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -20
- package/dist/index.js.map +1 -1
- package/dist/libs.d.ts +2 -0
- package/dist/libs.d.ts.map +1 -0
- package/dist/processors/groupsbuilder.js +2 -0
- package/dist/processors/groupsbuilder.js.map +1 -0
- package/dist/processors/jsonschemabuilder.d.ts +4 -0
- package/dist/processors/jsonschemabuilder.d.ts.map +1 -0
- package/dist/processors/jsonschemabuilder.js +146 -172
- package/dist/processors/jsonschemabuilder.js.map +1 -1
- package/dist/schematype/baseschema.js +25 -0
- package/dist/schematype/baseschema.js.map +1 -0
- package/dist/schematype/default.js +2 -0
- package/dist/schematype/default.js.map +1 -0
- package/dist/schematype/index.js +12 -0
- package/dist/schematype/index.js.map +1 -0
- package/dist/schematype/primarymasterdata.js +38 -0
- package/dist/schematype/primarymasterdata.js.map +1 -0
- package/dist/schematype/simple.js +24 -0
- package/dist/schematype/simple.js.map +1 -0
- package/dist/schematype/simplemasterdata.js +31 -0
- package/dist/schematype/simplemasterdata.js.map +1 -0
- package/dist/schematype/transaction.js +74 -0
- package/dist/schematype/transaction.js.map +1 -0
- package/dist/storage.d.ts +3 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +2 -2
- package/dist/storage.js.map +1 -1
- package/dist/type.d.ts +164 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/type.js +16 -1
- package/dist/type.js.map +1 -1
- package/dist/validation.d.ts +1 -0
- package/dist/validation.d.ts.map +1 -0
- package/documentation/designconcept.bpmn +349 -0
- package/documentation/documentation.png +0 -0
- package/documentation/infra.drawio +141 -0
- package/documentation/infra.png +0 -0
- package/documentation/management.drawio +57 -0
- package/documentation/stack.drawio +106 -0
- package/package.json +3 -1
- package/src/buildinschemas/autoincreament.ts +34 -0
- package/src/buildinschemas/branch.ts +39 -0
- package/src/buildinschemas/docnoformat.ts +58 -0
- package/src/buildinschemas/index.ts +7 -0
- package/src/buildinschemas/organization.ts +31 -0
- package/src/buildinschemas/permission.ts +31 -0
- package/src/buildinschemas/tenant.ts +38 -0
- package/src/buildinschemas/user.ts +28 -0
- package/src/constant.ts +2 -1
- package/src/framework.ts +126 -67
- package/src/generate.ts +327 -266
- package/src/generate.ts.backup +339 -0
- package/src/index.ts +93 -18
- package/src/processors/jsonschemabuilder.ts +199 -226
- package/src/processors/jsonschemabuilder.ts-old +383 -0
- package/src/storage.ts +1 -1
- package/src/type.ts +94 -27
- package/templates/basic/nest/controller.ts.eta +255 -0
- package/templates/basic/nest/default.ts.eta +42 -0
- package/templates/basic/{model.eta → nest/model.ts.eta} +18 -5
- package/templates/basic/nest/processor.ts.eta +129 -0
- package/templates/basic/nest/service.ts.eta +64 -0
- package/templates/basic/{type.eta → nest/type.ts.eta} +3 -3
- package/templates/basic/nuxt/default.ts.eta +42 -0
- package/templates/basic/{pageindex.vue.eta → nuxt/pages.crud.vue.eta} +85 -22
- package/templates/basic/nuxt/simpleapp.doc.ts.eta +11 -0
- package/templates/basic/nuxt/simpleapp.generate.client.ts.eta +212 -0
- package/templates/nest/.env.eta +31 -0
- package/templates/nest/.gitignore.eta +40 -0
- package/templates/nest/src/app.controller.ts.eta +19 -0
- package/templates/nest/src/app.module.ts.eta +77 -0
- package/templates/nest/src/app.service.ts.eta +9 -0
- package/templates/nest/src/main.ts.eta +58 -0
- package/templates/nest/src/simpleapp/generate/apischemas/index.ts.eta +16 -0
- package/templates/nest/src/simpleapp/generate/commons/decorators/appuser.decorator.ts.eta +8 -0
- package/templates/nest/src/simpleapp/generate/commons/dicts/foreignkeys.ts.eta +1 -0
- package/templates/nest/src/simpleapp/generate/commons/docnogenerator.service.ts.eta +101 -0
- package/templates/nest/src/simpleapp/generate/commons/exceptions/SimpleAppExceptionFilter.ts.eta +39 -0
- package/templates/nest/src/simpleapp/generate/commons/interceptors/response.interceptor.ts.eta +38 -0
- package/templates/nest/src/simpleapp/generate/commons/middlewares/tenant.middleware.ts.eta +88 -0
- package/templates/nest/{Workflow.eta → src/simpleapp/generate/commons/providers/workflow.provider.ts.etax} +20 -14
- package/templates/nest/src/simpleapp/generate/commons/roles/roles.decorator.ts.eta +6 -0
- package/templates/nest/src/simpleapp/generate/commons/roles/roles.enum.ts.eta +28 -0
- package/templates/nest/src/simpleapp/generate/commons/roles/roles.group.ts.eta +10 -0
- package/templates/nest/src/simpleapp/generate/commons/roles/roles.guard.ts.eta +34 -0
- package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +391 -0
- package/templates/nest/src/simpleapp/generate/controllers/simpleapp.controller.ts.eta +71 -0
- package/templates/nest/src/simpleapp/generate/models/perm.model.ts.eta +53 -0
- package/templates/nest/src/simpleapp/generate/models/tenant.model.ts.eta +45 -0
- package/templates/nest/src/simpleapp/generate/models/user.model.ts.eta +57 -0
- package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +624 -0
- package/templates/nest/src/simpleapp/generate/types/index.ts.eta +19 -0
- package/templates/nest/src/simpleapp/profile/profile.apischema.ts.eta +74 -0
- package/templates/nest/src/simpleapp/profile/profile.controller.ts.eta +110 -0
- package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +195 -0
- package/templates/nest/src/simpleapp/profile/profile.types.ts.eta +18 -0
- package/templates/nest/src/simpleapp/services/autoinc.service.ts.eta +89 -0
- package/templates/nest/src/simpleapp/services/branch.service.ts.eta +66 -0
- package/templates/nest/src/simpleapp/services/docno.service.ts.eta +93 -0
- package/templates/nest/src/simpleapp/services/org.service.ts.eta +67 -0
- package/templates/nest/src/simpleapp/services/perm.service.ts.eta +102 -0
- package/templates/nest/src/simpleapp/services/tenant.service.ts.eta +69 -0
- package/templates/nest/src/simpleapp/services/user.service.ts.eta +66 -0
- package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +43 -0
- package/templates/nuxt/.env.eta +21 -0
- package/templates/nuxt/.gitignore.eta +28 -0
- package/templates/nuxt/app.vue.eta +5 -2
- package/templates/nuxt/assets/css/tailwind.css.eta +35 -0
- package/templates/nuxt/components/CrudNestedDoc.vue.eta +164 -0
- package/templates/nuxt/components/CrudSimple.vue.eta +179 -0
- package/templates/nuxt/{components.debugdocdata.vue.eta → components/DebugDocumentData.vue.eta} +4 -1
- package/templates/nuxt/{components.eventmonitor.vue.eta → components/EventMonitor.vue.eta} +27 -27
- package/templates/nuxt/components/Invitation.vue.eta +50 -0
- package/templates/nuxt/components/Menus.vue.eta +58 -0
- package/templates/nuxt/components/PermissionInfo.vue.eta +92 -0
- package/templates/nuxt/components/SimpleAppAutocomplete.vue.eta +131 -0
- package/templates/nuxt/components/SimpleAppAutocompletemulti.vue.eta +73 -0
- package/templates/nuxt/components/SimpleAppCalendar.vue.eta +55 -0
- package/templates/nuxt/components/SimpleAppCheckbox.vue.eta +29 -0
- package/templates/nuxt/components/SimpleAppChip.vue.eta +28 -0
- package/templates/nuxt/components/SimpleAppColor.vue.eta +41 -0
- package/templates/nuxt/components/SimpleAppDatatable.vue.eta +20 -0
- package/templates/nuxt/components/SimpleAppDocumentNo.vue.eta +90 -0
- package/templates/nuxt/components/SimpleAppDynamicInput.vue.eta +29 -0
- package/templates/nuxt/components/SimpleAppEditor.vue.eta +31 -0
- package/templates/nuxt/components/SimpleAppForm.vue.eta +131 -0
- package/templates/nuxt/components/SimpleAppInputTable.vue.eta +104 -0
- package/templates/nuxt/components/SimpleAppList.vue.eta +38 -0
- package/templates/nuxt/components/SimpleAppListmulti.vue.eta +41 -0
- package/templates/nuxt/components/SimpleAppNumber.vue.eta +32 -0
- package/templates/nuxt/components/SimpleAppPassword.vue.eta +41 -0
- package/templates/nuxt/components/SimpleAppRadio.vue.eta +42 -0
- package/templates/nuxt/components/SimpleAppRating.vue.eta +41 -0
- package/templates/nuxt/components/SimpleAppSelect.vue.eta +38 -0
- package/templates/nuxt/components/SimpleAppSelectmulti.vue.eta +39 -0
- package/templates/nuxt/components/SimpleAppSlider.vue.eta +42 -0
- package/templates/nuxt/components/SimpleAppSwitch.vue.eta +30 -0
- package/templates/nuxt/components/SimpleAppText.vue.eta +50 -0
- package/templates/nuxt/components/SimpleAppTextarea.vue.eta +30 -0
- package/templates/nuxt/components/SimpleAppValue.vue.eta +86 -0
- package/templates/nuxt/components/SimpleFieldContainer.vue.eta +102 -0
- package/templates/nuxt/components/XorgPicker.vue.eta +66 -0
- package/templates/nuxt/components/helper.ts.eta +90 -0
- package/templates/nuxt/components/type.ts.eta +32 -0
- package/templates/nuxt/composables/docformat.generate.ts.eta +5 -0
- package/templates/nuxt/{composables.getautocomplete.ts.eta → composables/getAutocomplete.generate.ts.eta} +4 -5
- package/templates/nuxt/{composables.getmenus.ts.eta → composables/getMenus.generate.ts.eta} +22 -7
- package/templates/nuxt/composables/getOpenApi.generate.ts.eta +6 -0
- package/templates/nuxt/composables/getTenant.generate.ts.eta +4 -0
- package/templates/nuxt/composables/getUserStore.generate.ts.eta +22 -0
- package/templates/nuxt/composables/logout.generate.ts.eta +22 -0
- package/templates/nuxt/composables/roles.generate.ts.eta +48 -0
- package/templates/nuxt/composables/stringHelper.generate.ts.eta +5 -0
- package/templates/nuxt/{layouts.default.vue.eta → layouts/default.vue.eta} +2 -0
- package/templates/nuxt/middleware/10.acl.global.ts.eta +38 -0
- package/templates/nuxt/nuxt.config.ts.eta +12 -2
- package/templates/nuxt/pages/[xorg]/branch/index.vue.eta +102 -0
- package/templates/nuxt/pages/[xorg]/docnoformat/[id].vue.eta +17 -0
- package/templates/nuxt/pages/[xorg]/docnoformat/index.vue.eta +269 -0
- package/templates/nuxt/pages/[xorg]/index.vue.eta +36 -0
- package/templates/nuxt/pages/[xorg]/organization/index.vue.eta +148 -0
- package/templates/nuxt/pages/[xorg]/permission/index.vue.eta +280 -0
- package/templates/nuxt/pages/[xorg]/tenant/index.vue.eta +93 -0
- package/templates/nuxt/pages/[xorg]/user/index.vue.eta +468 -0
- package/templates/nuxt/pages/index.vue.eta +191 -0
- package/templates/nuxt/pages/login.vue.eta +21 -0
- package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +53 -0
- package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +155 -0
- package/templates/nuxt/plugins/50.simpleapp-client.ts.eta +23 -0
- package/templates/nuxt/{server.api.ts.eta → server/api/[xorg]/[...].ts.eta} +5 -2
- package/templates/nuxt/server/api/auth/[...].ts.eta +68 -0
- package/templates/nuxt/{server.api.auth.logout.ts.eta → server/api/auth/logout.ts.eta} +1 -3
- package/templates/nuxt/server/api/profile/[...].ts.eta +150 -0
- package/templates/nuxt/server/api/profile/index.ts.eta +103 -0
- package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +187 -0
- package/templates/nuxt/simpleapp/generate/commons/documents.ts.eta +6 -0
- package/templates/nuxt/simpleapp/generate/commons/events.ts.eta +5 -0
- package/templates/nuxt/simpleapp/generate/commons/groups.ts.eta +11 -0
- package/templates/nuxt/simpleapp/generate/commons/roles.ts.eta +21 -0
- package/templates/nuxt/types/index.ts.eta +65 -0
- package/templates/project/README.md +11 -0
- package/templates/project/build.sh.eta +17 -0
- package/templates/project/config.json.eta +2 -0
- package/templates/project/generate.ts.eta +10 -0
- package/templates/project/schemas/category.ts.eta +26 -0
- package/templates/project/schemas/index.ts.eta +5 -0
- package/templates/project/schemas/product.ts.eta +59 -0
- package/templates/project/shares/hello.ts.eta +1 -0
- package/templates/project/shares/index.ts.eta +2 -0
- package/tsconfig.json +9 -2
- package/tsconfig.tsbuildinfo +1 -0
- package/definations/category.cat.jsonschema.json +0 -55
- package/definations/level.lvl.jsonschema.json +0 -48
- package/definations/product.prd.jsonschema.json +0 -46
- package/templates/basic/controller.eta +0 -152
- package/templates/basic/module.eta +0 -22
- package/templates/basic/service.eta +0 -62
- package/templates/basic/simpleappclient.eta +0 -120
- package/templates/nest/SimpleAppController.eta +0 -69
- package/templates/nest/SimpleAppService.eta +0 -366
- package/templates/nest/TenantMiddleware.eta +0 -34
- package/templates/nest/UserProvider.eta +0 -127
- package/templates/nest/app.controller.eta +0 -12
- package/templates/nest/app.module.eta +0 -64
- package/templates/nest/app.service.eta +0 -8
- package/templates/nest/inputvalidation-exception.eta +0 -6
- package/templates/nest/nest.env.eta +0 -28
- package/templates/nest/nest.main.eta +0 -31
- package/templates/nuxt/components.crudsimple.vue.eta +0 -124
- package/templates/nuxt/components.menus.vue.eta +0 -35
- package/templates/nuxt/env.eta +0 -17
- package/templates/nuxt/pages.[xorg].index.vue.eta +0 -20
- package/templates/nuxt/pages.index.vue.eta +0 -72
- package/templates/nuxt/pages.login.vue.eta +0 -20
- package/templates/nuxt/plugins.simpleapp.ts.eta +0 -88
- package/templates/nuxt/server.api.auth[...].ts.eta +0 -233
- package/templates/nuxt/tailwind.css.eta +0 -49
- /package/templates/basic/{apischema.eta → nest/apischema.ts.eta} +0 -0
- /package/templates/basic/{jsonschema.eta → nest/jsonschema.ts.eta} +0 -0
- /package/templates/basic/{pageindexwithid.vue.eta → nuxt/pages.[id].vue.eta} +0 -0
- /package/templates/nest/{oauth2-redirect.eta → public_html/oauth2-redirect.html.eta} +0 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import { Injectable, Logger,Inject } from '@nestjs/common';
|
|
2
|
+
import { InjectModel } from '@nestjs/mongoose';
|
|
3
|
+
import * as jsonpath from 'jsonpath'
|
|
4
|
+
import { uniq } from 'lodash';
|
|
5
|
+
|
|
6
|
+
import {foreignkeys} from '../commons/dicts/foreignkeys'
|
|
7
|
+
import { Model,Types,PipelineStage,mongo, FilterQuery, ProjectionType} from 'mongoose';
|
|
8
|
+
import Ajv from 'ajv';
|
|
9
|
+
import addFormats from 'ajv-formats';
|
|
10
|
+
import addErrors from 'ajv-errors';
|
|
11
|
+
import {
|
|
12
|
+
NotFoundException,
|
|
13
|
+
BadRequestException,
|
|
14
|
+
ForbiddenException,
|
|
15
|
+
InternalServerErrorException,
|
|
16
|
+
HttpExceptionOptions,
|
|
17
|
+
} from '@nestjs/common/exceptions';
|
|
18
|
+
import { UserContext } from '../commons/user.context';
|
|
19
|
+
import { DocNumberFormatGenerator } from '../commons/docnogenerator.service';
|
|
20
|
+
|
|
21
|
+
export enum IsolationType {
|
|
22
|
+
'none' = 'none',
|
|
23
|
+
'org' = 'org',
|
|
24
|
+
'tenant' = 'tenant',
|
|
25
|
+
'branch' = 'branch',
|
|
26
|
+
}
|
|
27
|
+
export enum HookType {
|
|
28
|
+
'init' = 'init',
|
|
29
|
+
'beforeSearch' = 'beforeSearch',
|
|
30
|
+
'afterSearch' = 'afterSearch',
|
|
31
|
+
'beforeValidation' = 'beforeValidation',
|
|
32
|
+
'afterValidation' = 'afterValidation',
|
|
33
|
+
'beforeCreate' = 'beforeCreate',
|
|
34
|
+
'afterCreate' = 'afterCreate',
|
|
35
|
+
'beforeUpdate' = 'beforeUpdate',
|
|
36
|
+
'afterUpdate' = 'afterUpdate',
|
|
37
|
+
'beforeDelete' = 'beforeDelete',
|
|
38
|
+
'afterDelete' = 'afterDelete',
|
|
39
|
+
'beforeFetchRecord' = 'beforeFetchRecord',
|
|
40
|
+
'afterFetchRecord' = 'afterFetchRecord',
|
|
41
|
+
}
|
|
42
|
+
export type MoreProjectionType = {
|
|
43
|
+
[key: string]: string;
|
|
44
|
+
};
|
|
45
|
+
@Injectable()
|
|
46
|
+
export class SimpleAppService<T extends { _id?: string }> {
|
|
47
|
+
protected logger = new Logger();
|
|
48
|
+
protected strictIsolation = true
|
|
49
|
+
protected jsonschema = { type: 'object', properties: {}, required: [] };
|
|
50
|
+
protected documentIdentityCode = 'code';
|
|
51
|
+
protected documentIdentityLabel = 'label';
|
|
52
|
+
protected documentName = '-unknowndocname-';
|
|
53
|
+
protected documentType = '-unknowndoctype-';
|
|
54
|
+
protected LIMITPERPAGE = 20;
|
|
55
|
+
protected moreAutoCompleteField: MoreProjectionType = {};
|
|
56
|
+
protected isolationtype: IsolationType = IsolationType.org;
|
|
57
|
+
protected isolationFilter: any = {};
|
|
58
|
+
protected data: T = { _id: '' } as T;
|
|
59
|
+
protected doc: Model<T>; //set private to prevent developer break data isolation control
|
|
60
|
+
protected errorlist = [];
|
|
61
|
+
protected withDocNumberFormat=false
|
|
62
|
+
protected foreignkeys = {}
|
|
63
|
+
// protected userprovider = new UserContext() ;
|
|
64
|
+
|
|
65
|
+
constructor(
|
|
66
|
+
doctype: string,
|
|
67
|
+
docname: string,
|
|
68
|
+
newdoc: Model<T>,
|
|
69
|
+
isolationtype: IsolationType = IsolationType.org,
|
|
70
|
+
private docnogenerator:DocNumberFormatGenerator
|
|
71
|
+
) {
|
|
72
|
+
// console.log("-------init simpleapp service abstract class -------userprovider=",typeof this.userprovider)
|
|
73
|
+
this.documentType = doctype.toUpperCase();
|
|
74
|
+
this.documentName = docname;
|
|
75
|
+
this.doc = newdoc;
|
|
76
|
+
this.isolationtype = isolationtype;
|
|
77
|
+
this.hook(undefined,HookType.init, undefined);
|
|
78
|
+
// this.tenantdoc = tenantdoc
|
|
79
|
+
}
|
|
80
|
+
getDocumentType = () => this.documentType;
|
|
81
|
+
getDocumentName = () => this.documentName;
|
|
82
|
+
getRecordId = (): string => this.data._id;
|
|
83
|
+
setSchema = (newschema) => (this.jsonschema = newschema);
|
|
84
|
+
getSchema = () => this.doc.schema.obj;
|
|
85
|
+
getData = () => {
|
|
86
|
+
//console.log('thisdata', this.data);
|
|
87
|
+
return this.data;
|
|
88
|
+
};
|
|
89
|
+
setData = (newdata: T) => {
|
|
90
|
+
delete newdata._id;
|
|
91
|
+
this.data = { ...newdata };
|
|
92
|
+
return this;
|
|
93
|
+
};
|
|
94
|
+
reCalculate() {}
|
|
95
|
+
getIsolationFilter = (appuser:UserContext,) => {
|
|
96
|
+
let isolationFilter = {};
|
|
97
|
+
switch (this.isolationtype) {
|
|
98
|
+
case 'none':
|
|
99
|
+
isolationFilter = {};
|
|
100
|
+
break;
|
|
101
|
+
case 'branch':
|
|
102
|
+
isolationFilter = appuser.getBranchFilter();
|
|
103
|
+
break;
|
|
104
|
+
case 'tenant':
|
|
105
|
+
isolationFilter = appuser.getTenantFilter();
|
|
106
|
+
break;
|
|
107
|
+
case 'org':
|
|
108
|
+
default:
|
|
109
|
+
isolationFilter = appuser.getOrgFilter();
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
return isolationFilter;
|
|
113
|
+
};
|
|
114
|
+
async list(appuser:UserContext,) {
|
|
115
|
+
try {
|
|
116
|
+
//console.log("this.isolationFilter",this.getIsolationFilter())
|
|
117
|
+
const products = await this.doc.find(this.getIsolationFilter(appuser));
|
|
118
|
+
// console.log(products)
|
|
119
|
+
const productlist = products.map((p: T) => {
|
|
120
|
+
return p;
|
|
121
|
+
});
|
|
122
|
+
// console.log(products);
|
|
123
|
+
return productlist;
|
|
124
|
+
} catch (err) {
|
|
125
|
+
throw new InternalServerErrorException(err.message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
addAutoCompleteField = (morefield: MoreProjectionType) => {
|
|
129
|
+
const props = Object.getOwnPropertyNames(morefield);
|
|
130
|
+
// console.log('addAutoCompleteField', props);
|
|
131
|
+
for (let i = 0; i < props.length; i++) {
|
|
132
|
+
const key = props[i];
|
|
133
|
+
this.moreAutoCompleteField[key] = '$' + morefield[key];
|
|
134
|
+
}
|
|
135
|
+
// console.log(this.moreAutoCompleteField);
|
|
136
|
+
};
|
|
137
|
+
async getAutoComplete(appuser:UserContext, keyword: string) {
|
|
138
|
+
try {
|
|
139
|
+
const filter1 = {};
|
|
140
|
+
const filter2 = {};
|
|
141
|
+
let filters: any[] = [];
|
|
142
|
+
if (
|
|
143
|
+
this.jsonschema.properties[this.documentIdentityCode]['type'] ==
|
|
144
|
+
'string'
|
|
145
|
+
) {
|
|
146
|
+
filter1[this.documentIdentityCode] = { $regex: keyword, $options: 'i' };
|
|
147
|
+
filters.push(filter1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
filter2[this.documentIdentityLabel] = { $regex: keyword, $options: 'i' };
|
|
151
|
+
filters.push(filter2);
|
|
152
|
+
const filterobj = { $or: filters };
|
|
153
|
+
|
|
154
|
+
Object.assign(filterobj, this.getIsolationFilter(appuser));
|
|
155
|
+
let projections = {
|
|
156
|
+
id: `\$_id`,
|
|
157
|
+
label: `\$${this.documentIdentityLabel}`,
|
|
158
|
+
code: `\$${this.documentIdentityCode}`,
|
|
159
|
+
};
|
|
160
|
+
if (this.moreAutoCompleteField) {
|
|
161
|
+
Object.assign(projections, this.moreAutoCompleteField);
|
|
162
|
+
}
|
|
163
|
+
const products = await this.doc.find(filterobj, projections, {
|
|
164
|
+
limit: this.LIMITPERPAGE,
|
|
165
|
+
});
|
|
166
|
+
const productlist = products.map((p: T) => {
|
|
167
|
+
return p;
|
|
168
|
+
});
|
|
169
|
+
return productlist;
|
|
170
|
+
} catch (err) {
|
|
171
|
+
throw new InternalServerErrorException(err.message);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Special search function which can by pass data isolation. reserved and try not use
|
|
177
|
+
* @param appuser
|
|
178
|
+
* @param filters
|
|
179
|
+
* @returns
|
|
180
|
+
*/
|
|
181
|
+
private async searchNoIsolation(appuser:UserContext,filters: Object) {
|
|
182
|
+
try {
|
|
183
|
+
await this.hook(appuser,HookType.beforeSearch, filters);
|
|
184
|
+
const products = await this.doc.find(filters);
|
|
185
|
+
const productlist = products.map((p: T) => {
|
|
186
|
+
return p;
|
|
187
|
+
});
|
|
188
|
+
await this.hook(appuser,HookType.afterSearch, productlist);
|
|
189
|
+
// console.log(products);
|
|
190
|
+
return productlist;
|
|
191
|
+
} catch (err) {
|
|
192
|
+
throw new InternalServerErrorException(err.message);
|
|
193
|
+
}
|
|
194
|
+
// return this;
|
|
195
|
+
}
|
|
196
|
+
async aggregate(appuser:UserContext,pipeline:PipelineStage[]){
|
|
197
|
+
|
|
198
|
+
if(pipeline[0] && pipeline[0]['$match']){
|
|
199
|
+
try{
|
|
200
|
+
const isolationFilter= {... this.getIsolationFilter(appuser)}
|
|
201
|
+
this.polishIsolationFilter(isolationFilter)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
Object.assign(pipeline[0]['$match'],isolationFilter);
|
|
205
|
+
console.log("final agg",pipeline)
|
|
206
|
+
return await this.doc.aggregate(pipeline)
|
|
207
|
+
}catch(err){
|
|
208
|
+
throw new InternalServerErrorException(err);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
}else{
|
|
212
|
+
throw new InternalServerErrorException('first aggregate pipelinestage shall use $match');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
async search(appuser:UserContext,filters: FilterQuery<T>,projection:ProjectionType<T>=undefined,sort:any=undefined) {
|
|
217
|
+
try {
|
|
218
|
+
const isolationFilter= {... this.getIsolationFilter(appuser)}
|
|
219
|
+
this.polishIsolationFilter(isolationFilter)
|
|
220
|
+
|
|
221
|
+
// console.log("initial search",filters)
|
|
222
|
+
const newfilters ={...filters,...isolationFilter}
|
|
223
|
+
await this.hook(appuser,HookType.beforeSearch, newfilters);
|
|
224
|
+
// console.log("before _find",newfilters)
|
|
225
|
+
// console.log("this.doc",this.doc)
|
|
226
|
+
const products = await this.doc.find(newfilters,projection).sort(sort);
|
|
227
|
+
// console.log("after search",products)
|
|
228
|
+
const productlist = products.map((p: T) => {
|
|
229
|
+
return p;
|
|
230
|
+
});
|
|
231
|
+
// console.log("after map",productlist)
|
|
232
|
+
await this.hook(appuser,HookType.afterSearch, productlist);
|
|
233
|
+
// console.log(products);
|
|
234
|
+
return productlist;
|
|
235
|
+
} catch (err) {
|
|
236
|
+
throw new BadRequestException(err.message);
|
|
237
|
+
}
|
|
238
|
+
// return this;
|
|
239
|
+
}
|
|
240
|
+
async findById(appuser:UserContext,id: string) {
|
|
241
|
+
await this.hook(appuser,HookType.beforeFetchRecord, id);
|
|
242
|
+
const data = await this.search(appuser,{ _id: id });
|
|
243
|
+
await this.hook(appuser,HookType.afterFetchRecord, data);
|
|
244
|
+
if (data.length == 1) {
|
|
245
|
+
// console.log('data0', data[0]);
|
|
246
|
+
return data[0];
|
|
247
|
+
} else {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
async create(appuser:UserContext, data:T) {
|
|
254
|
+
let result;
|
|
255
|
+
if(!data._id){
|
|
256
|
+
data._id = crypto.randomUUID()
|
|
257
|
+
}
|
|
258
|
+
if(this.withDocNumberFormat && !data[this.documentIdentityCode]){
|
|
259
|
+
await this.genNewDocNo(appuser,data)
|
|
260
|
+
}
|
|
261
|
+
console.log("DATA for create",data)
|
|
262
|
+
await this.hook(appuser,HookType.beforeCreate, data);
|
|
263
|
+
|
|
264
|
+
let isolationFilter:any = {...appuser.getCreateFilter()}
|
|
265
|
+
isolationFilter = this.polishIsolationFilter(isolationFilter,data)
|
|
266
|
+
|
|
267
|
+
this.logger.debug("isolationFilter",'SimpleAppService')
|
|
268
|
+
this.logger.debug(isolationFilter,'SimpleAppService')
|
|
269
|
+
this.logger.debug("Create data before isolation",'SimpleAppService')
|
|
270
|
+
this.logger.debug(data,'SimpleAppService')
|
|
271
|
+
Object.assign(data, isolationFilter);
|
|
272
|
+
|
|
273
|
+
await this.validateData(appuser,data);
|
|
274
|
+
this.logger.debug("Create record",'SimpleAppService')
|
|
275
|
+
this.logger.debug(data,'SimpleAppService')
|
|
276
|
+
|
|
277
|
+
this.applyNestedDateTime(appuser,data,'create')
|
|
278
|
+
const newdoc = new this.doc(data);
|
|
279
|
+
|
|
280
|
+
result = await newdoc.save({session:appuser.getDBSession()})
|
|
281
|
+
|
|
282
|
+
// this.doc.create(data)
|
|
283
|
+
// this.doc
|
|
284
|
+
|
|
285
|
+
// result = await newdoc.save()
|
|
286
|
+
await this.hook(appuser,HookType.afterCreate, result);
|
|
287
|
+
|
|
288
|
+
return result as T;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
applyNestedDateTime=(appuser:UserContext,data:any,transtype:string)=>{
|
|
293
|
+
|
|
294
|
+
const props = Object.getOwnPropertyNames(data)
|
|
295
|
+
for(let i=0;i<props.length;i++){
|
|
296
|
+
const key = props[i]
|
|
297
|
+
//need to apply nested
|
|
298
|
+
if(Array.isArray(data[key]) && data[key].length>0 && typeof data[key][0] == 'object'){
|
|
299
|
+
for(let j=0;j<data[key].length;j++){
|
|
300
|
+
this.applyNestedDateTime(appuser,data[key][j],transtype)
|
|
301
|
+
}
|
|
302
|
+
}else if(key == 'created'){
|
|
303
|
+
data['created'] = (transtype == 'create' || !data['created']) ? new Date() .toISOString() : data['created']
|
|
304
|
+
}else if(key == 'createdby'){
|
|
305
|
+
data['createdby'] = (transtype == 'create' || !data['createdby']) ? appuser.getUid() : data['createdby']
|
|
306
|
+
}else if(key == 'updated'){
|
|
307
|
+
data['updated'] = new Date() .toISOString()
|
|
308
|
+
}else if(key == 'updatedby'){
|
|
309
|
+
data['updatedby'] = appuser.getUid()
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
}
|
|
314
|
+
hook = async (appuser:UserContext,type: string, data?: any) => {
|
|
315
|
+
return true;
|
|
316
|
+
};
|
|
317
|
+
async validateData(appuser:UserContext,data: T) {
|
|
318
|
+
const ajv = new Ajv({ allErrors: true, useDefaults: true });
|
|
319
|
+
addFormats(ajv);
|
|
320
|
+
addErrors(ajv);
|
|
321
|
+
|
|
322
|
+
ajv.addFormat('tel', /^$|^\d{7,15}$/gm);
|
|
323
|
+
ajv.addFormat('text', /.*$/);
|
|
324
|
+
ajv.addFormat('html', /.*$/);
|
|
325
|
+
ajv.addFormat('documentno', /.*$/);
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
ajv.addKeyword({ keyword: 'x-document-no', schemaType:'boolean' });
|
|
329
|
+
ajv.addKeyword({ keyword: 'x-document-label',schemaType: 'boolean' });
|
|
330
|
+
ajv.addKeyword({ keyword: 'x-document-status', schemaType: 'array' });
|
|
331
|
+
ajv.addKeyword({ keyword: 'x-document-api',schemaType: 'array' });
|
|
332
|
+
ajv.addKeyword({ keyword: 'x-page-type',schemaType:'string' }); // undefine mean no generate page
|
|
333
|
+
ajv.addKeyword({ keyword: 'x-ignore-autocomplete',schemaType: 'boolean' });
|
|
334
|
+
ajv.addKeyword({ keyword: 'x-isolation-type', schemaType: 'string' });
|
|
335
|
+
ajv.addKeyword({ keyword: 'x-document-type', schemaType: 'string' });
|
|
336
|
+
ajv.addKeyword({ keyword: 'x-document-name', schemaType: 'string' });
|
|
337
|
+
ajv.addKeyword({ keyword: 'x-collection-name',schemaType: 'string' });
|
|
338
|
+
ajv.addKeyword({ keyword: 'x-autocomplete-field', schemaType: 'boolean' });
|
|
339
|
+
ajv.addKeyword({ keyword: 'x-foreignkey', schemaType: 'string' });
|
|
340
|
+
ajv.addKeyword({ keyword: 'x-import-lib', schemaType: 'array' });
|
|
341
|
+
ajv.addKeyword({ keyword: 'x-compute', schemaType: 'object' });
|
|
342
|
+
ajv.addKeyword({ keyword: 'x-required-role', schemaType: 'array' });
|
|
343
|
+
|
|
344
|
+
const issuccess = await this.hook(appuser,HookType.beforeValidation, data);
|
|
345
|
+
if (!issuccess) {
|
|
346
|
+
const errormsg: string[] = [];
|
|
347
|
+
for (let i = 0; i < this.errorlist.length; i++) {
|
|
348
|
+
errormsg.push(this.errorlist[i].message);
|
|
349
|
+
}
|
|
350
|
+
this.logger.log('run hook during validation');
|
|
351
|
+
throw new BadRequestException("Before validation hook failed",errormsg as HttpExceptionOptions);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
let validate;
|
|
355
|
+
try {
|
|
356
|
+
validate = ajv.compile(this.jsonschema);
|
|
357
|
+
} catch (err) {
|
|
358
|
+
this.logger.error('compile error', err);
|
|
359
|
+
throw new ForbiddenException(err.message);
|
|
360
|
+
}
|
|
361
|
+
const valid = validate(data);
|
|
362
|
+
if (!valid) {
|
|
363
|
+
this.logger.error(JSON.stringify(validate.errors), 'validate errors:');
|
|
364
|
+
throw new BadRequestException("Data validation failed",validate.errors as HttpExceptionOptions);
|
|
365
|
+
}
|
|
366
|
+
await this.hook(appuser,HookType.afterValidation, data);
|
|
367
|
+
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
polishIsolationFilter = (filterIsolation:any,data:any={}) =>{
|
|
371
|
+
if(this.isolationtype == 'none'){
|
|
372
|
+
delete filterIsolation['branchId']
|
|
373
|
+
delete filterIsolation['orgId']
|
|
374
|
+
delete filterIsolation['tenantId']
|
|
375
|
+
}
|
|
376
|
+
if(this.isolationtype == 'tenant' && !this.strictIsolation){
|
|
377
|
+
// delete filterIsolation['tenantId']
|
|
378
|
+
if(data['tenantId']){
|
|
379
|
+
filterIsolation['tenantId']=data['tenantId']
|
|
380
|
+
}
|
|
381
|
+
delete filterIsolation['branchId']
|
|
382
|
+
delete filterIsolation['orgId']
|
|
383
|
+
}
|
|
384
|
+
if(this.isolationtype == 'org' && !this.strictIsolation){
|
|
385
|
+
// delete filterIsolation['tenantId']
|
|
386
|
+
if(data['tenantId']){
|
|
387
|
+
filterIsolation['tenantId']=data['tenantId']
|
|
388
|
+
}
|
|
389
|
+
if(data['orgId']){
|
|
390
|
+
filterIsolation['orgId']=data['orgId']
|
|
391
|
+
}
|
|
392
|
+
// delete filterIsolation['orgId']
|
|
393
|
+
delete filterIsolation['branchId']
|
|
394
|
+
}
|
|
395
|
+
return filterIsolation
|
|
396
|
+
}
|
|
397
|
+
async findIdThenDelete(appuser:UserContext,id: string): Promise<any> {
|
|
398
|
+
const deletedata = await this.findById(appuser,id);
|
|
399
|
+
let dependency
|
|
400
|
+
try {
|
|
401
|
+
await this.hook(appuser,HookType.beforeDelete, id);
|
|
402
|
+
this.logger.debug('delete record',this.documentName, id);
|
|
403
|
+
dependency = await this.getRelatedRecords(id);
|
|
404
|
+
console.log('dependency', dependency);
|
|
405
|
+
if (!dependency) {
|
|
406
|
+
let filterIsolation = this.getIsolationFilter(appuser);
|
|
407
|
+
this.polishIsolationFilter(filterIsolation)
|
|
408
|
+
|
|
409
|
+
filterIsolation['_id'] = id;
|
|
410
|
+
this.logger.debug('delete filter', filterIsolation);
|
|
411
|
+
const result = await this.doc.deleteOne(filterIsolation).session(appuser.getDBSession());
|
|
412
|
+
const deleteresult = {result:result, data: deletedata}
|
|
413
|
+
this.logger.debug(deleteresult, " delete result" +this.doc.collection.name,)
|
|
414
|
+
// this.doc.findByIdAndDelete(id)
|
|
415
|
+
await this.hook(appuser,HookType.afterDelete, deleteresult);
|
|
416
|
+
|
|
417
|
+
//this.doc.findByIdAndDelete(id);
|
|
418
|
+
return deleteresult;
|
|
419
|
+
} else {
|
|
420
|
+
console.log("reject query",dependency)
|
|
421
|
+
|
|
422
|
+
throw new ForbiddenException('Foreignkey constraint',dependency)
|
|
423
|
+
}
|
|
424
|
+
} catch (err) {
|
|
425
|
+
|
|
426
|
+
throw new InternalServerErrorException(err);
|
|
427
|
+
//JSON.stringify(dependency),JSON.stringify(dependency)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// updateOne = async (appuser:UserContext,data: T) => {
|
|
432
|
+
// this.doc.updateOne(data);
|
|
433
|
+
// };
|
|
434
|
+
|
|
435
|
+
findIdThenUpdate = async (appuser:UserContext,id: string, data: T,session:mongo.ClientSession=undefined) => {
|
|
436
|
+
const existingdata = await this.findById(appuser,id);
|
|
437
|
+
await this.hook(appuser,HookType.beforeUpdate, data);
|
|
438
|
+
// try {
|
|
439
|
+
Object.assign(data, appuser.getUpdateFilter());
|
|
440
|
+
Object.assign(existingdata, data);
|
|
441
|
+
delete existingdata['_id']
|
|
442
|
+
// existingdata['_id']=''
|
|
443
|
+
// console.log("newdata",data)
|
|
444
|
+
await this.validateData(appuser,data);
|
|
445
|
+
|
|
446
|
+
const isolationFilter = {...this.getIsolationFilter(appuser)}
|
|
447
|
+
this.polishIsolationFilter(isolationFilter)
|
|
448
|
+
|
|
449
|
+
isolationFilter['_id'] = id;
|
|
450
|
+
this.applyNestedDateTime(appuser,data,'update')
|
|
451
|
+
const result = await this.doc.findOneAndUpdate(isolationFilter, data).session(appuser.getDBSession());
|
|
452
|
+
await this.hook(appuser,HookType.afterUpdate, data);
|
|
453
|
+
return result;
|
|
454
|
+
// } catch (err) {
|
|
455
|
+
// throw new InternalServerErrorException(err.message);
|
|
456
|
+
// }
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
//find what foreign key constraint
|
|
460
|
+
async getRelatedRecords(id: string) {
|
|
461
|
+
this.logger.debug("get foreignkey for delete:",id)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
if(foreignkeys === undefined){
|
|
465
|
+
this.logger.error("foreignkeys object undetected")
|
|
466
|
+
throw new InternalServerErrorException("foreignkeys object undetected")
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const foreignkeysettings = foreignkeys[this.documentName];
|
|
470
|
+
if(!foreignkeysettings){
|
|
471
|
+
return null
|
|
472
|
+
}
|
|
473
|
+
const propkeys = Object.getOwnPropertyNames(foreignkeysettings);
|
|
474
|
+
|
|
475
|
+
if (propkeys.length > 0) {
|
|
476
|
+
//console.log('Have properties');
|
|
477
|
+
for (let i = 0; i < propkeys.length; i++) {
|
|
478
|
+
const collectionname = propkeys[i];
|
|
479
|
+
//console.log('run ', i, collectionname);
|
|
480
|
+
const fobjs = foreignkeysettings[propkeys[i]];
|
|
481
|
+
const collection = this.doc.db.collection(collectionname);
|
|
482
|
+
//single schema may have multiple foreign key link here, loop all
|
|
483
|
+
for (let j = 0; j < fobjs.length; j++) {
|
|
484
|
+
const fkey = fobjs[j] + '._id';
|
|
485
|
+
let filter = {}
|
|
486
|
+
filter[fkey] = id;
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
const result = await collection.findOne(filter);
|
|
490
|
+
if (result) {
|
|
491
|
+
this.logger.error(result,"related result found")
|
|
492
|
+
return result;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* dummy ping
|
|
502
|
+
*/
|
|
503
|
+
ping(...data) {
|
|
504
|
+
return `hello ${JSON.stringify(data)}`;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* change property documentStatus for specific document, no workflow execution
|
|
508
|
+
* @param id
|
|
509
|
+
* @param docstatus
|
|
510
|
+
* @returns Promise
|
|
511
|
+
*/
|
|
512
|
+
async setDocumentStatus(appuser:UserContext,id: string, docstatus: string) {
|
|
513
|
+
const partialdata: T = {} as T;
|
|
514
|
+
partialdata['documentStatus'] = docstatus;
|
|
515
|
+
return this.findIdThenUpdate(appuser,id, partialdata);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* change property documentStatus for specific document, no workflow execution
|
|
520
|
+
* @param id
|
|
521
|
+
* @param docstatus
|
|
522
|
+
* @returns Promise
|
|
523
|
+
*/
|
|
524
|
+
async executeWorkFlow(appuser:UserContext,id: string, bpmnname: string, docstatus: string) {
|
|
525
|
+
const data = await this.findById(appuser,id);
|
|
526
|
+
return "ok"
|
|
527
|
+
// Workflow.getInstance().executeWorkFlow(
|
|
528
|
+
// id,
|
|
529
|
+
// bpmnname,
|
|
530
|
+
// docstatus,
|
|
531
|
+
// data,
|
|
532
|
+
// );
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
async genNewDocNo(appuser:UserContext,data:T){
|
|
538
|
+
const result = await this.docnogenerator.generateNextNumberFromDocument(appuser,this.documentType,data)
|
|
539
|
+
data[this.documentIdentityCode]=result
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
async identifyUniqueKeys(appuser:UserContext,data:T){
|
|
544
|
+
/**
|
|
545
|
+
* 1. looping schemas identify what foreign key exists
|
|
546
|
+
* 2. loop through record obtain all foreign key value
|
|
547
|
+
* 3. get all unique key value in array {product:['xxxx','yyyy'],customer:['aaa']}
|
|
548
|
+
*/
|
|
549
|
+
const schema = this.jsonschema
|
|
550
|
+
|
|
551
|
+
//get all foreign keys catalogue
|
|
552
|
+
const collections = Object.getOwnPropertyNames(this.foreignkeys)
|
|
553
|
+
|
|
554
|
+
//obtain exists data in according foreign key
|
|
555
|
+
const pipelines :PipelineStage[] =[ {$match:{_id:false}}] //exclude data from current collection
|
|
556
|
+
const vdata = data['_doc']
|
|
557
|
+
const keystore = {}
|
|
558
|
+
collections.forEach((collectionname)=>{
|
|
559
|
+
const fks:string[] = this.foreignkeys[collectionname]
|
|
560
|
+
let results:string[] = []
|
|
561
|
+
fks.forEach(fieldpath=>{
|
|
562
|
+
const tmp = jsonpath.query(vdata,fieldpath).filter((item:string)=>item!='')
|
|
563
|
+
results = results.concat(tmp)
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
if(results.length>0){
|
|
569
|
+
console.log(results)
|
|
570
|
+
if(results.length>1){
|
|
571
|
+
results = uniq<string>(results)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
keystore[collectionname]= results
|
|
575
|
+
let addfield={$addFields:{collection:collectionname}}
|
|
576
|
+
|
|
577
|
+
const stagefilter:PipelineStage = {
|
|
578
|
+
$unionWith: {coll:collectionname,pipeline: [{ $match: { _id: {$in:results}} },addfield,{$project:{collection:1}}, ]}
|
|
579
|
+
}
|
|
580
|
+
pipelines.push(stagefilter)
|
|
581
|
+
}
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
// this.doc.db.collection(collectionname);
|
|
585
|
+
const unionresult = await this.doc.aggregate(pipelines)
|
|
586
|
+
|
|
587
|
+
if(!unionresult){
|
|
588
|
+
throw new InternalServerErrorException("Foreignkey check execution error",pipelines as HttpExceptionOptions)
|
|
589
|
+
}else{
|
|
590
|
+
let searchresult:any = {}
|
|
591
|
+
unionresult.forEach(item=>{
|
|
592
|
+
if(searchresult[item.collection]){
|
|
593
|
+
searchresult[item.collection].push(item._id)
|
|
594
|
+
}else{
|
|
595
|
+
searchresult[item.collection] = [item._id]
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
|
|
599
|
+
//search is it all foreign key exists in db
|
|
600
|
+
for(let i=0; i<collections.length; i++){
|
|
601
|
+
const collectionname = collections[i]
|
|
602
|
+
const keys:string[] = keystore[collectionname]
|
|
603
|
+
if(!keys){
|
|
604
|
+
continue
|
|
605
|
+
}
|
|
606
|
+
for(let k=0;k<keys.length; k++){
|
|
607
|
+
const key = keys[k]
|
|
608
|
+
if(!searchresult[collectionname].includes(key)){
|
|
609
|
+
console.log(`Foreignkey ${key} at collection ${collectionname} does not exist`)
|
|
610
|
+
throw new BadRequestException(`Foreignkey ${key} at collection ${collectionname} does not exist`)
|
|
611
|
+
}
|
|
612
|
+
else{
|
|
613
|
+
// console.log(`${collectionname} - ${key} found`)
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ForeignKey = {
|
|
2
|
+
_id: string
|
|
3
|
+
label: string
|
|
4
|
+
}
|
|
5
|
+
export type DocNumberFormatResult = {
|
|
6
|
+
formatId: string
|
|
7
|
+
formatName: string
|
|
8
|
+
result: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export type SearchBody = {
|
|
13
|
+
|
|
14
|
+
filter?:Object;
|
|
15
|
+
|
|
16
|
+
fields?: any[];
|
|
17
|
+
|
|
18
|
+
sorts?: any[];
|
|
19
|
+
}
|