tango-app-api-store-builder 1.1.13 → 1.1.15
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-store-builder",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.15",
|
|
4
4
|
"description": "storeBuilder",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"path": "^0.12.7",
|
|
34
34
|
"selenium-webdriver": "^4.31.0",
|
|
35
35
|
"sharp": "^0.34.1",
|
|
36
|
-
"tango-api-schema": "^2.5.
|
|
36
|
+
"tango-api-schema": "^2.5.49",
|
|
37
37
|
"tango-app-api-middleware": "3.1.48",
|
|
38
38
|
"url": "^0.11.4",
|
|
39
39
|
"winston": "^3.17.0",
|
|
@@ -10,6 +10,7 @@ import * as storeBuilderService from '../service/storeBuilder.service.js';
|
|
|
10
10
|
import * as planoRevisionService from '../service/planoRevision.service.js';
|
|
11
11
|
import * as storeBuilderController from './storeBuilder.controller.js';
|
|
12
12
|
import * as taskController from './task.controller.js';
|
|
13
|
+
import * as processedService from '../service/processedTaskservice.js';
|
|
13
14
|
import mongoose from 'mongoose';
|
|
14
15
|
import fetch from 'node-fetch';
|
|
15
16
|
import fs from 'fs';
|
|
@@ -1673,6 +1674,9 @@ export async function approveReplace( req, res ) {
|
|
|
1673
1674
|
skipped: [],
|
|
1674
1675
|
};
|
|
1675
1676
|
|
|
1677
|
+
// Map to track task IDs for each store
|
|
1678
|
+
const storeTaskIds = new Map();
|
|
1679
|
+
|
|
1676
1680
|
for ( const store of storesToProcess ) {
|
|
1677
1681
|
try {
|
|
1678
1682
|
const replaceResponseData = store.replaceResponseData;
|
|
@@ -1833,11 +1837,27 @@ export async function approveReplace( req, res ) {
|
|
|
1833
1837
|
body: taskPayload,
|
|
1834
1838
|
user: req.user || {},
|
|
1835
1839
|
};
|
|
1840
|
+
let taskId = null;
|
|
1836
1841
|
const mockTaskRes = {
|
|
1837
|
-
sendSuccess: () => {
|
|
1842
|
+
sendSuccess: ( data ) => {
|
|
1843
|
+
taskId = data?.taskId || null;
|
|
1844
|
+
},
|
|
1838
1845
|
sendError: () => {},
|
|
1839
1846
|
};
|
|
1840
1847
|
await taskController.createTask( mockTaskReq, mockTaskRes );
|
|
1848
|
+
|
|
1849
|
+
// Store the task ID based on the checklist name
|
|
1850
|
+
if ( taskId ) {
|
|
1851
|
+
if ( !storeTaskIds.has( store.storeName ) ) {
|
|
1852
|
+
storeTaskIds.set( store.storeName, { merchRolloutId: null, vmRolloutId: null } );
|
|
1853
|
+
}
|
|
1854
|
+
const taskIds = storeTaskIds.get( store.storeName );
|
|
1855
|
+
if ( taskPayload.checkListName === 'Merchandise Rollout' ) {
|
|
1856
|
+
taskIds.merchRolloutId = taskId;
|
|
1857
|
+
} else if ( taskPayload.checkListName === 'Visual Merch Rollout' ) {
|
|
1858
|
+
taskIds.vmRolloutId = taskId;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1841
1861
|
}
|
|
1842
1862
|
} else {
|
|
1843
1863
|
logger.info( {
|
|
@@ -1873,6 +1893,25 @@ export async function approveReplace( req, res ) {
|
|
|
1873
1893
|
}
|
|
1874
1894
|
}
|
|
1875
1895
|
|
|
1896
|
+
// Update stores in findReplaceDoc with task IDs
|
|
1897
|
+
const updatedStores = findReplaceDoc.stores.map( ( store ) => {
|
|
1898
|
+
const taskIds = storeTaskIds.get( store.storeName );
|
|
1899
|
+
if ( taskIds ) {
|
|
1900
|
+
return {
|
|
1901
|
+
...store,
|
|
1902
|
+
merchRolloutId: taskIds.merchRolloutId || store.merchRolloutId,
|
|
1903
|
+
vmRolloutId: taskIds.vmRolloutId || store.vmRolloutId,
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
return store;
|
|
1907
|
+
} );
|
|
1908
|
+
|
|
1909
|
+
// Update findReplaceAiModel with task IDs
|
|
1910
|
+
await findReplaceAiService.updateOne(
|
|
1911
|
+
{ _id: findReplaceId },
|
|
1912
|
+
{ stores: updatedStores },
|
|
1913
|
+
);
|
|
1914
|
+
|
|
1876
1915
|
const allStoresProcessed = storesToProcess.length === results.success.length + results.failed.length + results.skipped.length;
|
|
1877
1916
|
if ( allStoresProcessed ) {
|
|
1878
1917
|
await findReplaceAiService.updateOne(
|
|
@@ -1897,6 +1936,119 @@ export async function approveReplace( req, res ) {
|
|
|
1897
1936
|
}
|
|
1898
1937
|
}
|
|
1899
1938
|
|
|
1939
|
+
export async function processScheduledFindReplace( req, res ) {
|
|
1940
|
+
try {
|
|
1941
|
+
const today = dayjs();
|
|
1942
|
+
const startOfDay = today.startOf( 'day' ).toDate();
|
|
1943
|
+
const endOfDay = today.endOf( 'day' ).toDate();
|
|
1944
|
+
|
|
1945
|
+
// Find all scheduled entries for today
|
|
1946
|
+
const scheduledEntries = await findReplaceAiService.find( {
|
|
1947
|
+
schedule: true,
|
|
1948
|
+
scheduleDate: {
|
|
1949
|
+
$gte: startOfDay,
|
|
1950
|
+
$lte: endOfDay,
|
|
1951
|
+
},
|
|
1952
|
+
status: { $in: [ 'scheduled', 'yet-to-approve' ] },
|
|
1953
|
+
} );
|
|
1954
|
+
|
|
1955
|
+
if ( !scheduledEntries || scheduledEntries.length === 0 ) {
|
|
1956
|
+
return res.sendSuccess( {
|
|
1957
|
+
message: 'No scheduled entries found for today',
|
|
1958
|
+
processed: 0,
|
|
1959
|
+
results: [],
|
|
1960
|
+
} );
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
const results = {
|
|
1964
|
+
processed: [],
|
|
1965
|
+
failed: [],
|
|
1966
|
+
};
|
|
1967
|
+
|
|
1968
|
+
// Process each scheduled entry
|
|
1969
|
+
for ( const entry of scheduledEntries ) {
|
|
1970
|
+
try {
|
|
1971
|
+
const findReplaceId = entry._id.toString();
|
|
1972
|
+
const entryDoc = entry.toObject ? entry.toObject() : entry;
|
|
1973
|
+
|
|
1974
|
+
// Verify the schedule date matches today (double check)
|
|
1975
|
+
const scheduleDate = dayjs( entryDoc.scheduleDate );
|
|
1976
|
+
if ( !scheduleDate.isSame( today, 'day' ) ) {
|
|
1977
|
+
logger.warn( {
|
|
1978
|
+
functionName: 'processScheduledFindReplace',
|
|
1979
|
+
findReplaceId: findReplaceId,
|
|
1980
|
+
message: 'Schedule date does not match today, skipping',
|
|
1981
|
+
scheduleDate: scheduleDate.format( 'YYYY-MM-DD' ),
|
|
1982
|
+
today: today.format( 'YYYY-MM-DD' ),
|
|
1983
|
+
} );
|
|
1984
|
+
continue;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
// Call approveReplace internally
|
|
1988
|
+
const mockApproveReq = {
|
|
1989
|
+
body: {
|
|
1990
|
+
findReplaceId: findReplaceId,
|
|
1991
|
+
sendRollout: true,
|
|
1992
|
+
},
|
|
1993
|
+
user: req.user || {},
|
|
1994
|
+
};
|
|
1995
|
+
|
|
1996
|
+
let approveResult = null;
|
|
1997
|
+
let approveError = null;
|
|
1998
|
+
|
|
1999
|
+
const mockApproveRes = {
|
|
2000
|
+
sendSuccess: ( data ) => {
|
|
2001
|
+
approveResult = data;
|
|
2002
|
+
},
|
|
2003
|
+
sendError: ( error, statusCode ) => {
|
|
2004
|
+
approveError = { error, statusCode };
|
|
2005
|
+
},
|
|
2006
|
+
};
|
|
2007
|
+
|
|
2008
|
+
await approveReplace( mockApproveReq, mockApproveRes );
|
|
2009
|
+
|
|
2010
|
+
if ( approveError ) {
|
|
2011
|
+
results.failed.push( {
|
|
2012
|
+
findReplaceId: findReplaceId,
|
|
2013
|
+
name: entryDoc.name || 'Unknown',
|
|
2014
|
+
error: approveError.error || approveError,
|
|
2015
|
+
} );
|
|
2016
|
+
} else {
|
|
2017
|
+
results.processed.push( {
|
|
2018
|
+
findReplaceId: findReplaceId,
|
|
2019
|
+
name: entryDoc.name || 'Unknown',
|
|
2020
|
+
result: approveResult,
|
|
2021
|
+
} );
|
|
2022
|
+
}
|
|
2023
|
+
} catch ( entryError ) {
|
|
2024
|
+
logger.error( {
|
|
2025
|
+
functionName: 'processScheduledFindReplace',
|
|
2026
|
+
findReplaceId: entry._id.toString(),
|
|
2027
|
+
error: entryError,
|
|
2028
|
+
} );
|
|
2029
|
+
results.failed.push( {
|
|
2030
|
+
findReplaceId: entry._id.toString(),
|
|
2031
|
+
name: ( entry.toObject ? entry.toObject() : entry ).name || 'Unknown',
|
|
2032
|
+
error: entryError.message || 'Unknown error',
|
|
2033
|
+
} );
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
return res.sendSuccess( {
|
|
2038
|
+
message: 'Scheduled entries processed',
|
|
2039
|
+
summary: {
|
|
2040
|
+
total: scheduledEntries.length,
|
|
2041
|
+
processed: results.processed.length,
|
|
2042
|
+
failed: results.failed.length,
|
|
2043
|
+
},
|
|
2044
|
+
results: results,
|
|
2045
|
+
} );
|
|
2046
|
+
} catch ( e ) {
|
|
2047
|
+
logger.error( { functionName: 'processScheduledFindReplace', error: e } );
|
|
2048
|
+
return res.sendError( e, 500 );
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
|
|
1900
2052
|
export async function cancelFindReplace( req, res ) {
|
|
1901
2053
|
try {
|
|
1902
2054
|
const { findReplaceId } = req.body;
|
|
@@ -1996,6 +2148,168 @@ export async function cancelFindReplace( req, res ) {
|
|
|
1996
2148
|
}
|
|
1997
2149
|
}
|
|
1998
2150
|
|
|
2151
|
+
export async function revokeFindReplace( req, res ) {
|
|
2152
|
+
try {
|
|
2153
|
+
const { findReplaceId } = req.body;
|
|
2154
|
+
|
|
2155
|
+
if ( !findReplaceId || !mongoose.isValidObjectId( findReplaceId ) ) {
|
|
2156
|
+
return res.sendError( 'Valid findReplaceId is required', 400 );
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
const findReplaceData = await findReplaceAiService.findOne( { _id: findReplaceId } );
|
|
2160
|
+
if ( !findReplaceData ) {
|
|
2161
|
+
return res.sendError( 'FindReplace document not found', 404 );
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
const findReplaceDoc = findReplaceData.toObject ? findReplaceData.toObject() : findReplaceData;
|
|
2165
|
+
|
|
2166
|
+
if ( !Array.isArray( findReplaceDoc.stores ) || findReplaceDoc.stores.length === 0 ) {
|
|
2167
|
+
return res.sendError( 'No stores found in the document', 400 );
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
const results = {
|
|
2171
|
+
success: [],
|
|
2172
|
+
failed: [],
|
|
2173
|
+
};
|
|
2174
|
+
|
|
2175
|
+
// Map to track which task IDs were successfully revoked
|
|
2176
|
+
const revokedTaskIds = new Set();
|
|
2177
|
+
|
|
2178
|
+
// Process each store to revoke tasks
|
|
2179
|
+
for ( const store of findReplaceDoc.stores ) {
|
|
2180
|
+
try {
|
|
2181
|
+
const tasksToRevoke = [];
|
|
2182
|
+
|
|
2183
|
+
// Check for merchRolloutId
|
|
2184
|
+
if ( store.merchRolloutId ) {
|
|
2185
|
+
tasksToRevoke.push( {
|
|
2186
|
+
taskId: store.merchRolloutId,
|
|
2187
|
+
type: 'merchRollout',
|
|
2188
|
+
fieldName: 'merchRolloutId',
|
|
2189
|
+
} );
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
// Check for vmRolloutId
|
|
2193
|
+
if ( store.vmRolloutId ) {
|
|
2194
|
+
tasksToRevoke.push( {
|
|
2195
|
+
taskId: store.vmRolloutId,
|
|
2196
|
+
type: 'vmRollout',
|
|
2197
|
+
fieldName: 'vmRolloutId',
|
|
2198
|
+
} );
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
let revokedCount = 0;
|
|
2202
|
+
|
|
2203
|
+
// Revoke each task
|
|
2204
|
+
for ( const task of tasksToRevoke ) {
|
|
2205
|
+
try {
|
|
2206
|
+
// Get task details to retrieve floorId and planoId
|
|
2207
|
+
const taskDetails = await processedService.findOne( { _id: new mongoose.Types.ObjectId( task.taskId ) } );
|
|
2208
|
+
|
|
2209
|
+
if ( !taskDetails ) {
|
|
2210
|
+
logger.warn( {
|
|
2211
|
+
functionName: 'revokeFindReplace',
|
|
2212
|
+
storeName: store.storeName,
|
|
2213
|
+
taskId: task.taskId,
|
|
2214
|
+
message: 'Task not found, skipping revocation'
|
|
2215
|
+
} );
|
|
2216
|
+
continue;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
const taskData = taskDetails.toObject ? taskDetails.toObject() : taskDetails;
|
|
2220
|
+
const floorId = taskData.floorId ? taskData.floorId.toString() : null;
|
|
2221
|
+
const planoId = taskData.planoId ? taskData.planoId.toString() : store.planoId || null;
|
|
2222
|
+
|
|
2223
|
+
if ( !floorId || !planoId ) {
|
|
2224
|
+
logger.warn( {
|
|
2225
|
+
functionName: 'revokeFindReplace',
|
|
2226
|
+
storeName: store.storeName,
|
|
2227
|
+
taskId: task.taskId,
|
|
2228
|
+
message: 'Missing floorId or planoId, skipping revocation'
|
|
2229
|
+
} );
|
|
2230
|
+
continue;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// Call revokeTask internally
|
|
2234
|
+
const mockRevokeReq = {
|
|
2235
|
+
body: {
|
|
2236
|
+
taskId: task.taskId,
|
|
2237
|
+
floorId: floorId,
|
|
2238
|
+
planoId: planoId,
|
|
2239
|
+
type: task.type,
|
|
2240
|
+
},
|
|
2241
|
+
};
|
|
2242
|
+
const mockRevokeRes = {
|
|
2243
|
+
sendSuccess: () => {},
|
|
2244
|
+
sendError: ( error ) => {
|
|
2245
|
+
throw new Error( error );
|
|
2246
|
+
},
|
|
2247
|
+
};
|
|
2248
|
+
|
|
2249
|
+
await taskController.revokeTask( mockRevokeReq, mockRevokeRes );
|
|
2250
|
+
|
|
2251
|
+
// Mark task as successfully revoked
|
|
2252
|
+
revokedTaskIds.add( task.taskId );
|
|
2253
|
+
revokedCount++;
|
|
2254
|
+
} catch ( taskError ) {
|
|
2255
|
+
logger.error( {
|
|
2256
|
+
functionName: 'revokeFindReplace',
|
|
2257
|
+
storeName: store.storeName,
|
|
2258
|
+
taskId: task.taskId,
|
|
2259
|
+
taskError: taskError
|
|
2260
|
+
} );
|
|
2261
|
+
// Continue with other tasks even if one fails
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
if ( revokedCount > 0 ) {
|
|
2266
|
+
results.success.push( {
|
|
2267
|
+
storeName: store.storeName,
|
|
2268
|
+
revokedTasks: revokedCount,
|
|
2269
|
+
} );
|
|
2270
|
+
}
|
|
2271
|
+
} catch ( storeError ) {
|
|
2272
|
+
logger.error( { functionName: 'revokeFindReplace', storeName: store.storeName, error: storeError } );
|
|
2273
|
+
results.failed.push( {
|
|
2274
|
+
storeName: store.storeName,
|
|
2275
|
+
reason: storeError.message || 'Unknown error',
|
|
2276
|
+
} );
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
// Update stores to remove only successfully revoked task IDs
|
|
2281
|
+
const updatedStores = findReplaceDoc.stores.map( ( store ) => {
|
|
2282
|
+
const updatedStore = { ...store };
|
|
2283
|
+
if ( store.merchRolloutId && revokedTaskIds.has( store.merchRolloutId ) ) {
|
|
2284
|
+
delete updatedStore.merchRolloutId;
|
|
2285
|
+
}
|
|
2286
|
+
if ( store.vmRolloutId && revokedTaskIds.has( store.vmRolloutId ) ) {
|
|
2287
|
+
delete updatedStore.vmRolloutId;
|
|
2288
|
+
}
|
|
2289
|
+
return updatedStore;
|
|
2290
|
+
} );
|
|
2291
|
+
|
|
2292
|
+
// Update findReplaceAiModel to remove task IDs
|
|
2293
|
+
await findReplaceAiService.updateOne(
|
|
2294
|
+
{ _id: findReplaceId },
|
|
2295
|
+
{ stores: updatedStores },
|
|
2296
|
+
);
|
|
2297
|
+
|
|
2298
|
+
return res.sendSuccess( {
|
|
2299
|
+
message: 'Tasks revoked successfully',
|
|
2300
|
+
results: results,
|
|
2301
|
+
summary: {
|
|
2302
|
+
total: findReplaceDoc.stores.length,
|
|
2303
|
+
success: results.success.length,
|
|
2304
|
+
failed: results.failed.length,
|
|
2305
|
+
},
|
|
2306
|
+
} );
|
|
2307
|
+
} catch ( e ) {
|
|
2308
|
+
logger.error( { functionName: 'revokeFindReplace', error: e } );
|
|
2309
|
+
return res.sendError( e, 500 );
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
|
|
1999
2313
|
export async function deleteFindReplaceAi( req, res ) {
|
|
2000
2314
|
try {
|
|
2001
2315
|
const { id } = req.body;
|
|
@@ -8023,6 +8023,7 @@ export async function searchProduct( req, res ) {
|
|
|
8023
8023
|
return res.sendError( 'Pid is required', 400 );
|
|
8024
8024
|
}
|
|
8025
8025
|
let getProductDetails = await planoMappingService.find( { $or: [ { pid: { $regex: req.body.pid, $options: 'i' } }, { rfId: { $regex: req.body.pid, $options: 'i' } }, { barCode: { $regex: req.body.pid, $options: 'i' } } ], planoId: req.body.planoId, floorId: req.body.floorId } );
|
|
8026
|
+
console.log( getProductDetails );
|
|
8026
8027
|
if ( !getProductDetails.length ) {
|
|
8027
8028
|
return res.sendError( 'No data found', 204 );
|
|
8028
8029
|
}
|
|
@@ -8035,7 +8036,7 @@ export async function searchProduct( req, res ) {
|
|
|
8035
8036
|
...ele.toObject(),
|
|
8036
8037
|
...productDetails?.toObject(),
|
|
8037
8038
|
...fixtureDetails?.toObject(),
|
|
8038
|
-
...shelfDetails?.toObject(),
|
|
8039
|
+
...shelfDetails?.toObject(), shelfNumber: shelfDetails.shelfNumber-1,
|
|
8039
8040
|
};
|
|
8040
8041
|
} ) );
|
|
8041
8042
|
return res.sendSuccess( result );
|
|
@@ -74,7 +74,7 @@ async function createUser( data ) {
|
|
|
74
74
|
],
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
|
-
|
|
77
|
+
featureName: 'TangoEye',
|
|
78
78
|
modules: [
|
|
79
79
|
{
|
|
80
80
|
name: 'ZoneTag',
|
|
@@ -85,7 +85,7 @@ async function createUser( data ) {
|
|
|
85
85
|
],
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
|
-
|
|
88
|
+
featureName: 'TangoTrax',
|
|
89
89
|
modules: [
|
|
90
90
|
{
|
|
91
91
|
name: 'checklist',
|
|
@@ -101,6 +101,29 @@ async function createUser( data ) {
|
|
|
101
101
|
},
|
|
102
102
|
],
|
|
103
103
|
},
|
|
104
|
+
{
|
|
105
|
+
featureName: 'FootfallDirectory',
|
|
106
|
+
modules: [
|
|
107
|
+
{
|
|
108
|
+
name: 'creator',
|
|
109
|
+
isAdd: true,
|
|
110
|
+
isEdit: true,
|
|
111
|
+
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'reviewer',
|
|
115
|
+
isAdd: false,
|
|
116
|
+
isEdit: false,
|
|
117
|
+
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'approver',
|
|
121
|
+
isAdd: false,
|
|
122
|
+
isEdit: false,
|
|
123
|
+
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
104
127
|
],
|
|
105
128
|
};
|
|
106
129
|
let response = await userService.create( params );
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import { isAllowedSessionHandler } from 'tango-app-api-middleware';
|
|
2
|
+
import { isAllowedSessionHandler, isAllowedInternalAPIHandler } from 'tango-app-api-middleware';
|
|
3
3
|
import * as planoAIController from '../controllers/planoAI.controller.js';
|
|
4
4
|
|
|
5
5
|
|
|
@@ -18,5 +18,7 @@ planoAIRouter
|
|
|
18
18
|
.post( '/batchFindReplace', isAllowedSessionHandler, planoAIController.batchFindReplace )
|
|
19
19
|
.post( '/updateBatchProgress', isAllowedSessionHandler, planoAIController.updateBatchProgress )
|
|
20
20
|
.post( '/approveReplace', isAllowedSessionHandler, planoAIController.approveReplace )
|
|
21
|
+
.post( '/processScheduledFindReplace', planoAIController.processScheduledFindReplace )
|
|
21
22
|
.post( '/cancelFindReplace', isAllowedSessionHandler, planoAIController.cancelFindReplace )
|
|
23
|
+
.post( '/revokeFindReplace', isAllowedSessionHandler, planoAIController.revokeFindReplace )
|
|
22
24
|
.post( '/deleteFindReplaceAi', isAllowedSessionHandler, planoAIController.deleteFindReplaceAi );
|