@simitgroup/simpleapp-generator 1.0.58 → 1.0.60
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/README.md +3 -2
- package/dist/buildinschemas/branch.d.ts.map +1 -1
- package/dist/buildinschemas/branch.js +1 -0
- package/dist/buildinschemas/branch.js.map +1 -1
- package/dist/buildinschemas/organization.d.ts.map +1 -1
- package/dist/buildinschemas/organization.js +1 -0
- package/dist/buildinschemas/organization.js.map +1 -1
- package/dist/buildinschemas/permission.js +5 -5
- package/dist/buildinschemas/permission.js.map +1 -1
- package/dist/buildinschemas/user.d.ts.map +1 -1
- package/dist/buildinschemas/user.js +4 -1
- package/dist/buildinschemas/user.js.map +1 -1
- package/dist/framework.js +1 -1
- package/dist/framework.js.map +1 -1
- package/dist/generate.js +6 -1
- package/dist/generate.js.map +1 -1
- package/dist/type.d.ts +1 -0
- package/dist/type.d.ts.map +1 -1
- package/docs/backend.md +89 -0
- package/docs/formula.md +0 -0
- package/docs/frontend.md +57 -0
- package/docs/jsonschema.md +12 -3
- package/package.json +1 -1
- package/src/buildinschemas/branch.ts +1 -0
- package/src/buildinschemas/organization.ts +1 -0
- package/src/buildinschemas/permission.ts +5 -5
- package/src/buildinschemas/user.ts +4 -1
- package/src/framework.ts +1 -1
- package/src/generate.ts +6 -1
- package/src/type.ts +1 -0
- package/templates/basic/nest/controller.ts.eta +5 -3
- package/templates/basic/nest/model.ts.eta +32 -7
- package/templates/basic/nuxt/pages.crud.vue.eta +59 -163
- package/templates/basic/nuxt/pages.index.vue.eta +225 -0
- package/templates/nest/.env._eta +1 -0
- package/templates/nest/src/simpleapp/generate/commons/exceptions/SimpleAppExceptionFilter.ts.eta +1 -1
- package/templates/nest/src/simpleapp/generate/commons/roles/roles.group.ts.eta +1 -1
- package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +157 -23
- package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +22 -15
- package/templates/nest/src/simpleapp/generate/types/index.ts.eta +8 -0
- package/templates/nest/src/simpleapp/profile/profile.controller.ts.eta +25 -2
- package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +23 -6
- package/templates/nest/src/simpleapp/services/branch.service.ts.eta +41 -40
- package/templates/nest/src/simpleapp/services/user.service.ts.eta +10 -9
- package/templates/nuxt/app.vue.eta +2 -1
- package/templates/nuxt/assets/css/style.css._eta +3 -12
- package/templates/nuxt/assets/primevue/passthrough.ts._eta +24 -20
- package/templates/nuxt/components/ButtonCreateTenant.vue.eta +30 -23
- package/templates/nuxt/components/ButtonHome.vue.eta +15 -2
- package/templates/nuxt/components/ButtonMenuPicker.vue.eta +5 -20
- package/templates/nuxt/components/ButtonPermissionInfo.vue.eta +5 -7
- package/templates/nuxt/components/ButtonProfile.vue.eta +42 -25
- package/templates/nuxt/components/CrudSimple.vue.eta +1 -1
- package/templates/nuxt/components/EventDecision.vue.eta +115 -0
- package/templates/nuxt/components/EventNotification.vue.eta +157 -0
- package/templates/nuxt/components/HeaderBar.vue.eta +2 -2
- package/templates/nuxt/components/Invitation.vue.eta +3 -3
- package/templates/nuxt/components/SelectBranch.vue.eta +5 -2
- package/templates/nuxt/components/SimpleAppDatatable.vue.eta +151 -5
- package/templates/nuxt/components/TenantPicker.vue.eta +75 -0
- package/templates/nuxt/components/UserProfileListItem.vue.eta +65 -0
- package/templates/nuxt/components/renderers/BooleanRender.vue.eta +7 -0
- package/templates/nuxt/components/renderers/DateRender.vue.eta +6 -0
- package/templates/nuxt/components/renderers/ForeignKeyRender.vue.eta +10 -0
- package/templates/nuxt/components/renderers/MoneyRender.vue.eta +7 -0
- package/templates/nuxt/components/renderers/MultiTextRender.vue.eta +11 -0
- package/templates/nuxt/composables/getDocument.generate.ts.eta +4 -0
- package/templates/nuxt/composables/getMenus.generate.ts.eta +35 -31
- package/templates/nuxt/composables/getUserStore.generate.ts.eta +6 -1
- package/templates/nuxt/composables/goTo.generate.ts.eta +15 -0
- package/templates/nuxt/composables/notifications.generate.ts.eta +21 -0
- package/templates/nuxt/composables/stringHelper.generate.ts.eta +11 -1
- package/templates/nuxt/error.vue._eta +20 -5
- package/templates/nuxt/layouts/documentlist.vue.eta +166 -0
- package/templates/nuxt/middleware/30.acl.global.ts.eta +4 -1
- package/templates/nuxt/pages/[xorg]/organization/index.vue.eta +4 -4
- package/templates/nuxt/pages/[xorg]/profile.vue.eta +6 -0
- package/templates/nuxt/pages/[xorg]/user/[id].vue.eta +6 -0
- package/templates/nuxt/pages/[xorg]/user/index.vue.eta +211 -377
- package/templates/nuxt/pages/[xorg]/user.vue.eta +197 -0
- package/templates/nuxt/pages/index.vue._eta +101 -0
- package/templates/nuxt/pages/profile.vue.eta +94 -0
- package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +4 -4
- package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +11 -10
- package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +69 -17
- package/templates/nuxt/simpleapp/generate/commons/documents.ts.eta +6 -3
- package/templates/nuxt/tailwind.config.ts._eta +10 -0
- package/templates/nuxt/types/documentlist.ts.eta +9 -0
- package/templates/nuxt/types/events.ts.eta +20 -0
- package/templates/nuxt/types/index.ts.eta +6 -79
- package/templates/nuxt/types/notifications.ts.eta +16 -0
- package/templates/nuxt/types/others.ts.eta +42 -0
- package/templates/nuxt/types/user.ts.eta +44 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/templates/nest/src/simpleapp/generate/models/perm.model.ts.eta +0 -52
- package/templates/nest/src/simpleapp/generate/models/tenant.model.ts.eta +0 -43
- package/templates/nest/src/simpleapp/generate/models/user.model.ts.eta +0 -56
- package/templates/nuxt/components/EventMonitor.vue.eta +0 -85
- package/templates/nuxt/pages/[xorg]/tenant/index.vue.eta +0 -89
- package/templates/nuxt/pages/index.vue.eta +0 -116
- package/templates/nuxt/simpleapp/generate/commons/events.ts.eta +0 -11
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Injectable, Scope,Inject,Logger, BadRequestException } from '@nestjs/common';
|
|
8
8
|
import { Model, model, connect, PipelineStage } from 'mongoose';
|
|
9
|
+
import {ModifiedCollection,ModifiedRecords} from '../types'
|
|
9
10
|
import _ from 'lodash'
|
|
10
11
|
import { Module } from '@nestjs/common';
|
|
11
12
|
import * as jwt from 'jsonwebtoken';
|
|
@@ -20,8 +21,10 @@ import { Permission, } from './../types/perm.type';
|
|
|
20
21
|
import {ProfileUserBranch , ProfileUserInvites} from '../../profile/profile.types'
|
|
21
22
|
|
|
22
23
|
import {ClientSession} from 'mongoose'
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
@Injectable({scope:Scope.REQUEST})
|
|
24
26
|
export class UserContext {
|
|
27
|
+
protected sessionId : string =crypto.randomUUID()
|
|
25
28
|
protected logger = new Logger()
|
|
26
29
|
protected uid: string = '';
|
|
27
30
|
protected _id: string = '';
|
|
@@ -41,19 +44,20 @@ export class UserContext {
|
|
|
41
44
|
protected orgCode: string = '';
|
|
42
45
|
protected orgName: string = '';
|
|
43
46
|
protected branches: any[] = []
|
|
47
|
+
protected lastActivity : string = new Date().toISOString()
|
|
44
48
|
protected invites: any[] = [] //User + field tenant:Tenant[]
|
|
45
49
|
protected roles: string[] = [];
|
|
46
|
-
|
|
50
|
+
protected modifiedRecords:ModifiedRecords = {createds:{},updateds:{},deleteds:{}}
|
|
47
51
|
|
|
48
52
|
constructor(
|
|
49
53
|
private readonly usermodel:Model<User>,
|
|
50
54
|
private readonly permmodel:Model<Permission>,
|
|
51
|
-
private dbsession:ClientSession
|
|
55
|
+
private dbsession:ClientSession,
|
|
56
|
+
|
|
52
57
|
) {
|
|
53
58
|
|
|
54
59
|
}
|
|
55
60
|
getDBSession = ():ClientSession => this.dbsession
|
|
56
|
-
|
|
57
61
|
getId = () => this._id;
|
|
58
62
|
getUid = () => this.uid;
|
|
59
63
|
getUname = () => this.uname;
|
|
@@ -64,6 +68,7 @@ export class UserContext {
|
|
|
64
68
|
getEmail = () => this.email;
|
|
65
69
|
getGroup = () => this.group;
|
|
66
70
|
getRoles = () => this.roles;
|
|
71
|
+
getModifieds = () => this.modifiedRecords
|
|
67
72
|
getBranches = ():ProfileUserBranch[] => {
|
|
68
73
|
this.branches;
|
|
69
74
|
const data:ProfileUserBranch[] = []
|
|
@@ -118,21 +123,19 @@ export class UserContext {
|
|
|
118
123
|
*/
|
|
119
124
|
obtainProfileFromDb = async () : Promise<User|undefined>=>{
|
|
120
125
|
const filter = { $match:{uid:this.uid,tenantId:this.tenantId} }
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
126
|
|
|
125
127
|
const joinpermission:PipelineStage = {$lookup: {
|
|
126
128
|
from : 'permission',
|
|
127
|
-
localField : '
|
|
128
|
-
foreignField : '
|
|
129
|
+
localField : '_id',
|
|
130
|
+
foreignField : 'userId',
|
|
129
131
|
as : 'permissions',
|
|
130
132
|
pipeline:[
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
{
|
|
134
|
+
$match:{
|
|
135
|
+
// userId:this.getId(),
|
|
136
|
+
tenantId:this.tenantId,
|
|
137
|
+
orgId:this.orgId,
|
|
138
|
+
branchId:this.branchId,
|
|
136
139
|
}},
|
|
137
140
|
{$lookup:{from: 'branch',localField: 'branchId',foreignField:'branchId',as: 'currentbranch'}},
|
|
138
141
|
{$lookup:{from: 'organization',localField: 'orgId',foreignField:'orgId',as: 'currentorg'}}
|
|
@@ -153,22 +156,38 @@ export class UserContext {
|
|
|
153
156
|
// console.log("obtainProfileFromDbobtainProfileFromDb ",users)
|
|
154
157
|
if(users && users.length>0){
|
|
155
158
|
const userinfo = users[0]
|
|
156
|
-
|
|
159
|
+
console.log("userinfouserinfouserinfouserinfouserinfouserinfo ",userinfo)
|
|
157
160
|
|
|
158
161
|
if(this.tenantId>0){
|
|
159
162
|
const myperm=userinfo.permissions[0]
|
|
160
163
|
if(myperm && myperm.group){
|
|
161
164
|
userinfo.group = myperm.group
|
|
162
|
-
userinfo.roles = rolegroups[userinfo.group]
|
|
165
|
+
userinfo.roles = rolegroups[userinfo.group]()
|
|
163
166
|
userinfo.branchCode = myperm.currentbranch[0].branchCode
|
|
164
167
|
userinfo.branchName = myperm.currentbranch[0].branchName
|
|
165
168
|
userinfo.orgCode = myperm.currentorg[0].orgCode
|
|
166
169
|
userinfo.orgName = myperm.currentorg[0].orgName
|
|
170
|
+
|
|
167
171
|
}
|
|
168
172
|
}else{
|
|
169
173
|
userinfo.group = ''
|
|
170
174
|
}
|
|
175
|
+
console.log('userinfouserinfouserinfouserinfo',userinfo)
|
|
176
|
+
const currentitme = new Date(this.lastActivity).getTime()
|
|
177
|
+
console.log(" userinfo.lastactivity userinfo.lastactivity userinfo.lastactivity ", userinfo.lastActivity )
|
|
178
|
+
const dblastactivity = userinfo.lastActivity ?? '2000-01-01T00:00:00Z'
|
|
179
|
+
const lastvisit = new Date( dblastactivity).getTime() ?? 0
|
|
180
|
+
// if(currentitme - lastvisit)
|
|
181
|
+
console.log(`${userinfo._id}: ${this.lastActivity}: ${currentitme} - ${dblastactivity}:${lastvisit} = ${currentitme - lastvisit}`)
|
|
182
|
+
|
|
183
|
+
//update last activtity dont too frequent
|
|
184
|
+
if(!dblastactivity || currentitme - lastvisit > 5000 ){
|
|
185
|
+
const newusermodel = await this.usermodel.findById(userinfo._id)
|
|
186
|
+
newusermodel.lastActivity= this.lastActivity
|
|
187
|
+
const result = await newusermodel.save()
|
|
188
|
+
}
|
|
171
189
|
|
|
190
|
+
// const result = await this.usermodel.findOneAndUpdate({_id: userinfo._id},{lastActivity: new Date().toISOString})
|
|
172
191
|
return userinfo
|
|
173
192
|
}else{
|
|
174
193
|
return undefined
|
|
@@ -290,6 +309,7 @@ export class UserContext {
|
|
|
290
309
|
// obtain basic user info
|
|
291
310
|
const userinfo = {
|
|
292
311
|
_id: this.getId() ,
|
|
312
|
+
sessionId:this.sessionId,
|
|
293
313
|
tenantId: this.getTenantId(),
|
|
294
314
|
orgId: this.getOrgId(),
|
|
295
315
|
branchId: this.getBranchId(),
|
|
@@ -309,14 +329,17 @@ export class UserContext {
|
|
|
309
329
|
|
|
310
330
|
if(this.getId()!=''){
|
|
311
331
|
this.logger.debug(userinfo,"obtain permissions and invitations")
|
|
312
|
-
const filter:PipelineStage ={ $match:{
|
|
332
|
+
const filter:PipelineStage ={ $match:{
|
|
333
|
+
uid:this.uid,
|
|
334
|
+
tenantId :this.tenantId
|
|
335
|
+
}} as PipelineStage
|
|
313
336
|
const permission:PipelineStage = {$lookup: {
|
|
314
337
|
from : 'permission',
|
|
315
|
-
localField : '
|
|
316
|
-
foreignField : '
|
|
338
|
+
localField : '_id',
|
|
339
|
+
foreignField : 'userId',
|
|
317
340
|
as : 'permissions',
|
|
318
341
|
pipeline:[
|
|
319
|
-
{$match:{
|
|
342
|
+
// {$match:{userId: this.getId(),},},
|
|
320
343
|
{$lookup:{from : 'branch',localField : 'branchId',foreignField : 'branchId',as : 'branch',}},
|
|
321
344
|
]
|
|
322
345
|
}}
|
|
@@ -339,6 +362,7 @@ export class UserContext {
|
|
|
339
362
|
this.logger.debug(pipeline,"getUserInfo")
|
|
340
363
|
// // // const users = await usermodel.find(filter)
|
|
341
364
|
const users = await this.usermodel.aggregate(pipeline)
|
|
365
|
+
this.logger.debug(users,'users from aggregate')
|
|
342
366
|
|
|
343
367
|
|
|
344
368
|
this.invites = users[0].invites
|
|
@@ -387,13 +411,123 @@ export class UserContext {
|
|
|
387
411
|
const o = this.ssoACL
|
|
388
412
|
const ssoclient = process.env.OAUTH2_CLIENTID
|
|
389
413
|
const adminRole = process.env.OAUTH2_ADMINROLE
|
|
390
|
-
|
|
391
|
-
|
|
414
|
+
// return false
|
|
415
|
+
if(this.getEmail()===process.env.ADMIN_EMAIL){
|
|
416
|
+
return true
|
|
417
|
+
}
|
|
418
|
+
else if( o[ssoclient] && o[ssoclient]['roles'] && o[ssoclient]['roles'] == adminRole ){
|
|
392
419
|
return true
|
|
393
420
|
}else{
|
|
394
|
-
//console.log("not admin")
|
|
395
421
|
return false
|
|
396
422
|
}
|
|
397
423
|
|
|
398
424
|
}
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
searchInsertedRecordId(collection:string,_id:string){
|
|
428
|
+
return this.modifiedRecords.createds[collection].find((item)=>item===_id)
|
|
429
|
+
}
|
|
430
|
+
addInsertedRecordId(collection:string,_id:string){
|
|
431
|
+
if(this.modifiedRecords.createds[collection]){
|
|
432
|
+
this.modifiedRecords.createds[collection].push(_id)
|
|
433
|
+
}else{
|
|
434
|
+
this.modifiedRecords.createds[collection] = [_id]
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
addUpdatedRecordId(collection:string,_id:string){
|
|
438
|
+
if(this.modifiedRecords.updateds[collection]){
|
|
439
|
+
this.modifiedRecords.updateds[collection].push(_id)
|
|
440
|
+
}else{
|
|
441
|
+
this.modifiedRecords.updateds[collection] = [_id]
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
}
|
|
445
|
+
addDeletedRecordId(collection:string,_id:string){
|
|
446
|
+
if(this.modifiedRecords.deleteds[collection]){
|
|
447
|
+
this.modifiedRecords.deleteds[collection].push(_id)
|
|
448
|
+
}else{
|
|
449
|
+
this.modifiedRecords.deleteds[collection] = [_id]
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
async getAllTenants (){
|
|
456
|
+
const results = []
|
|
457
|
+
if(this.getId()!=''){
|
|
458
|
+
const filteruser:PipelineStage ={ $match:{
|
|
459
|
+
uid:this.uid,
|
|
460
|
+
tenantId :{'$gt':0}
|
|
461
|
+
}} as PipelineStage
|
|
462
|
+
|
|
463
|
+
const getTenantData:PipelineStage = { $lookup:{
|
|
464
|
+
from : 'tenant',
|
|
465
|
+
localField : 'tenantId',
|
|
466
|
+
foreignField : 'tenantId',
|
|
467
|
+
as : 'tenant',}}
|
|
468
|
+
|
|
469
|
+
const permission:PipelineStage = {$lookup: {
|
|
470
|
+
from : 'permission',
|
|
471
|
+
localField : '_id',
|
|
472
|
+
foreignField : 'userId',
|
|
473
|
+
as : 'permissions',
|
|
474
|
+
pipeline:[
|
|
475
|
+
|
|
476
|
+
{$lookup:{from : 'organization',localField : 'orgId',foreignField : 'orgId',as : 'org',}},
|
|
477
|
+
{$lookup:{from : 'branch',localField : 'branchId',foreignField : 'branchId',as : 'branch',}},
|
|
478
|
+
]
|
|
479
|
+
}}
|
|
480
|
+
|
|
481
|
+
const pipelines:PipelineStage[] =[filteruser,getTenantData,permission]
|
|
482
|
+
// const users=[]
|
|
483
|
+
this.logger.warn(pipelines,"pipelines")
|
|
484
|
+
const users = await this.usermodel.aggregate(pipelines)
|
|
485
|
+
|
|
486
|
+
if(users){
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
const activeusers = users.filter((u)=>{
|
|
490
|
+
// console.log(u.active,'===',true, ' && ',u.tenant[0].active,'===',true)
|
|
491
|
+
return u.active===true && u.tenant[0].active===true
|
|
492
|
+
})
|
|
493
|
+
// return activeusers
|
|
494
|
+
activeusers.forEach((u)=>{
|
|
495
|
+
|
|
496
|
+
const permissions = u.permissions.filter((item:any)=>{
|
|
497
|
+
return item.org[0].active && item.branch[0].active
|
|
498
|
+
})
|
|
499
|
+
.map((item:any)=>{
|
|
500
|
+
|
|
501
|
+
return {
|
|
502
|
+
_id: item._id,
|
|
503
|
+
orgId: item.orgId,
|
|
504
|
+
branchId: item.branchId,
|
|
505
|
+
group: item.group,
|
|
506
|
+
orgCode: item.org[0].orgCode,
|
|
507
|
+
orgName: item.org[0].orgName,
|
|
508
|
+
branchCode: item.branch[0].branchCode,
|
|
509
|
+
branchName: item.branch[0].branchName,
|
|
510
|
+
xOrg: this.generateXorg(u.tenantId,item.orgId,item.branchId)
|
|
511
|
+
}
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
results.push({
|
|
518
|
+
_id: u._id,
|
|
519
|
+
fullname : u.fullname,
|
|
520
|
+
tenantId: u.tenantId,
|
|
521
|
+
tenantName: u.tenant[0].tenantName,
|
|
522
|
+
permissions: permissions
|
|
523
|
+
})
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
}
|
|
531
|
+
return results
|
|
532
|
+
}
|
|
399
533
|
}
|
|
@@ -236,7 +236,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
236
236
|
await this.hook(appuser,HookType.beforeSearch, newfilters);
|
|
237
237
|
// console.log("before _find",newfilters)
|
|
238
238
|
// console.log("this.doc",this.doc)
|
|
239
|
-
const products = await this.doc.find(newfilters,projection).sort(sort);
|
|
239
|
+
const products = await this.doc.find(newfilters,projection,{session:appuser.getDBSession()}).sort(sort);
|
|
240
240
|
// console.log("after search",products)
|
|
241
241
|
const productlist = products.map((p: T) => {
|
|
242
242
|
return p;
|
|
@@ -264,7 +264,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
264
264
|
|
|
265
265
|
|
|
266
266
|
async create(appuser:UserContext, data:T) {
|
|
267
|
-
|
|
267
|
+
|
|
268
268
|
let result;
|
|
269
269
|
if(!data._id){
|
|
270
270
|
data._id = crypto.randomUUID()
|
|
@@ -279,7 +279,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
279
279
|
if(this.withDocNumberFormat && !data[this.documentIdentityCode]){
|
|
280
280
|
await this.genNewDocNo(appuser,data)
|
|
281
281
|
}
|
|
282
|
-
|
|
282
|
+
|
|
283
283
|
await this.hook(appuser,HookType.beforeCreate, data);
|
|
284
284
|
|
|
285
285
|
let isolationFilter:any = {...appuser.getCreateFilter()}
|
|
@@ -297,9 +297,10 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
297
297
|
|
|
298
298
|
this.applyNestedDateTime(appuser,data,'create')
|
|
299
299
|
const newdoc = new this.doc(data);
|
|
300
|
-
await this.
|
|
300
|
+
await this.identifyForeignKeys(appuser,data)
|
|
301
301
|
try{
|
|
302
302
|
result = await newdoc.save({session:dbsession})
|
|
303
|
+
appuser.addInsertedRecordId(this.documentName, result._id)
|
|
303
304
|
}catch(err){
|
|
304
305
|
this.logger.error(err)
|
|
305
306
|
throw new InternalServerErrorException(err)
|
|
@@ -429,6 +430,8 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
429
430
|
filterIsolation['_id'] = id;
|
|
430
431
|
this.logger.debug('delete filter', filterIsolation);
|
|
431
432
|
const result = await this.doc.deleteOne(filterIsolation).session(dbsession);
|
|
433
|
+
|
|
434
|
+
appuser.addUpdatedRecordId(this.documentName, id)
|
|
432
435
|
const deleteresult = {result:result, data: deletedata}
|
|
433
436
|
this.logger.debug(deleteresult, " delete result" +this.doc.collection.name,)
|
|
434
437
|
// this.doc.findByIdAndDelete(id)
|
|
@@ -478,6 +481,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
478
481
|
this.applyNestedDateTime(appuser,data,'update')
|
|
479
482
|
try{
|
|
480
483
|
const result = await this.doc.findOneAndUpdate(isolationFilter, data).session(dbsession);
|
|
484
|
+
appuser.addUpdatedRecordId(this.documentName, data._id)
|
|
481
485
|
await this.hook(appuser,HookType.afterUpdate, data);
|
|
482
486
|
return result;
|
|
483
487
|
} catch (err) {
|
|
@@ -571,7 +575,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
571
575
|
}
|
|
572
576
|
|
|
573
577
|
|
|
574
|
-
async
|
|
578
|
+
async identifyForeignKeys(appuser:UserContext,data:T){
|
|
575
579
|
/**
|
|
576
580
|
* 1. looping schemas identify what foreign key exists
|
|
577
581
|
* 2. loop through record obtain all foreign key value
|
|
@@ -590,9 +594,9 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
590
594
|
const fks:string[] = this.foreignkeys[collectionname]
|
|
591
595
|
let results:string[] = []
|
|
592
596
|
fks.forEach(fieldpath=>{
|
|
593
|
-
|
|
597
|
+
console.log("fieldpath:",fieldpath,"vdata",data,vdata)
|
|
594
598
|
const tmp = jsonpath.query(vdata,fieldpath).filter((item:string)=>item!='')
|
|
595
|
-
|
|
599
|
+
console.log("tmp",tmp)
|
|
596
600
|
|
|
597
601
|
results = results.concat(tmp)
|
|
598
602
|
})
|
|
@@ -600,12 +604,12 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
600
604
|
|
|
601
605
|
|
|
602
606
|
if(results.length>0){
|
|
603
|
-
console.log('tmp',results)
|
|
604
607
|
if(results.length>1){
|
|
605
608
|
results = uniq<string>(results)
|
|
606
609
|
}
|
|
607
610
|
|
|
608
611
|
keystore[collectionname]= results
|
|
612
|
+
console.log("keystorekeystore",keystore)
|
|
609
613
|
let addfield={$addFields:{collection:collectionname}}
|
|
610
614
|
|
|
611
615
|
const stagefilter:PipelineStage = {
|
|
@@ -614,23 +618,23 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
614
618
|
pipelines.push(stagefilter)
|
|
615
619
|
}
|
|
616
620
|
})
|
|
617
|
-
this.logger.
|
|
621
|
+
this.logger.log(pipelines,'identifyForeignKeys pipelines')
|
|
618
622
|
// this.doc.db.collection(collectionname);
|
|
619
623
|
const unionresult = await this.doc.aggregate(pipelines)
|
|
620
624
|
|
|
621
625
|
if(!unionresult){
|
|
622
|
-
this.logger.error("foreign key control failed ",'
|
|
626
|
+
this.logger.error("foreign key control failed ",'identifyForeignKeys')
|
|
623
627
|
throw new InternalServerErrorException("Foreignkey check execution error",pipelines as HttpExceptionOptions)
|
|
624
628
|
}else{
|
|
625
629
|
let searchresult:any = {}
|
|
626
630
|
unionresult.forEach(item=>{
|
|
627
|
-
console.log("111")
|
|
628
631
|
if(searchresult[item.collection]){
|
|
629
632
|
searchresult[item.collection].push(item._id)
|
|
630
633
|
}else{
|
|
631
634
|
searchresult[item.collection] = [item._id]
|
|
632
635
|
}
|
|
633
636
|
})
|
|
637
|
+
this.logger.log(unionresult,this.documentType+" search Result")
|
|
634
638
|
|
|
635
639
|
//search is it all foreign key exists in db
|
|
636
640
|
for(let i=0; i<collections.length; i++){
|
|
@@ -643,11 +647,15 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
643
647
|
const key = keys[k]
|
|
644
648
|
if(searchresult[collectionname] && searchresult[collectionname].includes(key)){
|
|
645
649
|
this.logger.debug(`foreignkey ${collectionname}->${key} exists`)
|
|
646
|
-
|
|
650
|
+
}
|
|
651
|
+
else if(appuser.searchInsertedRecordId(collectionname,key)){
|
|
652
|
+
this.logger.debug(`foreignkey ${collectionname} exists in user context which not yet commited`)
|
|
653
|
+
}
|
|
647
654
|
else{
|
|
648
|
-
this.logger.warn(
|
|
655
|
+
this.logger.warn(`${this.documentType}: Foreignkey ${key} at collection ${collectionname} does not exist`,'identifyForeignKeys')
|
|
656
|
+
this.logger.log(appuser.getModifieds,"appuser.getModifieds")
|
|
649
657
|
const errordata = {key:key,collection:collectionname}
|
|
650
|
-
throw new BadRequestException(
|
|
658
|
+
throw new BadRequestException(`${this.documentType}: Foreignkey ${key} at collection ${collectionname} does not exist`,JSON.stringify(errordata))
|
|
651
659
|
|
|
652
660
|
}
|
|
653
661
|
}
|
|
@@ -655,7 +663,6 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
655
663
|
}
|
|
656
664
|
|
|
657
665
|
}
|
|
658
|
-
console.log("666")
|
|
659
666
|
}
|
|
660
667
|
|
|
661
668
|
|
|
@@ -8,6 +8,14 @@ export type ForeignKey = {
|
|
|
8
8
|
_id: string
|
|
9
9
|
label: string
|
|
10
10
|
}
|
|
11
|
+
export type ModifiedCollection = {
|
|
12
|
+
[key:string]:string[]
|
|
13
|
+
}
|
|
14
|
+
export type ModifiedRecords = {
|
|
15
|
+
createds: ModifiedCollection
|
|
16
|
+
updateds: ModifiedCollection
|
|
17
|
+
deleteds: ModifiedCollection
|
|
18
|
+
}
|
|
11
19
|
export type DocNumberFormatResult = {
|
|
12
20
|
formatId: string
|
|
13
21
|
formatName: string
|
|
@@ -67,6 +67,31 @@ export class ProfileController {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
@Get('/tenants')
|
|
71
|
+
@Roles(Role.Everyone, Role.User)
|
|
72
|
+
@ApiOperation({
|
|
73
|
+
operationId: 'getAllTenants',
|
|
74
|
+
description: 'Get all tenants',
|
|
75
|
+
})
|
|
76
|
+
@ApiResponse({
|
|
77
|
+
status: 200,
|
|
78
|
+
type: () => [MyProfileApiSchema],
|
|
79
|
+
description: 'Success',
|
|
80
|
+
})
|
|
81
|
+
@ApiResponse({ status: 401, type: Object, description: 'Undefine profile' })
|
|
82
|
+
async getAllTenants(@AppUser() appuser: UserContext) {
|
|
83
|
+
this.logger.debug(
|
|
84
|
+
`access getAllTenants API by ${appuser.getUid()},(${appuser.getId()})`,
|
|
85
|
+
);
|
|
86
|
+
const result = await this.profileservice.getAllTenants(appuser);
|
|
87
|
+
this.logger.debug('getProfile result is:');
|
|
88
|
+
this.logger.debug(result);
|
|
89
|
+
if (result) {
|
|
90
|
+
return result;
|
|
91
|
+
} else {
|
|
92
|
+
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
70
95
|
|
|
71
96
|
@Post('/tenant')
|
|
72
97
|
@Roles(Role.Everyone)
|
|
@@ -106,10 +131,8 @@ export class ProfileController {
|
|
|
106
131
|
decision,
|
|
107
132
|
);
|
|
108
133
|
if (result) {
|
|
109
|
-
console.log('result', result);
|
|
110
134
|
return result;
|
|
111
135
|
} else {
|
|
112
|
-
console.log('throw error');
|
|
113
136
|
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
|
|
114
137
|
}
|
|
115
138
|
}
|
|
@@ -67,8 +67,6 @@ export class ProfileService {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
async createUserProfile(appuser: UserContext) {
|
|
70
|
-
|
|
71
|
-
|
|
72
70
|
const data: User = {
|
|
73
71
|
uid: appuser.getUid(),
|
|
74
72
|
fullname: appuser.getFullname(),
|
|
@@ -76,7 +74,11 @@ export class ProfileService {
|
|
|
76
74
|
active: true,
|
|
77
75
|
doctype: 'user',
|
|
78
76
|
} as User;
|
|
79
|
-
|
|
77
|
+
if (appuser.getTenantId() == 0) {
|
|
78
|
+
data.tenantId = 0;
|
|
79
|
+
data.orgId = 0;
|
|
80
|
+
data.branchId = 0;
|
|
81
|
+
}
|
|
80
82
|
const createresult = await this.usersvc.create(appuser, data);
|
|
81
83
|
const userinfo = await appuser.getUserInfo();
|
|
82
84
|
userinfo._id = createresult._id;
|
|
@@ -85,7 +87,7 @@ export class ProfileService {
|
|
|
85
87
|
|
|
86
88
|
async createTenant(appuser: UserContext, tenantName: string) {
|
|
87
89
|
// try{
|
|
88
|
-
appuser.getDBSession().startTransaction()
|
|
90
|
+
appuser.getDBSession().startTransaction();
|
|
89
91
|
const tenantdata: Tenant = {
|
|
90
92
|
tenantId: 1,
|
|
91
93
|
tenantName: tenantName,
|
|
@@ -112,7 +114,7 @@ export class ProfileService {
|
|
|
112
114
|
orgCode: 'HQ',
|
|
113
115
|
orgId: 1,
|
|
114
116
|
};
|
|
115
|
-
|
|
117
|
+
|
|
116
118
|
this.logger.log(orgdata, 'createOrg data');
|
|
117
119
|
const orgResult = await this.orgsvc.create(appuser, orgdata);
|
|
118
120
|
if (!orgResult) {
|
|
@@ -131,7 +133,7 @@ export class ProfileService {
|
|
|
131
133
|
organization: { _id: orgRecordId, label: tenantName },
|
|
132
134
|
};
|
|
133
135
|
this.logger.log(branchdata, 'createbranch data');
|
|
134
|
-
|
|
136
|
+
|
|
135
137
|
const branchResult = await this.branchsvc.create(appuser, branchdata);
|
|
136
138
|
if (!branchResult) {
|
|
137
139
|
throw new BadRequestException('Create Branch failed');
|
|
@@ -163,6 +165,7 @@ export class ProfileService {
|
|
|
163
165
|
orgId: orgResult.orgId,
|
|
164
166
|
branchId: branchResult.branchId,
|
|
165
167
|
uid: appuser.getUid(),
|
|
168
|
+
userId: userRecordId,
|
|
166
169
|
group: 'admin',
|
|
167
170
|
};
|
|
168
171
|
this.logger.log(permdata, 'create Permission data');
|
|
@@ -173,6 +176,16 @@ export class ProfileService {
|
|
|
173
176
|
|
|
174
177
|
this.logger.log(permResult, 'create Permission result');
|
|
175
178
|
|
|
179
|
+
|
|
180
|
+
//tenant owner shall map to userId for that tenant
|
|
181
|
+
|
|
182
|
+
const tenantUpdateData = await this.tenantsvc.findById(appuser,tenantResult._id)
|
|
183
|
+
this.logger.log(tenantUpdateData, `update tenant owner(${tenantResult._id})`);
|
|
184
|
+
tenantUpdateData.owner._id = userRecordId
|
|
185
|
+
const updateTenantOwnerResult = await this.tenantsvc.findIdThenUpdate(appuser,tenantResult._id,tenantUpdateData)
|
|
186
|
+
if (!updateTenantOwnerResult) {
|
|
187
|
+
throw new BadRequestException('Update tenant owner failed');
|
|
188
|
+
}
|
|
176
189
|
const xorg: string = Base64URL.encodeText(
|
|
177
190
|
`${tenantResult.tenantId}-${orgResult.orgId}-${branchResult.branchId}`,
|
|
178
191
|
);
|
|
@@ -198,4 +211,8 @@ export class ProfileService {
|
|
|
198
211
|
async decideInvitation(appuser: UserContext, id: string, decision: string) {
|
|
199
212
|
return await appuser.decideInvitation(id, decision);
|
|
200
213
|
}
|
|
214
|
+
|
|
215
|
+
async getAllTenants(appuser: UserContext) {
|
|
216
|
+
return await appuser.getAllTenants();
|
|
217
|
+
}
|
|
201
218
|
}
|
|
@@ -9,19 +9,19 @@ import { Model } from 'mongoose';
|
|
|
9
9
|
import { Injectable, InternalServerErrorException } from '@nestjs/common';
|
|
10
10
|
import { BranchProcessor } from '../generate/processors/branch.processor';
|
|
11
11
|
import { Branch } from '../generate/types/branch.type';
|
|
12
|
-
import {alldocuments} from '../generate/commons/dicts/documents'
|
|
12
|
+
import { alldocuments } from '../generate/commons/dicts/documents';
|
|
13
13
|
export { Branch } from '../generate/types/branch.type';
|
|
14
14
|
import { AutoincreamentService } from './autoinc.service';
|
|
15
15
|
import { UserContext } from '../generate/commons/user.context';
|
|
16
|
-
import { Docnoformat,DocnoformatService } from './docno.service';
|
|
16
|
+
import { Docnoformat, DocnoformatService } from './docno.service';
|
|
17
17
|
// import { Docnoformat } from '../generate/types/docno.type';
|
|
18
18
|
@Injectable()
|
|
19
19
|
export class BranchService extends BranchProcessor {
|
|
20
20
|
protected strictIsolation = false;
|
|
21
21
|
constructor(
|
|
22
22
|
@InjectModel('Branch') mydoc: Model<Branch>,
|
|
23
|
-
private increament: AutoincreamentService,
|
|
24
|
-
private docnoservice:DocnoformatService
|
|
23
|
+
private increament: AutoincreamentService,
|
|
24
|
+
private docnoservice: DocnoformatService,
|
|
25
25
|
) {
|
|
26
26
|
super(mydoc);
|
|
27
27
|
}
|
|
@@ -46,9 +46,9 @@ export class BranchService extends BranchProcessor {
|
|
|
46
46
|
);
|
|
47
47
|
data.branchId = searchresult.nextno;
|
|
48
48
|
break;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
case 'afterCreate':
|
|
50
|
+
await this.generateDefaultDocNumbers(appuser, data);
|
|
51
|
+
break;
|
|
52
52
|
// case 'beforeUpdate':
|
|
53
53
|
// break;
|
|
54
54
|
// case 'afterUpdate':
|
|
@@ -67,40 +67,41 @@ export class BranchService extends BranchProcessor {
|
|
|
67
67
|
return true;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
generateDefaultDocNumbers =async (appuser,data) => {
|
|
71
|
-
const branchName = data.branchName
|
|
72
|
-
const branchCode = data.branchCode
|
|
73
|
-
const recordId = data._id
|
|
74
|
-
const branchId= data.branchId
|
|
75
|
-
const orgId = data.orgId
|
|
76
|
-
const tenantId = data.tenantId
|
|
77
|
-
const docformats = alldocuments.filter((item)=>item.docNumber)
|
|
78
|
-
for(let i=0; i< docformats.length; i++){
|
|
79
|
-
const doc = docformats[i]
|
|
80
|
-
const pattern = `${doc.docType}-${branchCode}-[00000]
|
|
81
|
-
const formatdata:Docnoformat = {
|
|
82
|
-
_id:crypto.randomUUID(),
|
|
83
|
-
docNoFormatNo:
|
|
84
|
-
docNoFormatName:
|
|
70
|
+
generateDefaultDocNumbers = async (appuser, data) => {
|
|
71
|
+
const branchName = data.branchName;
|
|
72
|
+
const branchCode = data.branchCode;
|
|
73
|
+
const recordId = data._id;
|
|
74
|
+
const branchId = data.branchId;
|
|
75
|
+
const orgId = data.orgId;
|
|
76
|
+
const tenantId = data.tenantId;
|
|
77
|
+
const docformats = alldocuments.filter((item) => item.docNumber);
|
|
78
|
+
for (let i = 0; i < docformats.length; i++) {
|
|
79
|
+
const doc = docformats[i];
|
|
80
|
+
const pattern = `${doc.docType}-${branchCode}-[00000]`;
|
|
81
|
+
const formatdata: Docnoformat = {
|
|
82
|
+
_id: crypto.randomUUID(),
|
|
83
|
+
docNoFormatNo: doc.docType,
|
|
84
|
+
docNoFormatName: `Default ${doc.docType}`,
|
|
85
85
|
docNoType: doc.docType,
|
|
86
|
-
docNoPattern:
|
|
87
|
-
branch:{_id:recordId,branchId:branchId,label:branchName},
|
|
88
|
-
branchId:branchId,
|
|
89
|
-
orgId:orgId,
|
|
90
|
-
tenantId:tenantId,
|
|
91
|
-
nextNumber:1,
|
|
92
|
-
} as Docnoformat
|
|
93
|
-
try{
|
|
94
|
-
const result = await this.docnoservice.create(appuser,formatdata)
|
|
95
|
-
if(!result){
|
|
96
|
-
throw new InternalServerErrorException(
|
|
86
|
+
docNoPattern: pattern,
|
|
87
|
+
branch: { _id: recordId, branchId: branchId, label: branchName },
|
|
88
|
+
branchId: branchId,
|
|
89
|
+
orgId: orgId,
|
|
90
|
+
tenantId: tenantId,
|
|
91
|
+
nextNumber: 1,
|
|
92
|
+
} as Docnoformat;
|
|
93
|
+
try {
|
|
94
|
+
const result = await this.docnoservice.create(appuser, formatdata);
|
|
95
|
+
if (!result) {
|
|
96
|
+
throw new InternalServerErrorException(
|
|
97
|
+
`Generate default document number for "${branchCode}" failed. Pattern: ${pattern}`,
|
|
98
|
+
'generateDefaultDocNumbers',
|
|
99
|
+
);
|
|
97
100
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
throw new InternalServerErrorException(err)
|
|
101
|
+
} catch (err) {
|
|
102
|
+
this.logger.error(err);
|
|
103
|
+
throw new InternalServerErrorException(err);
|
|
102
104
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
106
107
|
}
|