@simitgroup/simpleapp-generator 1.6.3-alpha → 1.6.4-b-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/dist/buildinschemas/branch.d.ts.map +1 -1
  2. package/dist/buildinschemas/branch.js +1 -0
  3. package/dist/buildinschemas/branch.js.map +1 -1
  4. package/dist/buildinschemas/changehistories.d.ts +3 -0
  5. package/dist/buildinschemas/changehistories.d.ts.map +1 -0
  6. package/dist/buildinschemas/changehistories.js +36 -0
  7. package/dist/buildinschemas/changehistories.js.map +1 -0
  8. package/dist/buildinschemas/index.d.ts +1 -0
  9. package/dist/buildinschemas/index.d.ts.map +1 -1
  10. package/dist/buildinschemas/index.js +3 -1
  11. package/dist/buildinschemas/index.js.map +1 -1
  12. package/dist/buildinschemas/organization.js +2 -2
  13. package/dist/buildinschemas/organization.js.map +1 -1
  14. package/dist/buildinschemas/user.d.ts.map +1 -1
  15. package/dist/buildinschemas/user.js +5 -1
  16. package/dist/buildinschemas/user.js.map +1 -1
  17. package/dist/buildinschemas/webhook.d.ts +3 -0
  18. package/dist/buildinschemas/webhook.d.ts.map +1 -0
  19. package/dist/buildinschemas/webhook.js +33 -0
  20. package/dist/buildinschemas/webhook.js.map +1 -0
  21. package/dist/framework.d.ts.map +1 -1
  22. package/dist/framework.js +3 -2
  23. package/dist/framework.js.map +1 -1
  24. package/dist/generate.js +30 -11
  25. package/dist/generate.js.map +1 -1
  26. package/dist/processors/jsonschemabuilder.d.ts.map +1 -1
  27. package/dist/processors/jsonschemabuilder.js +10 -2
  28. package/dist/processors/jsonschemabuilder.js.map +1 -1
  29. package/dist/type.d.ts +2 -0
  30. package/dist/type.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/buildinschemas/branch.ts +1 -0
  33. package/src/buildinschemas/changehistories.ts +33 -0
  34. package/src/buildinschemas/index.ts +2 -1
  35. package/src/buildinschemas/organization.ts +2 -2
  36. package/src/buildinschemas/user.ts +5 -1
  37. package/src/buildinschemas/webhook.ts +31 -0
  38. package/src/framework.ts +3 -2
  39. package/src/generate.ts +35 -15
  40. package/src/processors/jsonschemabuilder.ts +10 -2
  41. package/src/type.ts +2 -0
  42. package/templates/basic/nest/controller.ts.eta +24 -3
  43. package/templates/basic/nest/model.ts.eta +9 -1
  44. package/templates/basic/nest/resolver.ts.eta +2 -2
  45. package/templates/basic/nuxt/pages.[id].vue.eta +7 -7
  46. package/templates/basic/nuxt/pages.form.vue.eta +1 -4
  47. package/templates/basic/nuxt/pages.landing.vue.eta +1 -20
  48. package/templates/basic/nuxt/simpleapp.generate.client.ts.eta +8 -1
  49. package/templates/nest/src/simpleapp/generate/apischemas/simpleapp.apischema.ts.eta +2 -0
  50. package/templates/nest/src/simpleapp/generate/commons/dicts/documents.ts.eta +9 -2
  51. package/templates/nest/src/simpleapp/generate/commons/docnogenerator.service.ts.eta +21 -8
  52. package/templates/nest/src/simpleapp/generate/commons/roles/roles.enum.ts.eta +5 -10
  53. package/templates/nest/src/simpleapp/generate/commons/roles/roles.group.ts.eta +1 -0
  54. package/templates/nest/src/simpleapp/generate/commons/runwebhook.service.ts.eta +50 -0
  55. package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +22 -8
  56. package/templates/nest/src/simpleapp/generate/controllers/simpleapp.controller.ts.eta +9 -1
  57. package/templates/nest/src/simpleapp/generate/processors/branch.processor.ts.eta +12 -6
  58. package/templates/nest/src/simpleapp/generate/processors/org.processor.ts.eta +7 -12
  59. package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +133 -28
  60. package/templates/nest/src/simpleapp/generate/types/schema.type.ts.eta +3 -1
  61. package/templates/nest/src/simpleapp/generate/types/simpleapp.type.ts.eta +1 -0
  62. package/templates/nest/src/simpleapp/profile/profile.controller.ts.eta +19 -0
  63. package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +33 -8
  64. package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +15 -9
  65. package/templates/nuxt/assets/css/calendar.css._eta +3 -0
  66. package/templates/nuxt/assets/css/style.css._eta +1 -1
  67. package/templates/nuxt/assets/images/unknown.png.eta +0 -0
  68. package/templates/nuxt/assets/primevue/passthrough.ts._eta +6 -1
  69. package/templates/nuxt/components/button/ButtonAction.vue._eta +40 -39
  70. package/templates/nuxt/components/button/ButtonDanger.vue._eta +11 -3
  71. package/templates/nuxt/components/button/ButtonDefault.vue._eta +11 -3
  72. package/templates/nuxt/components/button/ButtonPrimary.vue._eta +9 -3
  73. package/templates/nuxt/components/button/ButtonSecondary.vue._eta +33 -0
  74. package/templates/nuxt/components/button/ButtonText.vue._eta +9 -5
  75. package/templates/nuxt/components/button/ButtonWarning.vue._eta +11 -3
  76. package/templates/nuxt/components/calendar/CalendarInput.vue.eta +4 -3
  77. package/templates/nuxt/components/calendar/CalendarSmall.vue.eta +76 -52
  78. package/templates/nuxt/components/chart/card.vue._eta +1 -1
  79. package/templates/nuxt/components/debug/DebugDocumentData.vue.eta +36 -26
  80. package/templates/nuxt/components/event/EventDocumentViewer.vue._eta +35 -13
  81. package/templates/nuxt/components/form/FormBranch.vue._eta +52 -5
  82. package/templates/nuxt/components/form/FormDocnoformat.vue.eta +14 -10
  83. package/templates/nuxt/components/form/FormUser.vue._eta +2 -4
  84. package/templates/nuxt/components/form/user/FormUserPermission.vue.eta +77 -59
  85. package/templates/nuxt/components/header/HeaderSelectBranch.vue.eta +42 -35
  86. package/templates/nuxt/components/image/ImageAvatar.vue.eta._vue +30 -0
  87. package/templates/nuxt/components/image/ImageOrganization.vue.eta.vue +34 -14
  88. package/templates/nuxt/components/image/ImageToBase64Uploader.vue.eta.vue +67 -50
  89. package/templates/nuxt/components/list/ListDocumentTable.vue.eta +20 -12
  90. package/templates/nuxt/components/list/ListView.vue.eta +64 -35
  91. package/templates/nuxt/components/overlay/OverlayPanelWithToolBar.vue.eta +5 -4
  92. package/templates/nuxt/components/overlay/OverlayViewer.vue.eta +8 -8
  93. package/templates/nuxt/components/page/PageDocList.vue.eta +36 -13
  94. package/templates/nuxt/components/renderer/RendererDate.vue.eta +8 -2
  95. package/templates/nuxt/components/renderer/RendererDateTime.vue.eta +7 -1
  96. package/templates/nuxt/components/renderer/RendererDocHistories.vue.eta +56 -0
  97. package/templates/nuxt/components/renderer/RendererForeignKey.vue.eta +14 -8
  98. package/templates/nuxt/components/renderer/RendererLink.vue.eta +7 -4
  99. package/templates/nuxt/components/renderer/RendererMoney.vue.eta +25 -17
  100. package/templates/nuxt/components/renderer/RendererTime.vue.eta +7 -1
  101. package/templates/nuxt/components/renderer/RendererViewer.vue.eta +19 -9
  102. package/templates/nuxt/components/select/SelectTemplate.vue.eta +53 -22
  103. package/templates/nuxt/components/session/SessionBlock.vue.eta +44 -46
  104. package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +25 -16
  105. package/templates/nuxt/components/simpleApp/SimpleAppCalendarInput.vue.eta +60 -0
  106. package/templates/nuxt/components/simpleApp/SimpleAppChildrenList.vue.eta +16 -8
  107. package/templates/nuxt/components/simpleApp/SimpleAppDocumentNo.vue.eta +8 -8
  108. package/templates/nuxt/components/simpleApp/SimpleAppFieldContainer.vue.eta +1 -1
  109. package/templates/nuxt/components/simpleApp/SimpleAppFormToolBar.vue._eta +114 -38
  110. package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +89 -168
  111. package/templates/nuxt/components/simpleApp/SimpleAppInputTable.vue.eta +44 -40
  112. package/templates/nuxt/components/simpleApp/SimpleAppUserPicker.vue.eta +387 -0
  113. package/templates/nuxt/components/text/TextDocStatus.vue._eta +22 -0
  114. package/templates/nuxt/components/user/UserButtonCreateTenant.vue._eta +13 -15
  115. package/templates/nuxt/components/user/UserButtonPermissionInfo.vue.eta +138 -95
  116. package/templates/nuxt/components/user/UserInvitation.vue.eta +53 -45
  117. package/templates/nuxt/components/user/UserTenantPicker.vue.eta +32 -71
  118. package/templates/nuxt/composables/date.generate.ts.eta +105 -8
  119. package/templates/nuxt/composables/getDocument.generate.ts.eta +8 -6
  120. package/templates/nuxt/composables/getOpenApi.generate.ts.eta +58 -10
  121. package/templates/nuxt/composables/getUserStore.generate.ts.eta +39 -6
  122. package/templates/nuxt/composables/goTo.generate.ts.eta +14 -1
  123. package/templates/nuxt/composables/graphquery.generate.ts.eta +20 -2
  124. package/templates/nuxt/composables/recently.generate.ts.eta +16 -0
  125. package/templates/nuxt/composables/roles.generate.ts.eta +9 -13
  126. package/templates/nuxt/composables/stringHelper.generate.ts.eta +52 -0
  127. package/templates/nuxt/composables/sysmessage.generate.ts.eta +1 -1
  128. package/templates/nuxt/error.vue._eta +4 -2
  129. package/templates/nuxt/pages/[xorg]/{organization.vue.eta → organization.vue._eta} +38 -9
  130. package/templates/nuxt/pages/[xorg]/user.vue.eta +12 -9
  131. package/templates/nuxt/pages/login.vue._eta +4 -1
  132. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +54 -26
  133. package/templates/nuxt/plugins/70.recently.ts.eta +55 -0
  134. package/templates/nuxt/providers/my-provider.ts.eta +22 -0
  135. package/templates/nuxt/server/api/[xorg]/{[...].ts.eta → [...].ts._eta} +47 -21
  136. package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +44 -3
  137. package/templates/nuxt/types/events.ts.eta +3 -2
  138. package/templates/nuxt/types/others.ts.eta +11 -1
  139. package/templates/nuxt/types/schema.ts.eta +3 -1
  140. package/templates/nuxt/types/simpleappinput.ts.eta +1 -1
  141. package/templates/nuxt/types/user.ts.eta +8 -7
  142. package/templates/project/jsonschemas/branch.json._eta +1 -0
  143. package/templates/project/jsonschemas/invoice.json._eta +4 -3
  144. package/templates/project/jsonschemas/organization.json._eta +2 -2
  145. package/templates/project/lang/default._json +6 -2
  146. package/tsconfig.tsbuildinfo +1 -1
  147. package/templates/nuxt/components/image/ImageAvatar.vue.eta.vue +0 -38
  148. /package/templates/nuxt/pages/[xorg]/mobile/docnoformat/{index.vue.eta → index.vue.etaxxx} +0 -0
  149. /package/templates/nuxt/pages/[xorg]/mobile/{index.vue._eta → index.vue._etaxxx} +0 -0
  150. /package/templates/nuxt/pages/[xorg]/mobile/organization/{[id].vue._eta → [id].vue._etaxxx} +0 -0
  151. /package/templates/nuxt/pages/[xorg]/mobile/{pickgroup.vue._eta → pickgroup.vue._etaxxx} +0 -0
  152. /package/templates/nuxt/pages/[xorg]/mobile/user/{index.vue.eta → index.vue.etaxxx} +0 -0
@@ -90,7 +90,9 @@ export class UserContext {
90
90
  getFullname = () => this.fullname;
91
91
  getTenantId = () => this.tenantId;
92
92
  getOrgId = () => this.orgId;
93
+ getOrgRecordId = () => this.orgRecordId;
93
94
  getBranchId = () => this.branchId;
95
+ getBranchCode = () => this.branchCode;
94
96
  getEmail = () => this.email;
95
97
  getTimeZone = () => this.timeZone;
96
98
  getCountry = () => this.country;
@@ -218,7 +220,7 @@ export class UserContext {
218
220
  }
219
221
  }
220
222
 
221
- userinfo.branchRecordId = myperm.currentbranch[0].branchRecordId;
223
+ userinfo.branchRecordId = myperm.currentbranch[0]._id;
222
224
  userinfo.branchCode = myperm.currentbranch[0].branchCode;
223
225
  userinfo.branchName = myperm.currentbranch[0].branchName;
224
226
  userinfo.orgRecordId = myperm.currentorg[0]._id;
@@ -258,7 +260,7 @@ export class UserContext {
258
260
  const tokeninfo = jwt.decode(tokenstr);
259
261
  this.token = tokenstr;
260
262
  this.uid = tokeninfo?.sub ?? '';
261
- this.email = tokeninfo?.email ??'';
263
+ this.email = tokeninfo?.email ?? '';
262
264
  this.uname = tokeninfo?.preferred_username ?? '';
263
265
  this.fullname = tokeninfo?.name ?? [];
264
266
  this.ssoACL = tokeninfo?.resource_access ?? [];
@@ -535,7 +537,7 @@ export class UserContext {
535
537
  };
536
538
 
537
539
  searchInsertedRecordId(collection: string, _id: string) {
538
- if(!this.modifiedRecords.createds[collection]) return undefined
540
+ if (!this.modifiedRecords.createds[collection]) return undefined;
539
541
  return this.modifiedRecords.createds[collection].find(
540
542
  (item) => item === _id,
541
543
  );
@@ -608,6 +610,7 @@ export class UserContext {
608
610
  as: 'org',
609
611
  },
610
612
  },
613
+ {$unwind:'$org'},
611
614
  {
612
615
  $lookup: {
613
616
  from: 'branch',
@@ -616,6 +619,7 @@ export class UserContext {
616
619
  as: 'branch',
617
620
  },
618
621
  },
622
+ {$unwind:'$branch'},
619
623
  ],
620
624
  },
621
625
  };
@@ -638,7 +642,7 @@ export class UserContext {
638
642
  activeusers.forEach((u) => {
639
643
  const permissions = u.permissions
640
644
  .filter((item: any) => {
641
- return item.org[0].active && item.branch[0].active;
645
+ return item.org.active && item.branch.active;
642
646
  })
643
647
  .map((item: any) => {
644
648
  return {
@@ -646,10 +650,11 @@ export class UserContext {
646
650
  orgId: item.orgId,
647
651
  branchId: item.branchId,
648
652
  groups: item.groups,
649
- orgCode: item.org[0].orgCode,
650
- orgName: item.org[0].orgName,
651
- branchCode: item.branch[0].branchCode,
652
- branchName: item.branch[0].branchName,
653
+ orgRecordId:item.org._id,
654
+ orgCode: item.org.orgCode,
655
+ orgName: item.org.orgName,
656
+ branchCode: item.branch.branchCode,
657
+ branchName: item.branch.branchName,
653
658
  xOrg: this.generateXorg(u.tenantId, item.orgId, item.branchId),
654
659
  };
655
660
  });
@@ -724,4 +729,13 @@ export class UserContext {
724
729
  }
725
730
  return data;
726
731
  }
732
+
733
+ offsetDate(date: string): string {
734
+ const timestamp = new Date(date).getTime();
735
+ const offsets = this.getOffsetMinute() * 60000;
736
+ const isodate =
737
+ new Date(timestamp + offsets).toISOString().split('.')[0] + 'Z';
738
+ // console.log("Generate schedule ",date,":",appuser.getOffsetMinute()," => ",isodate)
739
+ return isodate;
740
+ }
727
741
  }
@@ -30,6 +30,7 @@ type ServiceType = {
30
30
  findIdThenPatch: Function;
31
31
  setData: Function;
32
32
  getAutoComplete: Function;
33
+ fullTextSearch:Function;
33
34
  };
34
35
 
35
36
  // @ApiTags(doctype)
@@ -50,15 +51,22 @@ export class SimpleAppAbstractController<
50
51
  async _list(appuser: UserContext) {
51
52
  return this.service.list(appuser);
52
53
  }
54
+ async _fulltextsearch(appuser: UserContext, keyword: string) {
55
+ return this.service.fullTextSearch(
56
+ appuser,
57
+ keyword
58
+ );
59
+ }
53
60
  async _search(appuser: UserContext, searchObject: SearchBody) {
54
61
  return this.service.search(
55
62
  appuser,
56
63
  searchObject['filter'],
57
64
  searchObject['fields'],
58
65
  searchObject['sorts'],
66
+ searchObject['lookup'],
59
67
  );
60
68
  }
61
- async _autocomplete(appuser: UserContext, keyword:string,data?:T) {
69
+ async _autocomplete(appuser: UserContext, keyword: string, data?: T) {
62
70
  return this.service.getAutoComplete(appuser, keyword, data);
63
71
  }
64
72
  async _findOne(appuser: UserContext, id: string) {
@@ -6,7 +6,11 @@
6
6
  */
7
7
  import { UserContext } from '../commons/user.context';
8
8
  import * as sharelibs from '../sharelibs';
9
- import { Injectable, Inject,InternalServerErrorException } from '@nestjs/common';
9
+ import {
10
+ Injectable,
11
+ Inject,
12
+ InternalServerErrorException,
13
+ } from '@nestjs/common';
10
14
  import { InjectModel } from '@nestjs/mongoose';
11
15
  import * as jsonpath from 'jsonpath';
12
16
  import { Model } from 'mongoose';
@@ -17,7 +21,7 @@ import { DocNumberFormatGenerator } from '../commons/docnogenerator.service';
17
21
  import { AutoincreamentService } from '../../services/autoinc.service';
18
22
  import { alldocuments } from '../commons/dicts/documents';
19
23
  import { Docnoformat, DocnoformatService } from '../../services/docno.service';
20
- import { BranchOrganization, Branch,BranchHooks } from '../types/branch.type';
24
+ import { BranchOrganization, Branch, BranchHooks } from '../types/branch.type';
21
25
  import {
22
26
  DefaultBranchOrganization,
23
27
  DefaultBranch,
@@ -32,9 +36,11 @@ export class BranchProcessor extends SimpleAppService<Branch> {
32
36
  protected strictIsolation = false;
33
37
  protected documentIdentityCode = 'branchCode';
34
38
  protected documentIdentityLabel = 'branchName';
35
- protected hooks: BranchHooks = {
36
- beforeCreate: async (appuser: UserContext, data: Branch) => await this.branchBeforeCreate(appuser,data),
37
- afterCreate: async (appuser: UserContext, data: Branch) => await this.branchAfterCreate(appuser,data),
39
+ protected hooks: BranchHooks = {
40
+ beforeCreate: async (appuser: UserContext, data: Branch) =>
41
+ await this.branchBeforeCreate(appuser, data),
42
+ afterCreate: async (appuser: UserContext, data: Branch) =>
43
+ await this.branchAfterCreate(appuser, data),
38
44
  };
39
45
  protected foreignkeys = { organization: ['$.organization._id'] };
40
46
  constructor(mydoc: Model<Branch>) {
@@ -74,7 +80,7 @@ export class BranchProcessor extends SimpleAppService<Branch> {
74
80
  const docformats = alldocuments.filter((item) => item.docNumber);
75
81
  for (let i = 0; i < docformats.length; i++) {
76
82
  const doc = docformats[i];
77
- const pattern = `${doc.docType}-${branchCode}-[00000]`;
83
+ const pattern = doc.docNoPattern.replace('@BranchCode',branchCode);
78
84
  const formatdata: Docnoformat = {
79
85
  _id: crypto.randomUUID(),
80
86
  docNoFormatNo: `${doc.docType}-${branchCode}`,
@@ -32,8 +32,6 @@ export class OrganizationProcessor extends SimpleAppService<Organization> {
32
32
  protected documentIdentityLabel = 'orgName';
33
33
  protected strictIsolation = false;
34
34
  protected foreignkeys = {};
35
- protected defaultlogo =
36
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=';
37
35
  protected hooks: OrganizationHooks = {
38
36
  beforeCreate: async (appuser: UserContext, data: Organization) =>
39
37
  await this.orgBeforeCreate(appuser, data),
@@ -65,23 +63,22 @@ export class OrganizationProcessor extends SimpleAppService<Organization> {
65
63
  async runGetlogo(appuser: UserContext) {
66
64
  const logo = await this.searchLogo(appuser);
67
65
  if (logo) return logo.value;
68
- else return this.defaultlogo;
66
+ else return ''
69
67
  }
70
68
 
71
69
  async searchLogo(appuser: UserContext) {
72
70
  const keyvaluepair = await this.kvpairService.search(appuser, {
73
- key: 'orglogo',
71
+ key: 'org-'+appuser.getOrgRecordId(),
74
72
  });
75
73
  if (keyvaluepair && keyvaluepair.length > 0) return keyvaluepair[0];
76
74
  else return null;
77
75
  }
78
- async runUploadlogo(appuser: UserContext, data: KeyValue) {
79
- // this.setDefaultLogo(data.value);
76
+ async runUploadlogo(appuser: UserContext, data: KeyValue) {
80
77
  const key = data.key;
81
78
 
82
79
  let kvdata: Keyvaluepair = await this.searchLogo(appuser);
83
80
  if (kvdata) {
84
- kvdata.value=data.value
81
+ kvdata.value = data.value;
85
82
  const res = await this.kvpairService.findIdThenUpdate(
86
83
  appuser,
87
84
  kvdata._id,
@@ -95,7 +92,7 @@ export class OrganizationProcessor extends SimpleAppService<Organization> {
95
92
  } else {
96
93
  kvdata = {
97
94
  _id: crypto.randomUUID(),
98
- key: 'orglogo',
95
+ key: 'org-'+appuser.getOrgRecordId(),
99
96
  value: data.value,
100
97
  };
101
98
  const res = await this.kvpairService.create(appuser, kvdata);
@@ -106,10 +103,8 @@ export class OrganizationProcessor extends SimpleAppService<Organization> {
106
103
  }
107
104
  }
108
105
 
109
- return this.defaultlogo;
106
+ return ''
110
107
  }
111
108
 
112
- async setDefaultLogo(data: string) {
113
- this.defaultlogo = data;
114
- }
109
+
115
110
  }
@@ -43,7 +43,7 @@ import {
43
43
  WorkflowName,
44
44
  } from '../types';
45
45
  @Injectable()
46
- export class SimpleAppService<T extends { _id?: string, __v?:number }> {
46
+ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
47
47
  @Inject(EventEmitter2)
48
48
  protected eventEmitter: EventEmitter2;
49
49
  @Inject(CloudApiService)
@@ -53,7 +53,12 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
53
53
  protected hooks: DefaultHooks<T> = {};
54
54
  protected logger = new Logger();
55
55
  protected strictIsolation = true;
56
- protected jsonschema = { type: 'object', properties: {}, required: [] };
56
+ protected jsonschema: any = {
57
+ type: 'object',
58
+ 'x-simpleapp-config': {},
59
+ properties: {},
60
+ required: [],
61
+ };
57
62
  protected documentIdentityCode = 'code';
58
63
  protected documentIdentityLabel = 'label';
59
64
  protected documentName = '-unknowndocname-';
@@ -97,6 +102,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
97
102
  getRecordId = (): string => this.data._id;
98
103
  setSchema = (newschema) => (this.jsonschema = newschema);
99
104
  getSchema = () => this.doc.schema.obj;
105
+ getJsonSchema = () => this.jsonschema;
100
106
  getHooks = () => this.hooks;
101
107
  getData = () => {
102
108
  //console.log('thisdata', this.data);
@@ -224,8 +230,10 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
224
230
  this.polishIsolationFilter(isolationFilter);
225
231
 
226
232
  Object.assign(pipeline[0]['$match'], isolationFilter);
227
- //console.log("final agg",pipeline)
228
- return await this.doc.aggregate(pipeline);
233
+ this.logger.verbose(pipeline, `${this.documentName} aggregate:`);
234
+ return await this.doc.aggregate(pipeline, {
235
+ session: appuser.getDBSession(),
236
+ });
229
237
  } catch (err) {
230
238
  throw new InternalServerErrorException(err);
231
239
  }
@@ -238,8 +246,9 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
238
246
  async search(
239
247
  appuser: UserContext,
240
248
  filters: FilterQuery<T>,
241
- projection: ProjectionType<T> = undefined,
249
+ projection: string[] = undefined,
242
250
  sort: any = undefined,
251
+ lookup: { [key: string]: string } = undefined,
243
252
  ) {
244
253
  try {
245
254
  const isolationFilter = { ...this.getIsolationFilter(appuser) };
@@ -252,24 +261,47 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
252
261
  await this.hooks.beforeSearch(appuser, newfilters);
253
262
  // console.log("before _find",newfilters)
254
263
  // console.log("this.doc",this.doc)
255
- const products = await this.doc
256
- .find(newfilters, projection, { session: appuser.getDBSession() })
257
- .sort(sort);
258
- // console.log("after search",products)
259
- const productlist = products.map((p: T) => {
264
+ let searchResults: T[] = [];
265
+ if (lookup === undefined) {
266
+ this.logger.debug('after search', newfilters);
267
+ searchResults = await this.doc
268
+ .find(newfilters, projection, { session: appuser.getDBSession() })
269
+ .sort(sort);
270
+ } else {
271
+ const pipelines = this.searchToAggregate(
272
+ filters,
273
+ projection,
274
+ sort,
275
+ lookup,
276
+ );
277
+ this.logger.debug('after aggregate', pipelines);
278
+
279
+ searchResults = await this.aggregate(appuser, pipelines);
280
+ }
281
+
282
+ const list: T[] = searchResults.map((p: T) => {
260
283
  return p;
261
284
  });
262
285
  // console.log("after map",productlist)
263
- if (this.hooks.afterSearch)
264
- await this.hooks.afterSearch(appuser, productlist);
286
+ if (this.hooks.afterSearch) await this.hooks.afterSearch(appuser, list);
265
287
 
266
288
  // console.log(products);
267
- return productlist;
289
+ return list;
268
290
  } catch (err) {
269
291
  throw new BadRequestException(err.message);
270
292
  }
271
293
  // return this;
272
294
  }
295
+
296
+ async fullTextSearch(appuser: UserContext, keyword: string) {
297
+ const isolationFilter = { ...this.getIsolationFilter(appuser) };
298
+ this.polishIsolationFilter(isolationFilter);
299
+
300
+ const filters = { $text: { $search: keyword } };
301
+ const newfilters: FilterQuery<T> = { ...filters, ...isolationFilter };
302
+
303
+ return await this.doc.find(newfilters);
304
+ }
273
305
  async findById(appuser: UserContext, id: string) {
274
306
  if (this.hooks.beforeFetchRecord)
275
307
  await this.hooks.beforeFetchRecord(appuser, id);
@@ -364,6 +396,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
364
396
  // result = await newdoc.save()
365
397
  try {
366
398
  if (this.hooks.afterCreate) await this.hooks.afterCreate(appuser, result);
399
+ this.callWebhook(appuser, 'create', result);
367
400
  return result as T;
368
401
  } catch (err) {
369
402
  throw new InternalServerErrorException(
@@ -416,6 +449,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
416
449
  ajv.addFormat('text', /.*$/);
417
450
  ajv.addFormat('html', /.*$/);
418
451
  ajv.addFormat('documentno', /.*$/);
452
+ ajv.addFormat('money', /.*$/);
419
453
 
420
454
  ajv.addKeyword({ keyword: 'x-foreignkey', schemaType: 'string' });
421
455
  ajv.addKeyword({ keyword: 'x-simpleapp-config', schemaType: 'object' });
@@ -524,6 +558,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
524
558
  if (this.hooks.afterDelete)
525
559
  await this.hooks.afterDelete(appuser, deleteresult, id);
526
560
  //this.doc.findByIdAndDelete(id);
561
+ this.callWebhook(appuser, 'delete', deletedata);
527
562
  return deleteresult;
528
563
  } else {
529
564
  this.logger.debug('reject query', dependency);
@@ -541,18 +576,24 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
541
576
  // };
542
577
 
543
578
  findIdThenUpdate = async (appuser: UserContext, id: string, data: T) => {
544
- const existingdata = await this.findById(appuser, id);
545
-
579
+
580
+ try {
546
581
  //version exists, need ensure different only 1
547
- if(typeof data.__v=='number' && data.__v != existingdata.__v ){
548
- throw new BadRequestException(`You submit older version data "v${data.__v}"" but latest version = "v${existingdata.__v}"`)
549
- }
550
-
551
- data.__v = existingdata.__v+1
552
- if (!existingdata) {
553
- throw new NotFoundException(`${id} not found`, 'not found');
554
- }
582
+ const existingdata = await this.findById(appuser, id);
583
+ if(!existingdata) throw new NotFoundException(`${this.documentName} findIdThenUpdate: _id:${id} not found`, 'not found');
555
584
 
585
+ this.logger.debug("update id:"+id,this.documentName+' findIdThenUpdate')
586
+ if (typeof data.__v == 'number' && data.__v != existingdata.__v) {
587
+ throw new BadRequestException(
588
+ `You submit older version data "v${data.__v}"" but latest version = "v${existingdata.__v}"`,
589
+ );
590
+ }
591
+ this.logger.debug("warn1",existingdata)
592
+ data.__v = existingdata.__v + 1;
593
+ // if (!existingdata) {
594
+ // throw new NotFoundException(`${id} not found`, 'not found');
595
+ // }
596
+ this.logger.debug("warn2")
556
597
  if (this.hooks.beforeUpdate)
557
598
  await this.hooks.beforeUpdate(appuser, id, data, existingdata);
558
599
 
@@ -574,7 +615,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
574
615
  this.polishIsolationFilter(isolationFilter);
575
616
  isolationFilter['_id'] = id;
576
617
  this.applyNestedDateTime(appuser, data, 'update');
577
- try {
618
+
578
619
  const result = await this.doc.findOneAndReplace(isolationFilter, data, {
579
620
  session: dbsession,
580
621
  new: true,
@@ -582,6 +623,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
582
623
  appuser.addUpdatedRecordId(this.documentName, data._id);
583
624
  if (this.hooks.afterUpdate)
584
625
  await this.hooks.afterUpdate(appuser, id, existingdata, result);
626
+ this.callWebhook(appuser, 'update', result);
585
627
  return result; // await this.findById(appuser, id);
586
628
  } catch (err) {
587
629
  this.logger.error(err);
@@ -599,12 +641,13 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
599
641
  if (!existingdata) {
600
642
  throw new NotFoundException(`${id} not found`, 'not found');
601
643
  }
602
- if(typeof data.__v=='number' && data.__v != existingdata.__v ){
603
- throw new BadRequestException(`You submit older version data "v${data.__v}"" but latest version = "v${existingdata.__v}"`)
644
+ if (typeof data.__v == 'number' && data.__v != existingdata.__v) {
645
+ throw new BadRequestException(
646
+ `You submit older version data "v${data.__v}"" but latest version = "v${existingdata.__v}"`,
647
+ );
604
648
  }
605
649
 
606
- data.__v = existingdata.__v+1
607
-
650
+ data.__v = existingdata.__v + 1;
608
651
 
609
652
  if (this.hooks.beforeUpdate)
610
653
  await this.hooks.beforeUpdate(appuser, id, data, existingdata);
@@ -641,6 +684,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
641
684
 
642
685
  if (this.hooks.afterUpdate)
643
686
  await this.hooks.afterUpdate(appuser, id, existingdata, result);
687
+ this.callWebhook(appuser, 'update', result);
644
688
  return result; //await this.findById(appuser, id);
645
689
  } catch (err) {
646
690
  throw new InternalServerErrorException(err.message);
@@ -744,6 +788,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
744
788
  if (this.hooks.afterSetStatus)
745
789
  await this.hooks.afterSetStatus(appuser, docstatus, finaldata);
746
790
 
791
+ this.callWebhook(appuser, docstatus, finaldata);
747
792
  return updateresult;
748
793
  }
749
794
  }
@@ -928,4 +973,64 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
928
973
  const pdfresult = await this.printapi.getBase64Pdf(appuser, formatid, id);
929
974
  return pdfresult;
930
975
  }
976
+
977
+ searchToAggregate(
978
+ filter: FilterQuery<T>,
979
+ columns: string[],
980
+ sort: string[][],
981
+ lookup: { [key: string]: string },
982
+ ) {
983
+ const pipelines: PipelineStage[] = [];
984
+ const projection = {};
985
+ // console.log('sortsort', sort);
986
+
987
+ pipelines.push({ $match: filter });
988
+ if (Array.isArray(columns) && columns.length > 0) {
989
+ columns.forEach((col) => {
990
+ projection[col] = 1;
991
+ });
992
+ }
993
+
994
+ const collections = Object.keys(lookup);
995
+ collections.forEach((tokey: string) => {
996
+ const toarr = tokey.split('.');
997
+ const to = toarr[0];
998
+ const foreignField = toarr[1] ?? '_id';
999
+ pipelines.push({
1000
+ $lookup: {
1001
+ from: to,
1002
+ as: '_' + to,
1003
+ localField: lookup[tokey],
1004
+ foreignField: foreignField,
1005
+ },
1006
+ });
1007
+ pipelines.push({ $unwind: '$_' + to });
1008
+
1009
+ if (Object.keys(projection).length > 0) projection['_' + to] = 1;
1010
+ });
1011
+
1012
+ if (Object.keys(projection).length > 0)
1013
+ pipelines.push({ $project: projection });
1014
+
1015
+ if (Array.isArray(sort) && sort.length > 0) {
1016
+ const sortobj = {};
1017
+ sort.forEach((item) => {
1018
+ sortobj[item[0]] = item[1].toLowerCase() == 'asc' ? 1 : -1;
1019
+ });
1020
+ pipelines.push({ $sort: sortobj });
1021
+ }
1022
+ // console.log('pipelinespipelinespipelines', pipelines);
1023
+
1024
+ return pipelines;
1025
+ }
1026
+
1027
+ callWebhook(appuser: UserContext, actionName: string, data: any) {
1028
+ this.eventEmitter.emit(
1029
+ 'webhook',
1030
+ appuser,
1031
+ this.documentName,
1032
+ actionName,
1033
+ data,
1034
+ );
1035
+ }
931
1036
  }
@@ -30,17 +30,19 @@ export type DocumentStatus = {
30
30
  formula:string //example "jslib.getDocumentSubTotal(@F{$.details})"
31
31
  }
32
32
  export type SchemaConfig = {
33
- isolationType: IsolationType
33
+ isolationType: string
34
34
  requiredRoles?:string[]
35
35
  pageType?: string
36
36
  uniqueKey?:string
37
37
  uniqueKeys?:string[][]
38
38
  documentTitle?:string
39
39
  generateDocumentNumber?:boolean
40
+ docNoPattern?:string
40
41
  documentDate?:string
41
42
  allStatus?:DocumentStatus[]
42
43
  additionalApis?:DocumentApi[]
43
44
  additionalAutoCompleteFields ?: string[]
45
+ search?:string[]
44
46
  // libs?:ImportLibs[] // both process class and frontend client class will import same lib
45
47
  formulas?: Formula[]
46
48
  documentType: string
@@ -27,6 +27,7 @@ export type SearchBody = {
27
27
  fields?: any[];
28
28
 
29
29
  sorts?: any[];
30
+ lookup?:Object;
30
31
  };
31
32
 
32
33
  export enum IsolationType {
@@ -160,4 +160,23 @@ export class ProfileController {
160
160
  throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
161
161
  }
162
162
  }
163
+ @Post('/tour-complete/:guidename')
164
+ @Roles(Role.User)
165
+ @ApiOperation({
166
+ operationId: 'runTourComplete',
167
+ description: 'complete specific tour guide',
168
+ })
169
+ @ApiResponse({ status: 201, type: Object, description: 'Success' })
170
+ async runTourComplete(
171
+ @AppUser() appuser: UserContext,
172
+ @Param('guidename') guidename: string,
173
+
174
+ ) {
175
+ const result = await this.profileservice.runTourComplete(appuser,guidename,);
176
+ if (result) {
177
+ return result;
178
+ } else {
179
+ throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
180
+ }
181
+ }
163
182
  }
@@ -5,8 +5,8 @@
5
5
  * Author: Ks Tan
6
6
  */
7
7
  import { UserService, User } from './../services/user.service';
8
- import countrytimezone from 'countries-and-timezones'
9
- import countryToCurrency, { Currencies, Countries } from "country-to-currency";
8
+ import countrytimezone from 'countries-and-timezones';
9
+ import countryToCurrency, { Currencies, Countries } from 'country-to-currency';
10
10
  import {
11
11
  Injectable,
12
12
  Scope,
@@ -91,14 +91,14 @@ export class ProfileService {
91
91
  appuser: UserContext,
92
92
  tenantName: string,
93
93
  timeZone: string,
94
- utcOffset: number
94
+ utcOffset: number,
95
95
  ) {
96
96
  // try{
97
- const timezonedata = countrytimezone.getCountriesForTimezone(timeZone)[0]
98
- const countryCode = timezonedata['id']
99
- const countryName = timezonedata['name']
100
- const currencyCode = countryToCurrency[countryCode]
101
-
97
+ const timezonedata = countrytimezone.getCountriesForTimezone(timeZone)[0];
98
+ const countryCode = timezonedata['id'];
99
+ const countryName = timezonedata['name'];
100
+ const currencyCode = countryToCurrency[countryCode];
101
+
102
102
  appuser.getDBSession().startTransaction();
103
103
  const tenantdata: Tenant = {
104
104
  tenantId: 1,
@@ -124,6 +124,7 @@ export class ProfileService {
124
124
  orgName: tenantName,
125
125
  active: true,
126
126
  orgCode: 'HQ',
127
+ registrationNo: '000000',
127
128
  timeZone: timeZone,
128
129
  offsetMinute: utcOffset,
129
130
  currency: currencyCode,
@@ -143,6 +144,13 @@ export class ProfileService {
143
144
  branchId: 1,
144
145
  branchCode: 'HQ',
145
146
  branchName: tenantName,
147
+ street1: '11,my street 1',
148
+ street2: 'my street 2',
149
+ postcode: '11111',
150
+ city: 'my city',
151
+ tel: '99999999999',
152
+ email: 'change-email@email.com',
153
+ region: 'my region',
146
154
  country: countryName,
147
155
  active: true,
148
156
  orgId: orgResult.orgId,
@@ -245,4 +253,21 @@ export class ProfileService {
245
253
  async getSession(appuser: UserContext) {
246
254
  return 'OK';
247
255
  }
256
+
257
+ async runTourComplete(appuser: UserContext, guideName: string) {
258
+ if (!guideName || guideName == '')
259
+ throw new BadRequestException('undefine guideName');
260
+
261
+ const user = await this.usersvc.findById(appuser, appuser.getId());
262
+ if (!Array.isArray(user.completedTours)) {
263
+ user.completedTours = [];
264
+ }
265
+
266
+ if (!user.completedTours.includes(guideName)) {
267
+ user.completedTours.push(guideName);
268
+ const res = await this.usersvc.findIdThenUpdate(appuser, user._id, user);
269
+ }
270
+
271
+ return 'ok';
272
+ }
248
273
  }