tango-app-api-store-builder 1.0.0-beta-108 → 1.0.0-beta-109

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,50 +1,49 @@
1
1
  {
2
- "name": "tango-app-api-store-builder",
3
- "version": "1.0.0-beta-108",
4
- "description": "storeBuilder",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "nodemon --exec \"eslint --fix . && node index.js\""
9
- },
10
- "engines": {
11
- "node": ">=18.10.0"
12
- },
13
- "author": "praveenraj",
14
- "license": "ISC",
15
- "dependencies": {
16
- "aws-sdk": "^2.1692.0",
17
- "chromedriver": "^135.0.1",
18
- "cors": "^2.8.5",
19
- "dayjs": "^1.11.13",
20
- "dotenv": "^16.4.7",
21
- "exceljs": "^4.4.0",
22
- "express": "^4.21.2",
23
- "express-fileupload": "^1.5.1",
24
- "fetch-cookie": "^3.1.0",
25
- "handlebars": "^4.7.8",
26
- "joi": "^17.13.3",
27
- "jszip": "^3.10.1",
28
- "mongodb": "^6.12.0",
29
- "node-fetch": "^2.7.0",
30
- "nodemon": "^3.1.9",
31
- "os": "^0.1.2",
32
- "path": "^0.12.7",
33
- "selenium-webdriver": "^4.31.0",
34
- "sharp": "^0.34.1",
35
- "tango-api-schema": "^2.2.149",
36
- "tango-app-api-middleware": "^3.1.48",
37
- "url": "^0.11.4",
38
- "winston": "^3.17.0",
39
- "winston-daily-rotate-file": "^5.0.0",
40
- "xlsx": "^0.18.5"
41
- },
42
- "devDependencies": {
43
- "eslint": "^8.57.1",
44
- "eslint-config-google": "^0.14.0",
45
- "eslint-config-semistandard": "^17.0.0",
46
- "eslint-config-standard": "^17.1.0",
47
- "eslint-plugin-import": "^2.31.0",
48
- "eslint-plugin-promise": "^6.6.0"
49
- }
2
+ "name": "tango-app-api-store-builder",
3
+ "version": "1.0.0-beta-109",
4
+ "description": "storeBuilder",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "nodemon --exec \"eslint --fix . && node index.js\""
9
+ },
10
+ "engines": {
11
+ "node": ">=18.10.0"
12
+ },
13
+ "author": "praveenraj",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "aws-sdk": "^2.1692.0",
17
+ "chromedriver": "^135.0.1",
18
+ "cors": "^2.8.5",
19
+ "dayjs": "^1.11.13",
20
+ "dotenv": "^16.4.7",
21
+ "exceljs": "^4.4.0",
22
+ "express": "^4.21.2",
23
+ "express-fileupload": "^1.5.1",
24
+ "fetch-cookie": "^3.1.0",
25
+ "handlebars": "^4.7.8",
26
+ "joi": "^17.13.3",
27
+ "jszip": "^3.10.1",
28
+ "node-fetch": "^2.7.0",
29
+ "nodemon": "^3.1.9",
30
+ "os": "^0.1.2",
31
+ "path": "^0.12.7",
32
+ "selenium-webdriver": "^4.31.0",
33
+ "sharp": "^0.34.1",
34
+ "tango-api-schema": "^3.0.2",
35
+ "tango-app-api-middleware": "^3.1.82",
36
+ "url": "^0.11.4",
37
+ "winston": "^3.17.0",
38
+ "winston-daily-rotate-file": "^5.0.0",
39
+ "xlsx": "^0.18.5"
40
+ },
41
+ "devDependencies": {
42
+ "eslint": "^8.57.1",
43
+ "eslint-config-google": "^0.14.0",
44
+ "eslint-config-semistandard": "^17.0.0",
45
+ "eslint-config-standard": "^17.1.0",
46
+ "eslint-plugin-import": "^2.31.0",
47
+ "eslint-plugin-promise": "^6.6.0"
48
+ }
50
49
  }
@@ -6,6 +6,7 @@ import * as planoService from '../service/planogram.service.js';
6
6
  import * as storeService from '../service/store.service.js';
7
7
  import * as processedTaskService from '../service/processedTaskservice.js';
8
8
  import * as fixtureShelfService from '../service/fixtureShelf.service.js';
9
+ import * as vmService from '../service/planoVm.service.js';
9
10
  import { createTask } from './task.controller.js';
10
11
  import mongoose from 'mongoose';
11
12
  import dayjs from 'dayjs';
@@ -191,6 +192,14 @@ export async function getTemplateDetails( req, res ) {
191
192
  },
192
193
  },
193
194
  ];
195
+ templateDetails = templateDetails.toObject();
196
+ templateDetails.vmConfig = await Promise.all( templateDetails.vmConfig.map( async ( vm ) => {
197
+ let vmDetails = await vmService.findOne( { _id: vm.vmId } );
198
+ if ( vmDetails ) {
199
+ vm = { ...vm, ...vmDetails.toObject() };
200
+ return vm;
201
+ }
202
+ } ) );
194
203
  let mappedStoreList = await storeFixtureService.aggregate( query );
195
204
  let storeList = mappedStoreList?.[0]?.store || [];
196
205
  let storeDetails = await storeService.find( { clientId: templateDetails.clientId, storeName: { $in: storeList } }, { storeName: 1, storeId: 1, spocDetails: 1 } );
@@ -202,7 +211,7 @@ export async function getTemplateDetails( req, res ) {
202
211
  templateDetails.status = planoDetails.includes( 'completed' ) ? 'active' : 'inactive';
203
212
  }
204
213
  let data = {
205
- ...templateDetails.toObject(),
214
+ ...templateDetails,
206
215
  store: storeDetails.map( ( ele ) => {
207
216
  return { storeName: ele.storeName, storeId: ele.storeId, userEmail: ele?.spocDetails?.[0]?.email };
208
217
  } ),
@@ -226,10 +235,13 @@ export async function getTemplateList( req, res ) {
226
235
  { fixtureName: { $regex: req.body.searchValue, $options: 'i' } } :
227
236
  {} ),
228
237
  ...( req.body?.filter?.brand?.length ?
229
- { productBrandName: { $in: req.body.filter.brand } } :
238
+ { $or: [
239
+ { 'productBrandName': { $in: req.body.filter.brand } },
240
+ { 'shelfConfig.productBrandName': { $in: req.body.filter.brand } },
241
+ ] } :
230
242
  {} ),
231
243
  ...( req.body?.filter?.category?.length ?
232
- { productCategory: { $in: req.body.filter.category } } :
244
+ { fixtureCategory: { $in: req.body.filter.category } } :
233
245
  {} ),
234
246
  ...( req.body?.filter?.subCategory?.length ?
235
247
  { productSubCategory: { $in: req.body.subCategory.category } } :
@@ -1,9 +1,8 @@
1
- import * as floorService from '../service/storeBuilder.service.js';
2
- import { logger } from 'tango-app-api-middleware';
1
+ // import * as storeBuilderService from '../service/storeBuilder.service.js';
3
2
  // import * as storeService from '../service/store.service.js';
4
3
  // import * as planoService from '../service/planogram.service.js';
5
- import * as storeFixtureService from '../service/storeFixture.service.js';
6
- import * as fixtureShelfService from '../service/fixtureShelf.service.js';
4
+ // import * as storeFixtureService from '../service/storeFixture.service.js';
5
+ // import * as fixtureShelfService from '../service/fixtureShelf.service.js';
7
6
  // import * as planoProductService from '../service/planoProduct.service.js';
8
7
  // import * as planoVmService from '../service/planoVm.service.js';
9
8
  // import * as planoMappingService from '../service/planoMapping.service.js';
@@ -13,6 +12,7 @@ import * as planoproductCategoryService from '../service/planoproductCategory.se
13
12
  import * as fixtureConfigService from '../service/fixtureConfig.service.js';
14
13
  import * as fixtureLibraryService from '../service/planoLibrary.service.js';
15
14
  import * as planoTaskService from '../service/planoTask.service.js';
15
+ import { logger } from 'tango-app-api-middleware';
16
16
  import mongoose from 'mongoose';
17
17
  export async function getplanoFeedback( req, res ) {
18
18
  try {
@@ -137,95 +137,7 @@ export async function getStoreFixturesfeedback( req, res ) {
137
137
  }
138
138
  export async function updateStorePlano( req, res ) {
139
139
  try {
140
- const { floorId, data } = req.body;
141
-
142
- const floorData = await floorService.findOne( { _id: new mongoose.Types.ObjectId( floorId ) } );
143
-
144
- const additionalMeta = {
145
- clientId: '11',
146
- storeId: floorData.toObject().storeId,
147
- storeName: floorData.toObject().storeName,
148
- planoId: floorData.toObject().planoId,
149
- floorId: floorData.toObject()._id,
150
- };
151
-
152
- const layoutPolygon = JSON.parse( JSON.stringify( data.layoutPolygon ) );
153
-
154
- layoutPolygon.forEach( ( element ) => {
155
- delete element.fixtures;
156
- } );
157
-
158
- await floorService.updateOne( { _id: new mongoose.Types.ObjectId( floorId ) },
159
- { layoutPolygon: layoutPolygon } );
160
-
161
- const currentWallFixtures = data.layoutPolygon.flatMap( ( element ) =>
162
- ( element.fixtures || [] ).map( ( fixture ) => fixture ),
163
- );
164
-
165
- const currentFloorFixtures = ( data.centerFixture || [] );
166
-
167
- const currentFixtures = [ ...currentWallFixtures, ...currentFloorFixtures ];
168
-
169
- const existingFixtures = await storeFixtureService.find( { floorId: new mongoose.Types.ObjectId( floorId ) } );
170
-
171
- const currentIds = new Set( currentFixtures.map( ( f ) => f._id ) );
172
- const removedFixtures = existingFixtures.filter(
173
- ( f ) => f._id && !currentIds.has( f._id.toString() ),
174
- );
175
-
176
- if ( removedFixtures.length ) {
177
- const fixtureIds = removedFixtures.map( ( fixture ) => fixture.toObject()._id );
178
- await storeFixtureService.deleteMany( { _id: { $in: fixtureIds } } );
179
- await fixtureShelfService.deleteMany( { fixtureId: { $in: fixtureIds } } );
180
- }
181
-
182
-
183
- const newWallFixtures = currentWallFixtures.filter( ( fixture ) => fixture?._id?.startsWith( 'new' ) );
184
-
185
- const newFloorFixtures = currentFloorFixtures.filter( ( fixture ) => fixture?._id?.startsWith( 'new' ) );
186
-
187
- const newFixtures = [ ...newWallFixtures, ...newFloorFixtures ];
188
-
189
- if ( newFixtures.length ) {
190
- newFixtures.forEach( async ( fixture ) => {
191
- delete fixture._id;
192
- const fixturePayload = {
193
- ...additionalMeta,
194
- ...fixture,
195
- };
196
- const createdFixture = await storeFixtureService.create( fixturePayload );
197
- fixture.shelfConfig.forEach( async ( shelf ) => {
198
- delete shelf._id;
199
- const shelfPayload = {
200
- ...additionalMeta,
201
- ...shelf,
202
- fixtureId: createdFixture.toObject()._id,
203
-
204
- };
205
- await fixtureShelfService.create( shelfPayload );
206
- } );
207
- } );
208
- }
209
-
210
- currentFixtures.forEach( async ( fixture ) => {
211
- if ( mongoose.Types.ObjectId.isValid( fixture._id ) ) {
212
- const updatedFixture = await storeFixtureService.upsertOne( { _id: new mongoose.Types.ObjectId( fixture._id ) }, fixture );
213
-
214
- await fixtureShelfService.deleteMany( { fixtureId: new mongoose.Types.ObjectId( fixture._id ) } );
215
-
216
- fixture.shelfConfig.forEach( async ( shelf ) => {
217
- delete shelf._id;
218
- const shelfPayload = {
219
- ...additionalMeta,
220
- ...shelf,
221
- fixtureId: updatedFixture.toObject()._id,
222
- };
223
- await fixtureShelfService.create( shelfPayload );
224
- } );
225
- }
226
- } );
227
-
228
- res.sendSuccess( 'Updated Successfully' );
140
+ console.log( 'reached' );
229
141
  } catch ( e ) {
230
142
  logger.error( { functionName: 'updateStorePlano', error: e } );
231
143
  return res.sendError( e, 500 );
@@ -272,10 +184,10 @@ export async function updateFixtureStatus( req, res ) {
272
184
  console.log( req.body );
273
185
 
274
186
  let comments={
275
- userId: req.user?._id,
276
- userName: req.user?.userName,
277
- role: req.user?.role,
278
- responsetype: req.user?.type,
187
+ userId: req.user._id,
188
+ userName: req.user.userName,
189
+ role: req.user.role,
190
+ responsetype: req.user.type,
279
191
  comment: req.body.comments,
280
192
  };
281
193
  console.log( comments );
@@ -9,6 +9,7 @@ import * as storeFixtureService from '../service/storeFixture.service.js';
9
9
  import * as planoService from '../service/planogram.service.js';
10
10
  import ExcelJS from 'exceljs';
11
11
  import mongoose from 'mongoose';
12
+ import dayjs from 'dayjs';
12
13
  const ObjectId = mongoose.Types.ObjectId;
13
14
  import path from 'path';
14
15
 
@@ -610,7 +611,7 @@ export async function getFixLibWidth( req, res ) {
610
611
  return res.sendError( 'No data content', 204 );
611
612
  }
612
613
 
613
- getLibDetails = getLibDetails.map( ( item ) => item.fixtureWidth.value +' '+item.fixtureWidth.unit );
614
+ getLibDetails = [ ...new Set( getLibDetails.map( ( item ) => item.fixtureWidth.value ) ) ];
614
615
  return res.sendSuccess( getLibDetails );
615
616
  } catch ( e ) {
616
617
  logger.error( { functionName: 'getFixLibWidth', error: e } );
@@ -725,8 +726,79 @@ export async function deletevmTypeImage( req, res ) {
725
726
 
726
727
  export async function getBrandList( req, res ) {
727
728
  try {
728
- let getBrandDetails = await planoProductService.find( { clientId: req.query.clientId }, { createdAt: 0, updatedAt: 0 } );
729
- return res.sendSuccess( getBrandDetails );
729
+ let getBrandDetails = await planoProductService.find( { clientId: req.body.clientId }, { createdAt: 0, updatedAt: 0 } );
730
+
731
+ getBrandDetails = await Promise.all( getBrandDetails.map( async ( ele ) => {
732
+ ele = { ...ele.toObject(), isUsed: false };
733
+ let mappedDetails = await vmService.findOne( { vmBrand: ele.brandName } );
734
+ if ( mappedDetails ) {
735
+ ele.isUsed = true;
736
+ }
737
+ return ele;
738
+ } ) );
739
+ if ( !req?.body?.export ) {
740
+ return res.sendSuccess( getBrandDetails );
741
+ } else {
742
+ const workbook = new ExcelJS.Workbook();
743
+ const sheet = workbook.addWorksheet( 'Brand Details' );
744
+
745
+ sheet.getRow( 1 ).values = [ 'Brand Name', 'Brand Category', 'Brand SubCategory' ];
746
+
747
+ let rowStart = 2;
748
+ let lockedRowNumber = [];
749
+ if ( req.body.emptyDownload ) {
750
+ getBrandDetails = [];
751
+ }
752
+ getBrandDetails.forEach( ( ele ) => {
753
+ sheet.getRow( rowStart ).values = [ ele.brandName, ele.category.toString(), ele.subCategory.toString() ];
754
+ if ( ele.isUsed ) {
755
+ lockedRowNumber.push( rowStart );
756
+ }
757
+ rowStart = rowStart + 1;
758
+ } );
759
+
760
+ let unlockCellValues = 20000;
761
+ let splitLoop = [];
762
+
763
+ for ( let i=1; i<=unlockCellValues; i+=2000 ) {
764
+ splitLoop.push( { start: i, end: i + 1999 } );
765
+ }
766
+
767
+ await Promise.all( splitLoop.map( ( item ) => {
768
+ for ( let i=item.start; i<=item.end; i++ ) {
769
+ const row = sheet.getRow( i );
770
+ if ( i > rowStart - 1 ) {
771
+ row.values = [ '', '', '', '', '', '', '', '', '', '' ];
772
+ }
773
+ if ( !lockedRowNumber.includes( i ) && i != 1 ) {
774
+ row.eachCell( ( cell ) => {
775
+ cell.protection = { locked: false };
776
+ } );
777
+ }
778
+ }
779
+ } ) );
780
+
781
+ await sheet.protect( 'password123', {
782
+ selectLockedCells: false,
783
+ selectUnlockedCells: true,
784
+ } );
785
+
786
+ sheet.columns.forEach( ( column ) => {
787
+ let maxLength = 10;
788
+ column.eachCell( { includeEmpty: true }, ( cell ) => {
789
+ const cellValue = cell.value ? cell.value.toString() : '';
790
+ if ( cellValue.length > maxLength ) {
791
+ maxLength = cellValue.length;
792
+ }
793
+ } );
794
+ column.width = maxLength + 2;
795
+ } );
796
+ const buffer = await workbook.xlsx.writeBuffer();
797
+ res.setHeader( 'Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' );
798
+ res.setHeader( 'Content-Disposition', 'attachment; filename="Brand Details.xlsx"' );
799
+
800
+ return res.send( buffer );
801
+ }
730
802
  } catch ( e ) {
731
803
  logger.error( { functionName: 'getBrandList', error: e } );
732
804
  return res.sendError( e, 500 );
@@ -736,12 +808,20 @@ export async function getBrandList( req, res ) {
736
808
  export async function addUpdateBrandList( req, res ) {
737
809
  try {
738
810
  let inputData = req.body;
739
- let checkBrandExists = await planoProductService.findOne( { brandName: inputData.brandName.trim(), ...( inputData?.brandId ) ? { _id: { $ne: req.params._id } } : {} } );
740
- if ( checkBrandExists ) {
741
- return res.sendError( 'Brand Name already Exists', 400 );
742
- }
743
- inputData.brandName = inputData.brandName.trim();
744
- await planoProductService.updateOne( { clientId: inputData.clientId, ...( inputData?.brandId ) ? { _id: { $ne: req.params._id } } : { brandName: inputData.brandName } }, inputData );
811
+ inputData.brandUsedList = inputData.brandUsedList.map( ( ele ) => new ObjectId( ele ) );
812
+ let brandData = [];
813
+ inputData.brandData.forEach( ( ele ) => {
814
+ if ( !ele?.isUsed ) {
815
+ brandData.push( {
816
+ clientId: inputData.clientId,
817
+ brandName: ele.brand,
818
+ category: [ ...new Set( ele.category ) ],
819
+ subCategory: [ ...new Set( ele.subCategory ) ],
820
+ } );
821
+ }
822
+ } );
823
+ await planoProductService.deleteMany( { clientId: inputData.clientId, _id: { $nin: inputData.brandUsedList } } );
824
+ await planoProductService.insertMany( brandData );
745
825
  return res.sendSuccess( 'Brand Details updated successfully' );
746
826
  } catch ( e ) {
747
827
  logger.error( { functionName: 'addBrandList', error: e } );
@@ -758,8 +838,8 @@ export async function uploadBrandList( req, res ) {
758
838
  acc[ele.brandName] = {
759
839
  brandName: ele.brandName,
760
840
  clientId: inputData.clientId,
761
- category: ele.category,
762
- subCategory: ele.subCategory,
841
+ category: [ ...new Set( ele.category ) ],
842
+ subCategory: [ ...new Set( ele.subCategory ) ],
763
843
  };
764
844
  } else {
765
845
  acc[ele.brandName].category.push( ...ele.category );
@@ -768,10 +848,11 @@ export async function uploadBrandList( req, res ) {
768
848
  return acc;
769
849
  }, {} );
770
850
 
771
-
772
- await Promise.all( Object.keys( brandData ).map( async ( ele ) => {
773
- await planoProductService.updateOne( { brandName: brandData[ele].brandName, clientId: req.body.clientId }, brandData[ele] );
774
- } ) );
851
+ await planoProductService.deleteMany( { clientId: inputData.clientId, _id: { $nin: inputData.brandUsedList } } );
852
+ await planoProductService.insertMany( brandData );
853
+ // await Promise.all( Object.keys( brandData ).map( async ( ele ) => {
854
+ // await planoProductService.updateOne( { brandName: { $regex: brandData[ele].brandName, $options: 'i' }, clientId: req.body.clientId }, brandData[ele] );
855
+ // } ) );
775
856
  return res.sendSuccess( 'Brand details upload successfully' );
776
857
  } catch ( e ) {
777
858
  logger.error( { functionName: 'uploadBrandList', error: e } );
@@ -785,6 +866,8 @@ export async function getTaskConfig( req, res ) {
785
866
  if ( !taskConfigDetails ) {
786
867
  return res.sendError( 'No data found', 204 );
787
868
  }
869
+ taskConfigDetails = { ...taskConfigDetails.toObject() };
870
+ taskConfigDetails.dueTime = dayjs( taskConfigDetails.dueTime, 'hh:mm A' ).format( 'HH:mm' );
788
871
  return res.sendSuccess( taskConfigDetails );
789
872
  } catch ( e ) {
790
873
  logger.error( { functionName: 'getTaskConfig', error: e } );
@@ -796,6 +879,7 @@ export async function updateTaskConfig( req, res ) {
796
879
  try {
797
880
  let inputData = req.body;
798
881
  inputData.type = 'task';
882
+ inputData.dueTime = dayjs( inputData.dueTime, 'HH:mm' ).format( 'hh:mm A' );
799
883
  await planoStaticService.updateOne( { clientId: req.body.clientId, type: 'task' }, inputData );
800
884
  return res.sendSuccess( 'Task config updated successfully' );
801
885
  } catch ( e ) {
@@ -954,6 +1038,7 @@ export async function getVmLibList( req, res ) {
954
1038
  vmLibCode: 1,
955
1039
  vmSubCategory: 1,
956
1040
  planoId: { $ifNull: [ { $arrayElemAt: [ '$storeFixtureDetails.planoId', 0 ] }, [] ] },
1041
+ templateCount: { $size: '$templateId' },
957
1042
  },
958
1043
  },
959
1044
  {
@@ -995,6 +1080,7 @@ export async function getVmLibList( req, res ) {
995
1080
  vmLibCode: 1,
996
1081
  vmSubCategory: 1,
997
1082
  planoStatus: { $ifNull: [ { $arrayElemAt: [ '$planoStatus.statusList', 0 ] }, [] ] },
1083
+ templateCount: 1,
998
1084
  status: {
999
1085
  $cond: {
1000
1086
  if: { $and: [ { $in: [ 'completed', { $ifNull: [ { $arrayElemAt: [ '$planoStatus.statusList', 0 ] }, [] ] } ] }, { $gt: [ { $size: '$templateId' }, 0 ] } ] },