rez_core 3.1.61 → 3.1.63
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/filter/repository/saved-filter.repository.d.ts +2 -0
- package/dist/module/filter/repository/saved-filter.repository.js +2 -1
- package/dist/module/filter/repository/saved-filter.repository.js.map +1 -1
- package/dist/module/integration/controller/integration.controller.js +1 -1
- package/dist/module/integration/controller/integration.controller.js.map +1 -1
- package/dist/module/integration/service/integration.service.js +9 -17
- package/dist/module/integration/service/integration.service.js.map +1 -1
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.d.ts +1 -1
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js +15 -8
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js.map +1 -1
- package/dist/module/integration/strategies/telephone/tubelight-voice.strategy.d.ts +7 -0
- package/dist/module/integration/strategies/telephone/tubelight-voice.strategy.js +51 -0
- package/dist/module/integration/strategies/telephone/tubelight-voice.strategy.js.map +1 -1
- package/dist/module/mapper/service/field-mapper.service.js +1 -1
- package/dist/module/mapper/service/field-mapper.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/module/filter/repository/saved-filter.repository.ts +3 -2
- package/src/module/integration/controller/integration.controller.ts +1 -1
- package/src/module/integration/service/integration.service.ts +15 -28
- package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +18 -10
- package/src/module/integration/strategies/telephone/tubelight-voice.strategy.ts +80 -0
- package/src/module/mapper/service/field-mapper.service.ts +1 -1
package/package.json
CHANGED
|
@@ -74,7 +74,7 @@ export class SavedFilterRepositoryService {
|
|
|
74
74
|
|
|
75
75
|
async getDefaultFilterByEntityType(
|
|
76
76
|
entityType: string,
|
|
77
|
-
): Promise<{ label: string; value: number } | null> {
|
|
77
|
+
): Promise<{ label: string; value: number ,code: string} | null> {
|
|
78
78
|
const filter = await this.savedFilterMasterRepo.findOne({
|
|
79
79
|
where: {
|
|
80
80
|
mapped_entity_type: entityType,
|
|
@@ -82,7 +82,7 @@ export class SavedFilterRepositoryService {
|
|
|
82
82
|
},
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
return filter ? { label: filter.name, value: filter.id } : null;
|
|
85
|
+
return filter ? { label: filter.name, value: filter.id , code: filter.code} : null;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
async getSavedFiltersByUserIdAndEntityType(
|
|
@@ -103,6 +103,7 @@ export class SavedFilterRepositoryService {
|
|
|
103
103
|
return filters.map((filter) => ({
|
|
104
104
|
label: filter.name,
|
|
105
105
|
value: filter.id,
|
|
106
|
+
code: filter.code,
|
|
106
107
|
}));
|
|
107
108
|
}
|
|
108
109
|
|
|
@@ -1279,7 +1279,7 @@ export class IntegrationService {
|
|
|
1279
1279
|
if (!commTemplate.template_id) {
|
|
1280
1280
|
let richText = commTemplate.rich_text;
|
|
1281
1281
|
|
|
1282
|
-
richText.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
1282
|
+
richText = richText.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
1283
1283
|
const value = variables[key];
|
|
1284
1284
|
return value !== undefined ? String(value) : match;
|
|
1285
1285
|
});
|
|
@@ -2370,7 +2370,7 @@ export class IntegrationService {
|
|
|
2370
2370
|
|
|
2371
2371
|
/**
|
|
2372
2372
|
* Check agent status for TELEPHONE integration
|
|
2373
|
-
*
|
|
2373
|
+
* Works with any provider that implements checkAgentStatus method
|
|
2374
2374
|
*/
|
|
2375
2375
|
async checkAgentStatus(
|
|
2376
2376
|
levelId: number,
|
|
@@ -2431,37 +2431,24 @@ export class IntegrationService {
|
|
|
2431
2431
|
);
|
|
2432
2432
|
}
|
|
2433
2433
|
|
|
2434
|
-
// Check if strategy
|
|
2435
|
-
if (
|
|
2436
|
-
const ozonetelStrategy = strategy as any;
|
|
2437
|
-
|
|
2438
|
-
// Generate token
|
|
2439
|
-
const token = await ozonetelStrategy.generateToken(mergedConfig);
|
|
2440
|
-
if (!token) {
|
|
2441
|
-
return {
|
|
2442
|
-
success: false,
|
|
2443
|
-
error: 'Failed to authenticate with telephone provider',
|
|
2444
|
-
};
|
|
2445
|
-
}
|
|
2446
|
-
|
|
2447
|
-
// Check agent status
|
|
2448
|
-
const statusResult = await ozonetelStrategy.checkAgentStatus(
|
|
2449
|
-
mergedConfig,
|
|
2450
|
-
token,
|
|
2451
|
-
);
|
|
2452
|
-
|
|
2434
|
+
// Check if strategy supports agent status check
|
|
2435
|
+
if (typeof (strategy as any).checkAgentStatus !== 'function') {
|
|
2453
2436
|
return {
|
|
2454
|
-
success:
|
|
2455
|
-
|
|
2456
|
-
state: statusResult.state,
|
|
2457
|
-
error: statusResult.error,
|
|
2437
|
+
success: false,
|
|
2438
|
+
error: `Agent status check not supported for provider: ${config.integration_provider}`,
|
|
2458
2439
|
};
|
|
2459
2440
|
}
|
|
2460
2441
|
|
|
2461
|
-
//
|
|
2442
|
+
// Check agent status
|
|
2443
|
+
const statusResult = await (strategy as any).checkAgentStatus(
|
|
2444
|
+
mergedConfig,
|
|
2445
|
+
);
|
|
2446
|
+
|
|
2462
2447
|
return {
|
|
2463
|
-
success:
|
|
2464
|
-
|
|
2448
|
+
success: true,
|
|
2449
|
+
isReady: statusResult.isReady,
|
|
2450
|
+
state: statusResult.state,
|
|
2451
|
+
error: statusResult.error,
|
|
2465
2452
|
};
|
|
2466
2453
|
} catch (error) {
|
|
2467
2454
|
this.logger.error(
|
|
@@ -50,27 +50,27 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
//
|
|
54
|
-
const
|
|
55
|
-
if (!
|
|
53
|
+
// Check agent status before making the call
|
|
54
|
+
const agentStatus = await this.checkAgentStatus(config);
|
|
55
|
+
if (!agentStatus.isReady) {
|
|
56
56
|
return {
|
|
57
57
|
success: false,
|
|
58
58
|
provider: 'ozonetel',
|
|
59
59
|
service: 'THIRD_PARTY',
|
|
60
|
-
error:
|
|
60
|
+
error: agentStatus.error ||
|
|
61
|
+
`Agent is not ready. Current state: ${agentStatus.state || 'Unknown'}. Please login to your agent dashboard.`,
|
|
61
62
|
timestamp: new Date(),
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
67
|
-
if (!
|
|
66
|
+
// Get JWT token for manual dial
|
|
67
|
+
const token = await this.generateToken(config);
|
|
68
|
+
if (!token) {
|
|
68
69
|
return {
|
|
69
70
|
success: false,
|
|
70
71
|
provider: 'ozonetel',
|
|
71
72
|
service: 'THIRD_PARTY',
|
|
72
|
-
error:
|
|
73
|
-
`Agent is not ready. Current state: ${agentStatus.state || 'Unknown'}. Please login to your agent dashboard.`,
|
|
73
|
+
error: 'Failed to generate Ozonetel authentication token',
|
|
74
74
|
timestamp: new Date(),
|
|
75
75
|
};
|
|
76
76
|
}
|
|
@@ -149,9 +149,17 @@ export class OzonetelVoiceStrategy implements IntegrationStrategy {
|
|
|
149
149
|
|
|
150
150
|
async checkAgentStatus(
|
|
151
151
|
config: OzonetelVoiceConfig,
|
|
152
|
-
token: string,
|
|
153
152
|
): Promise<{ isReady: boolean; state?: string; error?: string }> {
|
|
154
153
|
try {
|
|
154
|
+
// Generate token first
|
|
155
|
+
const token = await this.generateToken(config);
|
|
156
|
+
if (!token) {
|
|
157
|
+
return {
|
|
158
|
+
isReady: false,
|
|
159
|
+
error: 'Failed to authenticate with Ozonetel',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
155
163
|
const url = `${this.baseUrl}/ca_apis/AgentDetails`;
|
|
156
164
|
|
|
157
165
|
const response = await axios.post<AgentDetailsResponse>(
|
|
@@ -10,6 +10,7 @@ interface TubelightVoiceConfig {
|
|
|
10
10
|
userName: string;
|
|
11
11
|
password: string;
|
|
12
12
|
tenantId: string;
|
|
13
|
+
accessKey?: string; // For agent status check
|
|
13
14
|
agentLoginUrl?: string;
|
|
14
15
|
// Agent phone number from config JSON
|
|
15
16
|
agentPhoneNumber?: string;
|
|
@@ -123,7 +124,86 @@ export class TubelightVoiceStrategy implements IntegrationStrategy {
|
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
async checkAgentStatus(
|
|
128
|
+
config: TubelightVoiceConfig,
|
|
129
|
+
): Promise<{ isReady: boolean; state?: string; error?: string }> {
|
|
130
|
+
try {
|
|
131
|
+
if (!config.accessKey) {
|
|
132
|
+
return {
|
|
133
|
+
isReady: false,
|
|
134
|
+
error: 'Access key is required for agent status check',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!config.external_user_id) {
|
|
139
|
+
return {
|
|
140
|
+
isReady: false,
|
|
141
|
+
error: 'Agent email (external_user_id) is required',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const url = `https://dashboard.hellotubelight.com/tenant/v1/user/sso/agent/user/state/${config.external_user_id}`;
|
|
146
|
+
|
|
147
|
+
const response = await axios.post(
|
|
148
|
+
url,
|
|
149
|
+
{},
|
|
150
|
+
{
|
|
151
|
+
headers: {
|
|
152
|
+
'accept': '*/*',
|
|
153
|
+
'X-TENANT-ID': config.tenantId,
|
|
154
|
+
'access-key': config.accessKey,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Parse the response to determine agent status
|
|
160
|
+
const data = response.data;
|
|
161
|
+
const state = data?.state || data?.status;
|
|
162
|
+
|
|
163
|
+
// Determine if agent is ready based on the state
|
|
164
|
+
// Adjust this logic based on actual Tubelight API response format
|
|
165
|
+
const isReady = state?.toUpperCase() === 'READY' ||
|
|
166
|
+
state?.toUpperCase() === 'AVAILABLE' ||
|
|
167
|
+
state?.toUpperCase() === 'IDLE';
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
isReady,
|
|
171
|
+
state: state,
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error('Failed to check Tubelight agent status:', error);
|
|
175
|
+
return {
|
|
176
|
+
isReady: false,
|
|
177
|
+
error: axios.isAxiosError(error)
|
|
178
|
+
? error.response?.data?.message || error.message
|
|
179
|
+
: 'Unknown error checking agent status',
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
126
184
|
validateConfig(config: Partial<TubelightVoiceConfig>): boolean {
|
|
127
185
|
return !!(config && config.userName && config.password && config.tenantId);
|
|
128
186
|
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Create configuration with user agent data merged with admin credentials
|
|
190
|
+
*/
|
|
191
|
+
createUserSpecificConfig(
|
|
192
|
+
baseConfig: Pick<
|
|
193
|
+
TubelightVoiceConfig,
|
|
194
|
+
'userName' | 'password' | 'tenantId' | 'accessKey' | 'agentLoginUrl' | 'agentPhoneNumber'
|
|
195
|
+
>,
|
|
196
|
+
externalUserId?: string,
|
|
197
|
+
): TubelightVoiceConfig {
|
|
198
|
+
if (!externalUserId) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
'External user ID (agent email) is required for Tubelight voice calls',
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
...baseConfig,
|
|
206
|
+
external_user_id: externalUserId,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
129
209
|
}
|
|
@@ -39,7 +39,7 @@ export class FieldMapperService extends EntityServiceImpl {
|
|
|
39
39
|
async createFieldMappers(dtos: FieldMapperDto[], loggedInUser: UserData) {
|
|
40
40
|
let result: BaseEntity[] = [];
|
|
41
41
|
for (const dto of dtos) {
|
|
42
|
-
const fieldMapper = await
|
|
42
|
+
const fieldMapper = await this.createEntity(dto, loggedInUser);
|
|
43
43
|
result.push(fieldMapper);
|
|
44
44
|
}
|
|
45
45
|
return result;
|