@simitgroup/simpleapp-generator 1.6.3-alpha → 1.6.4-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 (148) 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 +23 -2
  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/roles/roles.enum.ts.eta +5 -10
  52. package/templates/nest/src/simpleapp/generate/commons/roles/roles.group.ts.eta +1 -0
  53. package/templates/nest/src/simpleapp/generate/commons/runwebhook.service.ts.eta +50 -0
  54. package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +13 -3
  55. package/templates/nest/src/simpleapp/generate/controllers/simpleapp.controller.ts.eta +9 -1
  56. package/templates/nest/src/simpleapp/generate/processors/branch.processor.ts.eta +12 -6
  57. package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +120 -19
  58. package/templates/nest/src/simpleapp/generate/types/schema.type.ts.eta +3 -1
  59. package/templates/nest/src/simpleapp/generate/types/simpleapp.type.ts.eta +1 -0
  60. package/templates/nest/src/simpleapp/profile/profile.controller.ts.eta +19 -0
  61. package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +30 -8
  62. package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +2 -1
  63. package/templates/nuxt/assets/css/calendar.css._eta +3 -0
  64. package/templates/nuxt/assets/css/style.css._eta +1 -1
  65. package/templates/nuxt/assets/images/unknown.png.eta +0 -0
  66. package/templates/nuxt/assets/primevue/passthrough.ts._eta +6 -1
  67. package/templates/nuxt/components/button/ButtonAction.vue._eta +40 -39
  68. package/templates/nuxt/components/button/ButtonDanger.vue._eta +11 -3
  69. package/templates/nuxt/components/button/ButtonDefault.vue._eta +11 -3
  70. package/templates/nuxt/components/button/ButtonPrimary.vue._eta +9 -3
  71. package/templates/nuxt/components/button/ButtonSecondary.vue._eta +33 -0
  72. package/templates/nuxt/components/button/ButtonText.vue._eta +9 -5
  73. package/templates/nuxt/components/button/ButtonWarning.vue._eta +11 -3
  74. package/templates/nuxt/components/calendar/CalendarInput.vue.eta +4 -3
  75. package/templates/nuxt/components/calendar/CalendarSmall.vue.eta +33 -16
  76. package/templates/nuxt/components/chart/card.vue._eta +1 -1
  77. package/templates/nuxt/components/debug/DebugDocumentData.vue.eta +36 -26
  78. package/templates/nuxt/components/event/EventDocumentViewer.vue._eta +36 -13
  79. package/templates/nuxt/components/form/FormBranch.vue._eta +52 -5
  80. package/templates/nuxt/components/form/FormDocnoformat.vue.eta +14 -10
  81. package/templates/nuxt/components/form/FormUser.vue._eta +1 -1
  82. package/templates/nuxt/components/form/user/FormUserPermission.vue.eta +77 -59
  83. package/templates/nuxt/components/header/HeaderSelectBranch.vue.eta +42 -35
  84. package/templates/nuxt/components/image/ImageAvatar.vue.eta._vue +30 -0
  85. package/templates/nuxt/components/image/ImageOrganization.vue.eta.vue +7 -5
  86. package/templates/nuxt/components/image/ImageToBase64Uploader.vue.eta.vue +67 -50
  87. package/templates/nuxt/components/list/ListDocumentTable.vue.eta +20 -12
  88. package/templates/nuxt/components/list/ListView.vue.eta +64 -35
  89. package/templates/nuxt/components/overlay/OverlayPanelWithToolBar.vue.eta +5 -4
  90. package/templates/nuxt/components/overlay/OverlayViewer.vue.eta +8 -8
  91. package/templates/nuxt/components/page/PageDocList.vue.eta +36 -13
  92. package/templates/nuxt/components/renderer/RendererDate.vue.eta +8 -2
  93. package/templates/nuxt/components/renderer/RendererDateTime.vue.eta +7 -1
  94. package/templates/nuxt/components/renderer/RendererDocHistories.vue.eta +56 -0
  95. package/templates/nuxt/components/renderer/RendererForeignKey.vue.eta +9 -8
  96. package/templates/nuxt/components/renderer/RendererLink.vue.eta +7 -4
  97. package/templates/nuxt/components/renderer/RendererMoney.vue.eta +25 -17
  98. package/templates/nuxt/components/renderer/RendererTime.vue.eta +7 -1
  99. package/templates/nuxt/components/renderer/RendererViewer.vue.eta +19 -9
  100. package/templates/nuxt/components/select/SelectTemplate.vue.eta +47 -21
  101. package/templates/nuxt/components/session/SessionBlock.vue.eta +44 -46
  102. package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +24 -15
  103. package/templates/nuxt/components/simpleApp/SimpleAppCalendarInput.vue.eta +64 -0
  104. package/templates/nuxt/components/simpleApp/SimpleAppChildrenList.vue.eta +16 -8
  105. package/templates/nuxt/components/simpleApp/SimpleAppDocumentNo.vue.eta +8 -8
  106. package/templates/nuxt/components/simpleApp/SimpleAppFieldContainer.vue.eta +1 -1
  107. package/templates/nuxt/components/simpleApp/SimpleAppFormToolBar.vue._eta +66 -22
  108. package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +89 -168
  109. package/templates/nuxt/components/simpleApp/SimpleAppInputTable.vue.eta +43 -40
  110. package/templates/nuxt/components/simpleApp/SimpleAppUserPicker.vue.eta +387 -0
  111. package/templates/nuxt/components/text/TextDocStatus.vue._eta +22 -0
  112. package/templates/nuxt/components/user/UserButtonCreateTenant.vue._eta +13 -15
  113. package/templates/nuxt/components/user/UserButtonPermissionInfo.vue.eta +127 -93
  114. package/templates/nuxt/components/user/UserTenantPicker.vue.eta +1 -1
  115. package/templates/nuxt/composables/date.generate.ts.eta +105 -8
  116. package/templates/nuxt/composables/getDocument.generate.ts.eta +8 -6
  117. package/templates/nuxt/composables/getOpenApi.generate.ts.eta +58 -10
  118. package/templates/nuxt/composables/getUserStore.generate.ts.eta +37 -5
  119. package/templates/nuxt/composables/goTo.generate.ts.eta +14 -1
  120. package/templates/nuxt/composables/graphquery.generate.ts.eta +20 -2
  121. package/templates/nuxt/composables/recently.generate.ts.eta +16 -0
  122. package/templates/nuxt/composables/roles.generate.ts.eta +8 -13
  123. package/templates/nuxt/composables/stringHelper.generate.ts.eta +52 -0
  124. package/templates/nuxt/composables/sysmessage.generate.ts.eta +1 -1
  125. package/templates/nuxt/pages/[xorg]/{organization.vue.eta → organization.vue._eta} +38 -9
  126. package/templates/nuxt/pages/[xorg]/user.vue.eta +12 -9
  127. package/templates/nuxt/pages/login.vue._eta +4 -1
  128. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +45 -26
  129. package/templates/nuxt/plugins/70.recently.ts.eta +55 -0
  130. package/templates/nuxt/providers/my-provider.ts.eta +22 -0
  131. package/templates/nuxt/server/api/[xorg]/{[...].ts.eta → [...].ts._eta} +47 -21
  132. package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +44 -3
  133. package/templates/nuxt/types/events.ts.eta +3 -2
  134. package/templates/nuxt/types/others.ts.eta +11 -1
  135. package/templates/nuxt/types/schema.ts.eta +3 -1
  136. package/templates/nuxt/types/simpleappinput.ts.eta +1 -1
  137. package/templates/nuxt/types/user.ts.eta +8 -7
  138. package/templates/project/jsonschemas/branch.json._eta +1 -0
  139. package/templates/project/jsonschemas/invoice.json._eta +4 -3
  140. package/templates/project/jsonschemas/organization.json._eta +2 -2
  141. package/templates/project/lang/default._json +3 -2
  142. package/tsconfig.tsbuildinfo +1 -1
  143. package/templates/nuxt/components/image/ImageAvatar.vue.eta.vue +0 -38
  144. /package/templates/nuxt/pages/[xorg]/mobile/docnoformat/{index.vue.eta → index.vue.etaxxx} +0 -0
  145. /package/templates/nuxt/pages/[xorg]/mobile/{index.vue._eta → index.vue._etaxxx} +0 -0
  146. /package/templates/nuxt/pages/[xorg]/mobile/organization/{[id].vue._eta → [id].vue._etaxxx} +0 -0
  147. /package/templates/nuxt/pages/[xorg]/mobile/{pickgroup.vue._eta → pickgroup.vue._etaxxx} +0 -0
  148. /package/templates/nuxt/pages/[xorg]/mobile/user/{index.vue.eta → index.vue.etaxxx} +0 -0
@@ -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}`,
@@ -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);
@@ -225,7 +231,9 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
225
231
 
226
232
  Object.assign(pipeline[0]['$match'], isolationFilter);
227
233
  //console.log("final agg",pipeline)
228
- return await this.doc.aggregate(pipeline);
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);
@@ -544,11 +579,13 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
544
579
  const existingdata = await this.findById(appuser, id);
545
580
 
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}"`)
582
+ if (typeof data.__v == 'number' && data.__v != existingdata.__v) {
583
+ throw new BadRequestException(
584
+ `You submit older version data "v${data.__v}"" but latest version = "v${existingdata.__v}"`,
585
+ );
549
586
  }
550
587
 
551
- data.__v = existingdata.__v+1
588
+ data.__v = existingdata.__v + 1;
552
589
  if (!existingdata) {
553
590
  throw new NotFoundException(`${id} not found`, 'not found');
554
591
  }
@@ -582,6 +619,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
582
619
  appuser.addUpdatedRecordId(this.documentName, data._id);
583
620
  if (this.hooks.afterUpdate)
584
621
  await this.hooks.afterUpdate(appuser, id, existingdata, result);
622
+ this.callWebhook(appuser, 'update', result);
585
623
  return result; // await this.findById(appuser, id);
586
624
  } catch (err) {
587
625
  this.logger.error(err);
@@ -599,12 +637,13 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
599
637
  if (!existingdata) {
600
638
  throw new NotFoundException(`${id} not found`, 'not found');
601
639
  }
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}"`)
640
+ if (typeof data.__v == 'number' && data.__v != existingdata.__v) {
641
+ throw new BadRequestException(
642
+ `You submit older version data "v${data.__v}"" but latest version = "v${existingdata.__v}"`,
643
+ );
604
644
  }
605
645
 
606
- data.__v = existingdata.__v+1
607
-
646
+ data.__v = existingdata.__v + 1;
608
647
 
609
648
  if (this.hooks.beforeUpdate)
610
649
  await this.hooks.beforeUpdate(appuser, id, data, existingdata);
@@ -641,6 +680,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
641
680
 
642
681
  if (this.hooks.afterUpdate)
643
682
  await this.hooks.afterUpdate(appuser, id, existingdata, result);
683
+ this.callWebhook(appuser, 'update', result);
644
684
  return result; //await this.findById(appuser, id);
645
685
  } catch (err) {
646
686
  throw new InternalServerErrorException(err.message);
@@ -744,6 +784,7 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
744
784
  if (this.hooks.afterSetStatus)
745
785
  await this.hooks.afterSetStatus(appuser, docstatus, finaldata);
746
786
 
787
+ this.callWebhook(appuser, docstatus, finaldata);
747
788
  return updateresult;
748
789
  }
749
790
  }
@@ -928,4 +969,64 @@ export class SimpleAppService<T extends { _id?: string, __v?:number }> {
928
969
  const pdfresult = await this.printapi.getBase64Pdf(appuser, formatid, id);
929
970
  return pdfresult;
930
971
  }
972
+
973
+ searchToAggregate(
974
+ filter: FilterQuery<T>,
975
+ columns: string[],
976
+ sort: string[][],
977
+ lookup: { [key: string]: string },
978
+ ) {
979
+ const pipelines: PipelineStage[] = [];
980
+ const projection = {};
981
+ // console.log('sortsort', sort);
982
+
983
+ pipelines.push({ $match: filter });
984
+ if (Array.isArray(columns) && columns.length > 0) {
985
+ columns.forEach((col) => {
986
+ projection[col] = 1;
987
+ });
988
+ }
989
+
990
+ const collections = Object.keys(lookup);
991
+ collections.forEach((tokey: string) => {
992
+ const toarr = tokey.split('.');
993
+ const to = toarr[0];
994
+ const foreignField = toarr[1] ?? '_id';
995
+ pipelines.push({
996
+ $lookup: {
997
+ from: to,
998
+ as: '_' + to,
999
+ localField: lookup[tokey],
1000
+ foreignField: foreignField,
1001
+ },
1002
+ });
1003
+ pipelines.push({ $unwind: '$_' + to });
1004
+
1005
+ if (Object.keys(projection).length > 0) projection['_' + to] = 1;
1006
+ });
1007
+
1008
+ if (Object.keys(projection).length > 0)
1009
+ pipelines.push({ $project: projection });
1010
+
1011
+ if (Array.isArray(sort) && sort.length > 0) {
1012
+ const sortobj = {};
1013
+ sort.forEach((item) => {
1014
+ sortobj[item[0]] = item[1].toLowerCase() == 'asc' ? 1 : -1;
1015
+ });
1016
+ pipelines.push({ $sort: sortobj });
1017
+ }
1018
+ // console.log('pipelinespipelinespipelines', pipelines);
1019
+
1020
+ return pipelines;
1021
+ }
1022
+
1023
+ callWebhook(appuser: UserContext, actionName: string, data: any) {
1024
+ this.eventEmitter.emit(
1025
+ 'webhook',
1026
+ appuser,
1027
+ this.documentName,
1028
+ actionName,
1029
+ data,
1030
+ );
1031
+ }
931
1032
  }
@@ -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,
@@ -245,4 +245,26 @@ export class ProfileService {
245
245
  async getSession(appuser: UserContext) {
246
246
  return 'OK';
247
247
  }
248
+
249
+
250
+ async runTourComplete(appuser: UserContext, guideName: string) {
251
+ if (!guideName || guideName == '')
252
+ throw new BadRequestException('undefine guideName');
253
+
254
+ const user = await this.usersvc.findById(
255
+ appuser,
256
+ appuser.getId(),
257
+ );
258
+ if(!Array.isArray(user.completedTours)){
259
+ user.completedTours=[]
260
+ }
261
+
262
+ if (!user.completedTours.includes(guideName)) {
263
+
264
+ user.completedTours.push(guideName);
265
+ const res = await this.usersvc.findIdThenUpdate(appuser, user._id, user);
266
+ }
267
+
268
+ return 'ok';
269
+ }
248
270
  }
@@ -10,7 +10,7 @@ import {DocNumberFormatGenerator} from './generate/commons/docnogenerator.servic
10
10
  import { AuditTrail } from './generate/commons/audittrail.service';
11
11
  import { CloudapiModule } from 'src/cloudapi/cloudapi.module';
12
12
  import { PrintapiModule } from 'src/printapi/printapi.module';
13
-
13
+ import { RunWebhookService } from 'src/simpleapp/generate/commons/runwebhook.service'
14
14
  import { UserResolverService } from './services/userresolver.service';
15
15
  // auto import modules
16
16
  <% for(let i=0;i<it.modules.length; i++){ %>
@@ -53,6 +53,7 @@ import { <%=capitalizeFirstLetter(bpmn)%>ListenerService } from 'src/simpleapp/w
53
53
  controllers: [<% for(let i=0;i<it.modules.length; i++){ %><%= it.modules[i].docname %>Controller,<%}%> ProfileController,WorkflowController],
54
54
  providers: [
55
55
  SimpleAppRobotUserService,
56
+ RunWebhookService,
56
57
  AuditTrail,DocNumberFormatGenerator,<% for(let i=0;i<it.modules.length; i++){ %>
57
58
  <%= it.modules[i].docname %>Service,
58
59
  <%= it.modules[i].docname %>Resolver,
@@ -5,6 +5,9 @@
5
5
  * author: Ks Tan
6
6
  */
7
7
  /* calendar */
8
+ .vuecal .p-button{
9
+ color: initial;
10
+ }
8
11
 
9
12
  #monthviewcal .vuecal__cell--current,
10
13
  #monthviewcal .vuecal__cell--today {
@@ -9,7 +9,7 @@
9
9
  @apply bg-gray-100 dark:bg-slate-800 dark:text-gray-300
10
10
  }
11
11
 
12
- [disabled=true],input[disabled] ,input[readonly] ,textarea[readonly]{
12
+ [disabled=true],input[disabled] ,input[readonly] ,textarea[readonly], .p-dropdown[readonly]{
13
13
  @apply bg-gray-300 dark:bg-gray-600
14
14
  }
15
15
 
@@ -24,7 +24,12 @@ const CustomTailwind = usePassThrough(
24
24
  root:{class:'bg-white dark:bg-gray-800 shadow p-2 rounded-2xl'},
25
25
  // title:{class:''},
26
26
  // header:{class:''}
27
- },
27
+ },
28
+ fieldset:{
29
+ root:{class:'border p-2 mt-1'},
30
+ legend:{class:''},
31
+ content:{class:'p-2'}
32
+ },
28
33
  // tabview:{
29
34
  // tabpanel:{
30
35
  // headeraction:{class:'p-tabview-nav-link p-tabview-header-action items-center cursor-pointer flex overflow-hidden relative select-none text-decoration-none select-none border-b-2 p-5 font-bold rounded-t-md transition-shadow duration-200 m-0 transition-colors duration-200 bg-white border-blue-500 text-blue-500 dark:bg-gray-600 dark:border-blue-300 dark:text-blue-300'}
@@ -1,66 +1,67 @@
1
1
  <template>
2
2
  <ButtonDefault v-if="!actionName" :animate="animate">
3
- <i :class="getIcon()"/><slot></slot>def</ButtonDefault
3
+ <i :class="getIcon()" /><slot></slot>def</ButtonDefault
4
4
  >
5
5
  <ButtonPrimary
6
- v-else-if="['create', 'update','confirm'].includes(actionName)"
6
+ v-else-if="['create', 'update', 'confirm'].includes(actionName)"
7
7
  :animate="animate"
8
- >
9
- <i :class="getIcon()"/>
8
+ >
9
+ <i :class="getIcon()" />
10
10
  <slot></slot
11
11
  ></ButtonPrimary>
12
-
12
+
13
13
  <ButtonDanger
14
14
  v-else-if="['delete', 'void'].includes(actionName)"
15
15
  :animate="animate"
16
- >
17
- <i :class="getIcon()"/>
16
+ >
17
+ <i :class="getIcon()" />
18
18
  <slot></slot>
19
19
  </ButtonDanger>
20
20
  <ButtonWarning v-else-if="['draft'].includes(actionName)" :animate="animate">
21
- <i :class="getIcon()"/>
21
+ <i :class="getIcon()" />
22
22
  <slot></slot>
23
- </ButtonWarning>
24
- <ButtonDefault
25
- v-else
26
- :animate="animate"
27
- >
28
- <i :class="getIcon()"/>
23
+ </ButtonWarning>
24
+ <ButtonSecondary v-else-if="actionName == 'print'">
25
+ <i :class="getIcon()" />
26
+ <slot></slot
27
+ ></ButtonSecondary>
28
+ <ButtonDefault v-else :animate="animate">
29
+ <i :class="getIcon()" />
29
30
  <slot></slot
30
31
  ></ButtonDefault>
31
32
  </template>
32
33
  <script setup lang="ts">
33
34
  /**
34
35
  * This file was automatically generated by simpleapp generator during initialization. It is changable.
36
+ * --remove-this-line-to-prevent-override--
35
37
  * last change 2024-03-01
36
38
  * author: Ks Tan
37
39
  */
38
40
 
39
41
  const props = defineProps<{ actionName?: string; animate?: boolean }>();
40
- const getIcon = ()=>{
41
- let cssname='mr-1 pi ';
42
- switch(props.actionName){
43
- case 'create':
44
- case 'update':
45
- cssname+='pi-save';
46
- break;
47
- case 'delete':
48
- cssname+='pi-trash';
49
- break;
50
- case 'print':
51
- cssname+='pi-file-pdf';
52
- break;
53
- case 'confirm':
54
- cssname+='pi-check';
55
- break;
56
- case 'void':
57
- cssname+='pi-file-excel';
58
- break;
59
- case 'draft':
60
- cssname+='pi-file-edit';
61
- break;
42
+ const getIcon = () => {
43
+ let cssname = "mr-1 pi ";
44
+ switch (props.actionName) {
45
+ case "create":
46
+ case "update":
47
+ cssname += "pi-save";
48
+ break;
49
+ case "delete":
50
+ cssname += "pi-trash";
51
+ break;
52
+ case "print":
53
+ cssname += "pi-file-pdf";
54
+ break;
55
+ case "confirm":
56
+ cssname += "pi-check";
57
+ break;
58
+ case "void":
59
+ cssname += "pi-file-excel";
60
+ break;
61
+ case "draft":
62
+ cssname += "pi-file-edit";
63
+ break;
62
64
  }
63
- return cssname
64
- }
65
-
65
+ return cssname;
66
+ };
66
67
  </script>
@@ -1,12 +1,20 @@
1
1
  <template>
2
2
  <Button
3
3
  v-if="isMobile()"
4
- :class="`w-full rounded-full text-center block dark:bg-danger-600 bg-danger-600 active:dark:bg-danger-400 text-white ${animate ? 'animate-bounce' :'' }`"
4
+ severity="danger"
5
+ :class="`w-full rounded-full text-center block ${
6
+ animate ? 'animate-bounce' : ''
7
+ }`"
5
8
  @click="onActivate"
6
9
  >
7
10
  <slot></slot>
8
11
  </Button>
9
- <Button v-else :class="`btn-danger ${animate ? 'animate-bounce' :'' }`" @click="onActivate">
12
+ <Button
13
+ v-else
14
+ severity="danger"
15
+ :class="`${animate ? 'animate-bounce' : ''}`"
16
+ @click="onActivate"
17
+ >
10
18
  <slot></slot>
11
19
  </Button>
12
20
  </template>
@@ -18,7 +26,7 @@
18
26
  * author: Ks Tan
19
27
  */
20
28
  const emits = defineEmits(["click"]);
21
- const props = defineProps<{animate?:boolean}>()
29
+ const props = defineProps<{ animate?: boolean }>();
22
30
  const onActivate = (e: Event) => {
23
31
  emits("click", e);
24
32
  };
@@ -1,12 +1,20 @@
1
1
  <template>
2
2
  <Button
3
3
  v-if="isMobile()"
4
- :class="`w-full rounded-full text-center block dark:bg-gray-600 bg-gray-600 active:dark:bg-gray-400 text-white ${animate ? 'animate-bounce' :'' }`"
4
+ severity="secondary"
5
+ :class="`w-full rounded-full text-center block ${
6
+ animate ? 'animate-bounce' : ''
7
+ }`"
5
8
  @click="onActivate"
6
9
  >
7
10
  <slot></slot>
8
11
  </Button>
9
- <Button v-else :class="`btn-default ${animate ? 'animate-bounce' :'' }`" @click="onActivate">
12
+ <Button
13
+ v-else
14
+ severity="secondary"
15
+ :class="`${animate ? 'animate-bounce' : ''}`"
16
+ @click="onActivate"
17
+ >
10
18
  <slot></slot>
11
19
  </Button>
12
20
  </template>
@@ -18,7 +26,7 @@
18
26
  * author: Ks Tan
19
27
  */
20
28
  const emits = defineEmits(["click"]);
21
- const props = defineProps<{animate?:boolean}>()
29
+ const props = defineProps<{ animate?: boolean }>();
22
30
  const onActivate = (e: Event) => {
23
31
  emits("click", e);
24
32
  };
@@ -1,12 +1,18 @@
1
1
  <template>
2
2
  <Button
3
3
  v-if="isMobile()"
4
- :class="`w-full rounded-full text-center block dark:bg-primary-600 bg-primary-600 active:dark:bg-primary-400 text-white ${animate ? 'animate-bounce' :'' }`"
4
+ :class="`w-full rounded-full text-center block dark:bg-primary-600 bg-primary-600 active:dark:bg-primary-400 text-white ${
5
+ animate ? 'animate-bounce' : ''
6
+ }`"
5
7
  @click="onActivate"
6
8
  >
7
9
  <slot></slot>
8
10
  </Button>
9
- <Button v-else :class="`btn-primary ${animate ? 'animate-bounce' :'' }`" @click="onActivate">
11
+ <Button
12
+ v-else
13
+ :class="`btn-primary ${animate ? 'animate-bounce' : ''}`"
14
+ @click="onActivate"
15
+ >
10
16
  <slot></slot>
11
17
  </Button>
12
18
  </template>
@@ -18,7 +24,7 @@
18
24
  * author: Ks Tan
19
25
  */
20
26
  const emits = defineEmits(["click"]);
21
- const props = defineProps<{animate?:boolean}>()
27
+ const props = defineProps<{ animate?: boolean }>();
22
28
  const onActivate = (e: Event) => {
23
29
  emits("click", e);
24
30
  };