rez_core 1.0.40 → 1.0.41
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/dist/module/master/controller/master.controller.d.ts +3 -2
- package/dist/module/master/controller/master.controller.js +0 -18
- package/dist/module/master/controller/master.controller.js.map +1 -1
- package/dist/module/master/service/master.service.d.ts +14 -6
- package/dist/module/master/service/master.service.js +100 -23
- package/dist/module/master/service/master.service.js.map +1 -1
- package/dist/module/module/controller/module-access.controller.d.ts +14 -0
- package/dist/module/module/controller/module-access.controller.js +10 -0
- package/dist/module/module/controller/module-access.controller.js.map +1 -1
- package/dist/module/module/repository/module-access.repository.d.ts +17 -1
- package/dist/module/module/repository/module-access.repository.js +47 -3
- package/dist/module/module/repository/module-access.repository.js.map +1 -1
- package/dist/module/module/service/module-access.service.d.ts +14 -0
- package/dist/module/module/service/module-access.service.js +3 -0
- package/dist/module/module/service/module-access.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/module/master/controller/master.controller.ts +1 -15
- package/src/module/master/service/master.service.ts +131 -27
- package/src/module/module/controller/module-access.controller.ts +12 -0
- package/src/module/module/repository/module-access.repository.ts +62 -4
- package/src/module/module/service/module-access.service.ts +10 -0
package/package.json
CHANGED
|
@@ -22,19 +22,5 @@ export class MasterController {
|
|
|
22
22
|
return this.masterService.processExcel(file);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
@UseInterceptors(FileInterceptor('file'))
|
|
27
|
-
async uploadMasterDataXls(@UploadedFile() file: Express.Multer.File) {
|
|
28
|
-
if (!file) {
|
|
29
|
-
throw new BadRequestException('File is required');
|
|
30
|
-
}
|
|
31
|
-
// const tempFilePath = join(__dirname, '../../uploads', `${Date.now()}_${file.originalname}`);
|
|
32
|
-
// await writeFile(tempFilePath, file.buffer);
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
await this.masterService.uploadMasterData(file.buffer);
|
|
36
|
-
} finally {
|
|
37
|
-
// FileUtil.deleteFile(tempFilePath);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
25
|
+
|
|
40
26
|
}
|
|
@@ -1,29 +1,148 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
-
import { ExcelUtil } from '../../../utils/service/excelUtil.service';
|
|
3
2
|
import { EntityManager } from 'typeorm';
|
|
3
|
+
import { ExcelUtil } from 'src/utils/service/excelUtil.service';
|
|
4
4
|
import { EntityMasterService } from '../../meta/service/entity-master.service';
|
|
5
5
|
|
|
6
|
+
interface ParentEntity {
|
|
7
|
+
id: number;
|
|
8
|
+
code: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
@Injectable()
|
|
7
12
|
export class MasterService {
|
|
8
13
|
constructor(
|
|
9
14
|
private readonly entityManager: EntityManager,
|
|
10
15
|
private readonly entityMasterService: EntityMasterService,
|
|
11
|
-
private
|
|
16
|
+
private readonly excelUtil: ExcelUtil,
|
|
12
17
|
) {}
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
private readonly metaSheets = [
|
|
20
|
+
'entity_master',
|
|
21
|
+
'attribute_master',
|
|
22
|
+
'list_master',
|
|
23
|
+
'list_master_items',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
private isMetaSheet(sheetName: string): boolean {
|
|
27
|
+
return this.metaSheets.includes(sheetName.toLowerCase());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async processExcel(file): Promise<{ message: string }> {
|
|
31
|
+
console.log('📥 Reading Excel file...');
|
|
32
|
+
const data = ExcelUtil.readExcel(file.buffer) as Record<string, Record<string, any>[]>;
|
|
33
|
+
|
|
34
|
+
for (const [sheetName, records] of Object.entries(data)) {
|
|
35
|
+
if (!records.length) continue;
|
|
36
|
+
|
|
37
|
+
const isMeta = this.isMetaSheet(sheetName);
|
|
38
|
+
console.log(`📄 Processing sheet: ${sheetName} | Meta: ${isMeta}`);
|
|
39
|
+
|
|
40
|
+
if (isMeta) {
|
|
41
|
+
await this.upsertData(sheetName, records);
|
|
42
|
+
} else {
|
|
43
|
+
await this.processEntityData(records);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { message: '✅ Data processed successfully' };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private async processEntityData(records: Record<string, any>[]): Promise<void> {
|
|
51
|
+
for (const row of records) {
|
|
52
|
+
const entityType = row['entity_type'];
|
|
53
|
+
if (!entityType) {
|
|
54
|
+
console.warn('⚠️ Skipping row without entity_type:', row);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { tableName } = await this.getEntityMeta(entityType);
|
|
59
|
+
const attrMap = await this.getAttributeMap(entityType);
|
|
60
|
+
const transformed = this.transformRow(row, attrMap);
|
|
61
|
+
|
|
62
|
+
// Resolve parent_id if parent_type and parent_id are present
|
|
63
|
+
if (row['parent_id'] && row['parent_type']) {
|
|
64
|
+
transformed['parent_id'] = await this.resolveParentId(row['parent_type'], row['parent_id']);
|
|
65
|
+
transformed['parent_type'] = row['parent_type'];
|
|
66
|
+
}
|
|
16
67
|
|
|
17
|
-
|
|
18
|
-
|
|
68
|
+
await this.insertEntityRow(tableName, transformed);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private async getEntityMeta(entityType: string): Promise<{ tableName: string; mappedEntityType: string }> {
|
|
73
|
+
const result = await this.entityManager.query(
|
|
74
|
+
`SELECT db_table_name, mapped_entity_type FROM entity_master WHERE mapped_entity_type = ? LIMIT 1`,
|
|
75
|
+
[entityType],
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (!result.length || !result[0].db_table_name) {
|
|
79
|
+
throw new Error(`❌ Entity metadata not found for entity_type: ${entityType}`);
|
|
19
80
|
}
|
|
20
81
|
|
|
21
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
tableName: result[0].db_table_name,
|
|
84
|
+
mappedEntityType: result[0].mapped_entity_type,
|
|
85
|
+
};
|
|
22
86
|
}
|
|
23
87
|
|
|
24
|
-
private async
|
|
88
|
+
private async getAttributeMap(mappedEntityType: string): Promise<Record<string, string>> {
|
|
89
|
+
const attributes = await this.entityManager.query(
|
|
90
|
+
'SELECT attribute_key FROM attribute_master WHERE mapped_entity_type = ? AND status = "ACTIVE"',
|
|
91
|
+
[mappedEntityType],
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return attributes.reduce((acc, attr) => {
|
|
95
|
+
acc[attr.attribute_key] = attr.attribute_key;
|
|
96
|
+
return acc;
|
|
97
|
+
}, {} as Record<string, string>);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private transformRow(row: Record<string, any>, attrMap: Record<string, string>): Record<string, any> {
|
|
101
|
+
const transformed: Record<string, any> = {};
|
|
102
|
+
for (const key of Object.keys(row)) {
|
|
103
|
+
if (attrMap[key]) {
|
|
104
|
+
transformed[attrMap[key]] = row[key];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return transformed;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private async resolveParentId(parentType: string, parentCode: string): Promise<number> {
|
|
111
|
+
const { tableName } = await this.getEntityMeta(parentType);
|
|
112
|
+
const parent = await this.entityManager.findOne<ParentEntity>(tableName, {
|
|
113
|
+
where: { code: parentCode },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (!parent) {
|
|
117
|
+
throw new Error(`❌ Parent with code "${parentCode}" not found in "${tableName}"`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return parent.id;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private async insertEntityRow(tableName: string, data: Record<string, any>): Promise<void> {
|
|
124
|
+
const keys = Object.keys(data);
|
|
125
|
+
if (!keys.length) {
|
|
126
|
+
console.warn('⚠️ Empty data, skipping insert');
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await this.entityManager
|
|
131
|
+
.createQueryBuilder()
|
|
132
|
+
.insert()
|
|
133
|
+
.into(tableName)
|
|
134
|
+
.values(data)
|
|
135
|
+
.orUpdate({
|
|
136
|
+
overwrite: keys,
|
|
137
|
+
conflict_target: ['code'],
|
|
138
|
+
})
|
|
139
|
+
.execute();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private async upsertData(tableName: string, records: Record<string, any>[]): Promise<void> {
|
|
25
143
|
if (!records.length) return;
|
|
26
144
|
|
|
145
|
+
const keys = Object.keys(records[0]);
|
|
27
146
|
await this.entityManager.transaction(async (manager) => {
|
|
28
147
|
for (const record of records) {
|
|
29
148
|
await manager
|
|
@@ -31,27 +150,12 @@ export class MasterService {
|
|
|
31
150
|
.insert()
|
|
32
151
|
.into(tableName)
|
|
33
152
|
.values(record)
|
|
34
|
-
.orUpdate(
|
|
153
|
+
.orUpdate({
|
|
154
|
+
overwrite: keys,
|
|
155
|
+
conflict_target: ['id'],
|
|
156
|
+
})
|
|
35
157
|
.execute();
|
|
36
158
|
}
|
|
37
159
|
});
|
|
38
160
|
}
|
|
39
|
-
|
|
40
|
-
async uploadMasterData(file) {
|
|
41
|
-
const data = ExcelUtil.readExcel(file.buffer);
|
|
42
|
-
await this.importEntityMasterData(data['cr_entity_master']);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private async importEntityMasterData(entityMasterList) {
|
|
46
|
-
for (let entityMaster of entityMasterList) {
|
|
47
|
-
let existingData = await this.entityMasterService.findByMappedEntityType(entityMaster.mapped_entity_type);
|
|
48
|
-
|
|
49
|
-
if (existingData) {
|
|
50
|
-
entityMaster.id = existingData.id;
|
|
51
|
-
await this.entityMasterService.update(existingData.id, entityMaster);
|
|
52
|
-
} else {
|
|
53
|
-
await this.entityMasterService.save(entityMaster);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
161
|
}
|
|
@@ -34,4 +34,16 @@ export class ModuleAccessController {
|
|
|
34
34
|
async updateModuleAccess(@Body() moduleAccessData: any[]) {
|
|
35
35
|
return this.moduleAccessService.updateModuleAccess(moduleAccessData);
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
@Post('create-role')
|
|
39
|
+
async createRole(@Body() body: {
|
|
40
|
+
name: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
status?: 'ACTIVE' | 'INACTIVE';
|
|
43
|
+
copyFromRoleId?: number;
|
|
44
|
+
}) {
|
|
45
|
+
return this.moduleAccessService.createRole(body);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
37
49
|
}
|
|
@@ -5,6 +5,7 @@ import { Role } from 'src/module/user/entity/role.entity';
|
|
|
5
5
|
import { ModuleAccess } from '../entity/module-access.entity';
|
|
6
6
|
import { ModuleAction } from '../entity/module-action.entity';
|
|
7
7
|
import { ModuleData } from '../entity/module.entity';
|
|
8
|
+
import { ClockIDGenService } from 'src/utils/service/clockIDGenUtil.service';
|
|
8
9
|
|
|
9
10
|
@Injectable()
|
|
10
11
|
export class ModuleAccessRepository {
|
|
@@ -17,6 +18,8 @@ export class ModuleAccessRepository {
|
|
|
17
18
|
private readonly moduleAccessRepo: Repository<ModuleAccess>,
|
|
18
19
|
@InjectRepository(ModuleAction)
|
|
19
20
|
private readonly moduleActionRepo: Repository<ModuleAction>,
|
|
21
|
+
private readonly clockIDGenService: ClockIDGenService,
|
|
22
|
+
|
|
20
23
|
) {}
|
|
21
24
|
|
|
22
25
|
async getRoles() {
|
|
@@ -91,10 +94,10 @@ export class ModuleAccessRepository {
|
|
|
91
94
|
// Function to recursively build module hierarchy
|
|
92
95
|
const buildHierarchy = (parentWbs: string) => {
|
|
93
96
|
return modules
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
.filter(mod => {
|
|
98
|
+
return mod.wbs_code.startsWith(parentWbs + '.') &&
|
|
99
|
+
mod.wbs_code.split('.').length === parentWbs.split('.').length + 1;
|
|
100
|
+
})
|
|
98
101
|
.map((mod) => ({
|
|
99
102
|
name: mod.name,
|
|
100
103
|
code: mod.module_code,
|
|
@@ -150,4 +153,59 @@ export class ModuleAccessRepository {
|
|
|
150
153
|
return false;
|
|
151
154
|
}
|
|
152
155
|
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
async createRole(body: {
|
|
159
|
+
name: string;
|
|
160
|
+
description?: string;
|
|
161
|
+
status?: 'ACTIVE' | 'INACTIVE';
|
|
162
|
+
copyFromRoleId?: number;
|
|
163
|
+
}) {
|
|
164
|
+
const { name, description, status, copyFromRoleId } = body;
|
|
165
|
+
|
|
166
|
+
const code = this.clockIDGenService.idGenerator('ROL');; // Replace with your custom clock ID generator
|
|
167
|
+
|
|
168
|
+
const newRole = this.roleRepo.create({
|
|
169
|
+
name,
|
|
170
|
+
code,
|
|
171
|
+
description,
|
|
172
|
+
status: status || 'ACTIVE',
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const savedRole = await this.roleRepo.save(newRole);
|
|
176
|
+
|
|
177
|
+
if (copyFromRoleId) {
|
|
178
|
+
const sourceRole = await this.roleRepo.findOne({ where: { id: copyFromRoleId } });
|
|
179
|
+
|
|
180
|
+
if (!sourceRole) {
|
|
181
|
+
throw new Error('Source role not found');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const sourcePermissions = await this.moduleAccessRepo.find({
|
|
185
|
+
where: { role_code: sourceRole.code },
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const clonedPermissions = sourcePermissions.map((perm) =>
|
|
189
|
+
this.moduleAccessRepo.create({
|
|
190
|
+
role_code: code,
|
|
191
|
+
module_code: perm.module_code,
|
|
192
|
+
action_type: perm.action_type,
|
|
193
|
+
access_flag: perm.access_flag,
|
|
194
|
+
app_code: perm.app_code,
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
await this.moduleAccessRepo.save(clonedPermissions);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
success: true,
|
|
203
|
+
msg: 'Role created successfully',
|
|
204
|
+
role: {
|
|
205
|
+
id: savedRole.id,
|
|
206
|
+
name: savedRole.name,
|
|
207
|
+
code: savedRole.code,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
153
211
|
}
|
|
@@ -39,4 +39,14 @@ export class ModuleAccessService {
|
|
|
39
39
|
return { success: false, msg: 'Failed to update module access' };
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
async createRole(body: {
|
|
44
|
+
name: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
status?: 'ACTIVE' | 'INACTIVE';
|
|
47
|
+
copyFromRoleId?: number;
|
|
48
|
+
}) {
|
|
49
|
+
return this.moduleAccessRepository.createRole(body);
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
}
|