rez_core 2.3.2 → 2.3.4
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/app.module.js +2 -0
- package/dist/app.module.js.map +1 -1
- package/dist/module/integration/controller/integration.controller.d.ts +8 -1
- package/dist/module/integration/controller/integration.controller.js +22 -0
- package/dist/module/integration/controller/integration.controller.js.map +1 -1
- package/dist/module/integration/dto/create-config.dto.d.ts +7 -0
- package/dist/module/integration/dto/create-config.dto.js +29 -1
- package/dist/module/integration/dto/create-config.dto.js.map +1 -1
- package/dist/module/integration/factories/sms.factory.d.ts +9 -1
- package/dist/module/integration/factories/sms.factory.js +36 -4
- package/dist/module/integration/factories/sms.factory.js.map +1 -1
- package/dist/module/integration/integration.module.js +6 -0
- package/dist/module/integration/integration.module.js.map +1 -1
- package/dist/module/integration/service/integration.service.d.ts +7 -0
- package/dist/module/integration/service/integration.service.js +51 -0
- package/dist/module/integration/service/integration.service.js.map +1 -1
- package/dist/module/integration/strategies/sms/gupshup-sms.strategy.d.ts +9 -0
- package/dist/module/integration/strategies/sms/gupshup-sms.strategy.js +104 -0
- package/dist/module/integration/strategies/sms/gupshup-sms.strategy.js.map +1 -0
- package/dist/module/integration/strategies/sms/msg91-sms.strategy.d.ts +9 -0
- package/dist/module/integration/strategies/sms/msg91-sms.strategy.js +113 -0
- package/dist/module/integration/strategies/sms/msg91-sms.strategy.js.map +1 -0
- package/dist/module/integration/strategies/sms/tubelight-sms.strategy.d.ts +9 -0
- package/dist/module/integration/strategies/sms/tubelight-sms.strategy.js +109 -0
- package/dist/module/integration/strategies/sms/tubelight-sms.strategy.js.map +1 -0
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.d.ts +7 -2
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js +52 -5
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js.map +1 -1
- package/dist/module/mapper/controller/field-mapper.controller.d.ts +6 -0
- package/dist/module/mapper/controller/field-mapper.controller.js +45 -0
- package/dist/module/mapper/controller/field-mapper.controller.js.map +1 -0
- package/dist/module/mapper/dto/field-mapper.dto.d.ts +11 -0
- package/dist/module/mapper/dto/field-mapper.dto.js +8 -0
- package/dist/module/mapper/dto/field-mapper.dto.js.map +1 -0
- package/dist/module/mapper/entity/field-lovs.entity.d.ts +7 -0
- package/dist/module/mapper/entity/field-lovs.entity.js +38 -0
- package/dist/module/mapper/entity/field-lovs.entity.js.map +1 -0
- package/dist/module/mapper/entity/field-mapper.entity.d.ts +12 -0
- package/dist/module/mapper/entity/field-mapper.entity.js +58 -0
- package/dist/module/mapper/entity/field-mapper.entity.js.map +1 -0
- package/dist/module/mapper/mapper.module.d.ts +2 -0
- package/dist/module/mapper/mapper.module.js +38 -0
- package/dist/module/mapper/mapper.module.js.map +1 -0
- package/dist/module/mapper/repository/field-lovs.repository.d.ts +8 -0
- package/dist/module/mapper/repository/field-lovs.repository.js +41 -0
- package/dist/module/mapper/repository/field-lovs.repository.js.map +1 -0
- package/dist/module/mapper/repository/field-mapper.repository.d.ts +9 -0
- package/dist/module/mapper/repository/field-mapper.repository.js +42 -0
- package/dist/module/mapper/repository/field-mapper.repository.js.map +1 -0
- package/dist/module/mapper/service/field-mapper.service.d.ts +16 -0
- package/dist/module/mapper/service/field-mapper.service.js +92 -0
- package/dist/module/mapper/service/field-mapper.service.js.map +1 -0
- package/dist/module/workflow/entity/action.entity.d.ts +2 -0
- package/dist/module/workflow/entity/action.entity.js +8 -0
- package/dist/module/workflow/entity/action.entity.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/app.module.ts +2 -0
- package/src/module/integration/controller/integration.controller.ts +24 -0
- package/src/module/integration/dto/create-config.dto.ts +22 -0
- package/src/module/integration/factories/sms.factory.ts +39 -6
- package/src/module/integration/integration.module.ts +10 -0
- package/src/module/integration/service/integration.service.ts +107 -0
- package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -0
- package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -0
- package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -0
- package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +80 -7
- package/src/module/mapper/controller/field-mapper.controller.ts +19 -0
- package/src/module/mapper/dto/field-mapper.dto.ts +14 -0
- package/src/module/mapper/entity/field-lovs.entity.ts +21 -0
- package/src/module/mapper/entity/field-mapper.entity.ts +36 -0
- package/src/module/mapper/mapper.module.ts +26 -0
- package/src/module/mapper/repository/field-lovs.repository.ts +22 -0
- package/src/module/mapper/repository/field-mapper.repository.ts +27 -0
- package/src/module/mapper/service/field-mapper.service.ts +91 -0
- package/src/module/workflow/entity/action.entity.ts +6 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
import axios, { AxiosResponse } from 'axios';
|
|
3
|
+
import {
|
|
4
|
+
IntegrationStrategy,
|
|
5
|
+
IntegrationResult,
|
|
6
|
+
} from '../integration.strategy';
|
|
7
|
+
|
|
8
|
+
interface TubelightSmsConfig {
|
|
9
|
+
userName: string;
|
|
10
|
+
password: string;
|
|
11
|
+
tenantId: string;
|
|
12
|
+
sourceNumber: string;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
senderId?: string;
|
|
15
|
+
dltTemplateId?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface TubelightSmsApiResponse {
|
|
19
|
+
status: string;
|
|
20
|
+
statusCode?: number;
|
|
21
|
+
messageId?: string;
|
|
22
|
+
data?: {
|
|
23
|
+
messageId: string;
|
|
24
|
+
status: string;
|
|
25
|
+
};
|
|
26
|
+
message?: string;
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Injectable()
|
|
31
|
+
export class TubelightSmsStrategy implements IntegrationStrategy {
|
|
32
|
+
private readonly logger = new Logger(TubelightSmsStrategy.name);
|
|
33
|
+
private readonly defaultBaseUrl = 'https://portal.tubelightcommunications.com/sms/api/v1';
|
|
34
|
+
|
|
35
|
+
async sendMessage(
|
|
36
|
+
to: string,
|
|
37
|
+
message: string,
|
|
38
|
+
config: any,
|
|
39
|
+
): Promise<IntegrationResult> {
|
|
40
|
+
try {
|
|
41
|
+
if (!this.validateConfig(config)) {
|
|
42
|
+
throw new Error('Invalid Tubelight SMS configuration');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const tubelightConfig = config as TubelightSmsConfig;
|
|
46
|
+
const baseUrl = tubelightConfig.baseUrl || this.defaultBaseUrl;
|
|
47
|
+
const url = `${baseUrl}/send`;
|
|
48
|
+
|
|
49
|
+
// Create Basic Auth token
|
|
50
|
+
const authToken = Buffer.from(
|
|
51
|
+
`${tubelightConfig.userName}:${tubelightConfig.password}`,
|
|
52
|
+
).toString('base64');
|
|
53
|
+
|
|
54
|
+
const payload = {
|
|
55
|
+
tenantId: tubelightConfig.tenantId,
|
|
56
|
+
from: tubelightConfig.senderId || tubelightConfig.sourceNumber,
|
|
57
|
+
to: this.formatPhoneNumber(to),
|
|
58
|
+
message: message,
|
|
59
|
+
dltTemplateId: tubelightConfig.dltTemplateId,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const response: AxiosResponse<TubelightSmsApiResponse> = await axios.post(
|
|
63
|
+
url,
|
|
64
|
+
payload,
|
|
65
|
+
{
|
|
66
|
+
headers: {
|
|
67
|
+
Authorization: `Basic ${authToken}`,
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
},
|
|
70
|
+
timeout: 30000,
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
response.data?.status === 'success' ||
|
|
76
|
+
response.data?.statusCode === 200 ||
|
|
77
|
+
response.data?.data?.status === 'sent'
|
|
78
|
+
) {
|
|
79
|
+
const messageId =
|
|
80
|
+
response.data?.messageId ||
|
|
81
|
+
response.data?.data?.messageId ||
|
|
82
|
+
new Date().getTime().toString();
|
|
83
|
+
|
|
84
|
+
this.logger.log(
|
|
85
|
+
`Tubelight SMS sent successfully to ${to}, messageId: ${messageId}`,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
success: true,
|
|
90
|
+
messageId: messageId,
|
|
91
|
+
provider: 'tubelight',
|
|
92
|
+
service: 'SMS',
|
|
93
|
+
timestamp: new Date(),
|
|
94
|
+
};
|
|
95
|
+
} else {
|
|
96
|
+
throw new Error(
|
|
97
|
+
response.data?.error ||
|
|
98
|
+
response.data?.message ||
|
|
99
|
+
'Failed to send SMS via Tubelight',
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
this.logger.error(
|
|
104
|
+
`Failed to send Tubelight SMS to ${to}`,
|
|
105
|
+
error.response?.data || error.message,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
provider: 'tubelight',
|
|
111
|
+
service: 'SMS',
|
|
112
|
+
error: this.extractErrorMessage(error),
|
|
113
|
+
timestamp: new Date(),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private formatPhoneNumber(phoneNumber: string): string {
|
|
119
|
+
// Remove any non-digit characters except +
|
|
120
|
+
let formatted = phoneNumber.replace(/[^\d+]/g, '');
|
|
121
|
+
|
|
122
|
+
// Ensure it has + prefix
|
|
123
|
+
if (!formatted.startsWith('+')) {
|
|
124
|
+
formatted = `+${formatted}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return formatted;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private extractErrorMessage(error: any): string {
|
|
131
|
+
if (error.response?.data?.error) {
|
|
132
|
+
return error.response.data.error;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (error.response?.data?.message) {
|
|
136
|
+
return error.response.data.message;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (error.message) {
|
|
140
|
+
return error.message;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return 'Unknown Tubelight SMS API error';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
validateConfig(config: any): boolean {
|
|
147
|
+
if (!config || typeof config !== 'object') {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Required fields
|
|
152
|
+
if (
|
|
153
|
+
!config.userName ||
|
|
154
|
+
!config.password ||
|
|
155
|
+
!config.tenantId ||
|
|
156
|
+
!config.sourceNumber
|
|
157
|
+
) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -16,6 +16,19 @@ interface OzonetelVoiceConfig {
|
|
|
16
16
|
external_user_id?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
interface AgentDetailsResponse {
|
|
20
|
+
status: string;
|
|
21
|
+
message: Array<{
|
|
22
|
+
AgentId: string;
|
|
23
|
+
AgentName: string;
|
|
24
|
+
State: string;
|
|
25
|
+
PhoneNumber: string;
|
|
26
|
+
Skill: string;
|
|
27
|
+
Mode: string;
|
|
28
|
+
Since: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
@Injectable()
|
|
20
33
|
export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
21
34
|
private readonly baseUrl = 'https://in1-ccaas-api.ozonetel.com';
|
|
@@ -49,6 +62,19 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
49
62
|
};
|
|
50
63
|
}
|
|
51
64
|
|
|
65
|
+
// Check agent status before making the call
|
|
66
|
+
const agentStatus = await this.checkAgentStatus(config, token);
|
|
67
|
+
if (!agentStatus.isReady) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
provider: 'ozonetel',
|
|
71
|
+
service: 'THIRD_PARTY',
|
|
72
|
+
error: agentStatus.error ||
|
|
73
|
+
`Agent is not ready. Current state: ${agentStatus.state || 'Unknown'}. Please login to your agent dashboard.`,
|
|
74
|
+
timestamp: new Date(),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
52
78
|
// Then make the manual dial call
|
|
53
79
|
const url = `${this.baseUrl}/ca_apis/AgentManualDial`;
|
|
54
80
|
|
|
@@ -56,7 +82,7 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
56
82
|
url,
|
|
57
83
|
{
|
|
58
84
|
userName: config.userName,
|
|
59
|
-
agentID: config.external_user_id
|
|
85
|
+
agentID: config.external_user_id,
|
|
60
86
|
campaignName: config.campaignName, // Always from config
|
|
61
87
|
customerNumber: to,
|
|
62
88
|
UCID: true,
|
|
@@ -95,7 +121,7 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
95
121
|
}
|
|
96
122
|
}
|
|
97
123
|
|
|
98
|
-
|
|
124
|
+
async generateToken(
|
|
99
125
|
config: OzonetelVoiceConfig,
|
|
100
126
|
): Promise<string | null> {
|
|
101
127
|
try {
|
|
@@ -121,6 +147,53 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
121
147
|
}
|
|
122
148
|
}
|
|
123
149
|
|
|
150
|
+
async checkAgentStatus(
|
|
151
|
+
config: OzonetelVoiceConfig,
|
|
152
|
+
token: string,
|
|
153
|
+
): Promise<{ isReady: boolean; state?: string; error?: string }> {
|
|
154
|
+
try {
|
|
155
|
+
const url = `${this.baseUrl}/ca_apis/AgentDetails`;
|
|
156
|
+
|
|
157
|
+
const response = await axios.post<AgentDetailsResponse>(
|
|
158
|
+
url,
|
|
159
|
+
{
|
|
160
|
+
userName: config.userName,
|
|
161
|
+
agentId: config.external_user_id,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
headers: {
|
|
165
|
+
apiKey: config.apiKey,
|
|
166
|
+
'Content-Type': 'application/json',
|
|
167
|
+
Authorization: `Bearer ${token}`,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (response.data?.status === 'success' && response.data?.message?.length > 0) {
|
|
173
|
+
const agentInfo = response.data.message[0];
|
|
174
|
+
const isReady = agentInfo.State?.toUpperCase() === 'READY';
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
isReady,
|
|
178
|
+
state: agentInfo.State,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
isReady: false,
|
|
184
|
+
error: 'Failed to retrieve agent details',
|
|
185
|
+
};
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error('Failed to check agent status:', error);
|
|
188
|
+
return {
|
|
189
|
+
isReady: false,
|
|
190
|
+
error: axios.isAxiosError(error)
|
|
191
|
+
? error.response?.data?.message || error.message
|
|
192
|
+
: 'Unknown error checking agent status',
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
124
197
|
validateConfig(config: Partial<OzonetelVoiceConfig>): boolean {
|
|
125
198
|
return !!(
|
|
126
199
|
config &&
|
|
@@ -133,24 +206,24 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
133
206
|
/**
|
|
134
207
|
* Create configuration with user agent data merged with admin credentials
|
|
135
208
|
* Admin credentials (apiKey, userName, campaignName) stay in base config
|
|
136
|
-
* Only agent-specific info (
|
|
209
|
+
* Only agent-specific info (external_user_id) comes from user integration
|
|
137
210
|
*/
|
|
138
211
|
createUserSpecificConfig(
|
|
139
212
|
baseConfig: Pick<
|
|
140
213
|
OzonetelVoiceConfig,
|
|
141
214
|
'apiKey' | 'userName' | 'campaignName' | 'agentLoginUrl'
|
|
142
215
|
>,
|
|
143
|
-
|
|
216
|
+
externalUserId?: string,
|
|
144
217
|
): OzonetelVoiceConfig {
|
|
145
|
-
if (!
|
|
218
|
+
if (!externalUserId) {
|
|
146
219
|
throw new Error(
|
|
147
|
-
'
|
|
220
|
+
'External user ID is required for Ozonetel voice calls',
|
|
148
221
|
);
|
|
149
222
|
}
|
|
150
223
|
|
|
151
224
|
return {
|
|
152
225
|
...baseConfig,
|
|
153
|
-
|
|
226
|
+
external_user_id: externalUserId,
|
|
154
227
|
};
|
|
155
228
|
}
|
|
156
229
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Controller, Inject, Post, Query, Req, UseGuards } from '@nestjs/common';
|
|
2
|
+
import { FieldMapperService } from '../service/field-mapper.service';
|
|
3
|
+
import { JwtAuthGuard } from '../../auth/guards/jwt.guard';
|
|
4
|
+
|
|
5
|
+
@Controller('field-mapper')
|
|
6
|
+
export class FieldMapperController {
|
|
7
|
+
constructor(@Inject('FieldMapperService') private readonly fieldMapperService: FieldMapperService) {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Post('resolve')
|
|
11
|
+
@UseGuards(JwtAuthGuard)
|
|
12
|
+
async resolve(@Req() req: any, @Query('integration_component') integration_component: string,
|
|
13
|
+
@Query('parent_type') parent_type: string,
|
|
14
|
+
@Query('parent_id') parent_id: number) {
|
|
15
|
+
const loggedInUser = req.user.userData;
|
|
16
|
+
return this.fieldMapperService.resolveData(integration_component, parent_type, parent_id, loggedInUser);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseEntity } from '../../meta/entity/base-entity.entity';
|
|
2
|
+
|
|
3
|
+
export class FieldMapperDto extends BaseEntity {
|
|
4
|
+
integration_component: string;
|
|
5
|
+
action: string;
|
|
6
|
+
source_attribute: string;
|
|
7
|
+
destination_attribute: string;
|
|
8
|
+
destination_entity_type: string;
|
|
9
|
+
mapped_entity_type: string;
|
|
10
|
+
filter_code?: string;
|
|
11
|
+
filter_json?: any;
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Column, Entity } from 'typeorm';
|
|
2
|
+
import { BaseEntity } from '../../meta/entity/base-entity.entity';
|
|
3
|
+
|
|
4
|
+
@Entity({ name: 'cr_field_lov_mapper' })
|
|
5
|
+
export class FieldLovMapper extends BaseEntity {
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this.entity_type = 'FLOV';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Column({ name: 'mapper_field_id'})
|
|
13
|
+
mapper_field_id: number; //1
|
|
14
|
+
|
|
15
|
+
@Column({ name: 'destination_attribute_value', type: 'varchar', length: 30 })
|
|
16
|
+
destination_attribute_value: string; //INDIA
|
|
17
|
+
|
|
18
|
+
@Column({ name: 'source_attribute_value', type: 'varchar', length: 30 })
|
|
19
|
+
source_attribute_value: string; //IND
|
|
20
|
+
|
|
21
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Column, Entity } from 'typeorm';
|
|
2
|
+
import { BaseEntity } from '../../meta/entity/base-entity.entity';
|
|
3
|
+
|
|
4
|
+
@Entity({ name: 'cr_field_mapper' })
|
|
5
|
+
export class FieldMapper extends BaseEntity {
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this.entity_type = 'FMAP';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Column({ name: 'integration_component', type: 'varchar', length: 30 })
|
|
13
|
+
integration_component: string;
|
|
14
|
+
|
|
15
|
+
@Column({ name: 'action', type: 'varchar', length: 30 })
|
|
16
|
+
action: string;
|
|
17
|
+
|
|
18
|
+
@Column({ name: 'source_attribute', type: 'varchar', length: 30 })
|
|
19
|
+
source_attribute: string;
|
|
20
|
+
|
|
21
|
+
@Column({ name: 'destination_attribute', type: 'varchar', length: 30 })
|
|
22
|
+
destination_attribute: string;
|
|
23
|
+
|
|
24
|
+
@Column({ name: 'destination_entity_type', type: 'varchar', length: 30 })
|
|
25
|
+
destination_entity_type: string;
|
|
26
|
+
|
|
27
|
+
@Column({ name: 'mapped_entity_type', type: 'varchar', length: 30, nullable: true })
|
|
28
|
+
mapped_entity_type: string;
|
|
29
|
+
|
|
30
|
+
@Column({ name: 'filter_code', type: 'varchar', length: 30, default: 'default' })
|
|
31
|
+
filter_code: string;
|
|
32
|
+
|
|
33
|
+
@Column({ name: 'is_lov_present', type: 'tinyint' })
|
|
34
|
+
is_lov_present: number;
|
|
35
|
+
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
3
|
+
import { FieldMapper } from './entity/field-mapper.entity';
|
|
4
|
+
import { FieldMapperService } from './service/field-mapper.service';
|
|
5
|
+
import { FieldMapperRepository } from './repository/field-mapper.repository';
|
|
6
|
+
import { FilterModule } from '../filter/filter.module';
|
|
7
|
+
import { EntityModule } from '../meta/entity.module';
|
|
8
|
+
import { FieldMapperController } from './controller/field-mapper.controller';
|
|
9
|
+
import { FieldLovMapper } from './entity/field-lovs.entity';
|
|
10
|
+
import { FieldLovsRepository } from './repository/field-lovs.repository';
|
|
11
|
+
|
|
12
|
+
@Module({
|
|
13
|
+
imports: [
|
|
14
|
+
TypeOrmModule.forFeature([FieldMapper, FieldLovMapper]),
|
|
15
|
+
FilterModule,
|
|
16
|
+
EntityModule,
|
|
17
|
+
],
|
|
18
|
+
providers: [
|
|
19
|
+
{ provide: 'FieldMapperService', useClass: FieldMapperService },
|
|
20
|
+
FieldMapperRepository,
|
|
21
|
+
FieldLovsRepository,
|
|
22
|
+
],
|
|
23
|
+
controllers: [FieldMapperController],
|
|
24
|
+
})
|
|
25
|
+
export class MapperModule {
|
|
26
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
|
+
import { FieldLovMapper } from '../entity/field-lovs.entity';
|
|
4
|
+
import { Repository } from 'typeorm';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class FieldLovsRepository {
|
|
8
|
+
constructor(@InjectRepository(FieldLovMapper) private readonly fieldLovMapperRepository: Repository<FieldLovMapper>) {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async findByMapperFieldIdAndSourceAttributeValue(mapper_field_id: number, source_attribute_value: string) {
|
|
12
|
+
return await this.fieldLovMapperRepository.findOne({
|
|
13
|
+
where: { mapper_field_id, source_attribute_value },
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async findByMapperFieldIdAndDestinationAttributeValue(mapper_field_id: number, destination_attribute_value: string) {
|
|
18
|
+
return await this.fieldLovMapperRepository.findOne({
|
|
19
|
+
where: { mapper_field_id, destination_attribute_value },
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
|
+
import { FieldMapper } from '../entity/field-mapper.entity';
|
|
4
|
+
import { Repository } from 'typeorm';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class FieldMapperRepository {
|
|
8
|
+
constructor(
|
|
9
|
+
@InjectRepository(FieldMapper)
|
|
10
|
+
private readonly fieldMapperRepository: Repository<FieldMapper>,
|
|
11
|
+
) {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async findByIntegrationComponentAndDestinationEntityType(integrationComponent: string, destinationEntityType: string) {
|
|
15
|
+
return await this.fieldMapperRepository.find({
|
|
16
|
+
where: { integration_component: integrationComponent, destination_entity_type: destinationEntityType },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async save(dto: Partial<FieldMapper>) {
|
|
21
|
+
return await this.fieldMapperRepository.save(dto);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async saveBulk(dtos: Partial<FieldMapper>[]) {
|
|
25
|
+
return await this.fieldMapperRepository.save(dtos);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
2
|
+
import { FieldMapperRepository } from '../repository/field-mapper.repository';
|
|
3
|
+
import { FieldMapperDto } from '../dto/field-mapper.dto';
|
|
4
|
+
import { EntityServiceImpl } from '../../meta/service/entity-service-impl.service';
|
|
5
|
+
import { UserData } from '../../user/entity/user.entity';
|
|
6
|
+
import { SavedFilterService } from '../../filter/service/saved-filter.service';
|
|
7
|
+
import { FieldLovsRepository } from '../repository/field-lovs.repository';
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class FieldMapperService extends EntityServiceImpl {
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly fieldMapperRepository: FieldMapperRepository,
|
|
13
|
+
@Inject('SavedFilterService') private readonly savedFilterService: SavedFilterService,
|
|
14
|
+
private readonly fieldLovsRepository: FieldLovsRepository,
|
|
15
|
+
) {
|
|
16
|
+
super();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async createEntity(dto: FieldMapperDto, loggedInUser: UserData) {
|
|
20
|
+
if (dto.filter_json) {
|
|
21
|
+
const savedFilter = await this.savedFilterService.createEntity(dto.filter_json, loggedInUser);
|
|
22
|
+
dto.filter_code = savedFilter.code;
|
|
23
|
+
}
|
|
24
|
+
return super.createEntity(dto, loggedInUser);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async updateEntity(dto: FieldMapperDto, loggedInUser: UserData) {
|
|
28
|
+
if (dto.filter_json) {
|
|
29
|
+
const savedFilter = await this.savedFilterService.createEntity(dto.filter_json, loggedInUser);
|
|
30
|
+
dto.filter_code = savedFilter.code;
|
|
31
|
+
}
|
|
32
|
+
return super.updateEntity(dto, loggedInUser);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async createFieldMappers(dtos: FieldMapperDto[]) {
|
|
36
|
+
return await this.fieldMapperRepository.saveBulk(dtos);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async resolveData(
|
|
40
|
+
integration_component: string,
|
|
41
|
+
parent_type: string,
|
|
42
|
+
parent_id: number,
|
|
43
|
+
userData: UserData,
|
|
44
|
+
) {
|
|
45
|
+
const fieldMappers =
|
|
46
|
+
await this.fieldMapperRepository.findByIntegrationComponentAndDestinationEntityType(
|
|
47
|
+
integration_component,
|
|
48
|
+
parent_type,
|
|
49
|
+
);
|
|
50
|
+
const result: Record<string, any> = {};
|
|
51
|
+
|
|
52
|
+
const inMemory: Record<string, Record<string, any>> = {};
|
|
53
|
+
|
|
54
|
+
for (const field of fieldMappers) {
|
|
55
|
+
const entityType = field.mapped_entity_type ? field.mapped_entity_type : field.destination_entity_type;
|
|
56
|
+
const filterCode = field.filter_code || 'default';
|
|
57
|
+
if (!inMemory[entityType]) {
|
|
58
|
+
inMemory[entityType] = {};
|
|
59
|
+
}
|
|
60
|
+
if (!inMemory[entityType][filterCode] && !field.mapped_entity_type) {
|
|
61
|
+
inMemory[entityType][filterCode] = await super.getResolvedEntityData(
|
|
62
|
+
entityType,
|
|
63
|
+
parent_id,
|
|
64
|
+
userData,
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
// TODO: Handle mapped_entity_type with filterCode
|
|
68
|
+
inMemory[entityType][filterCode] = {};
|
|
69
|
+
}
|
|
70
|
+
const entityData = inMemory[entityType][filterCode];
|
|
71
|
+
if (entityData) {
|
|
72
|
+
let value = entityData[field.destination_attribute];
|
|
73
|
+
if (field.is_lov_present) {
|
|
74
|
+
if (field.action === 'LOOKUP') {
|
|
75
|
+
let fieldLovMapper = await this.fieldLovsRepository.findByMapperFieldIdAndDestinationAttributeValue(field.id, value);
|
|
76
|
+
if (fieldLovMapper) {
|
|
77
|
+
value = fieldLovMapper.source_attribute_value;
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
let fieldLovMapper = await this.fieldLovsRepository.findByMapperFieldIdAndSourceAttributeValue(field.id, value);
|
|
81
|
+
if (fieldLovMapper) {
|
|
82
|
+
value = fieldLovMapper.destination_attribute_value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
result[field.source_attribute] = value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -41,4 +41,10 @@ export class ActionEntity extends BaseEntity {
|
|
|
41
41
|
|
|
42
42
|
@Column({ type: 'int', nullable: true })
|
|
43
43
|
dependent_action_id: number;
|
|
44
|
+
|
|
45
|
+
@Column({ type: 'varchar', nullable: true })
|
|
46
|
+
mode: string;
|
|
47
|
+
|
|
48
|
+
@Column({ type: 'varchar', nullable: true })
|
|
49
|
+
template: string;
|
|
44
50
|
}
|