tango-app-api-store-builder 1.0.31 → 1.0.33
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 +2 -2
- package/src/controllers/fixtureTemplate.controller.js +339 -0
- package/src/controllers/managePlano.controller.js +264 -6
- package/src/controllers/script.controller.js +2 -2
- package/src/controllers/storeBuilder.controller.js +541 -60
- package/src/routes/managePlano.routes.js +23 -22
- package/src/routes/storeBuilder.routes.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-store-builder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"description": "storeBuilder",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"path": "^0.12.7",
|
|
33
33
|
"selenium-webdriver": "^4.31.0",
|
|
34
34
|
"sharp": "^0.34.1",
|
|
35
|
-
"tango-api-schema": "^2.5.
|
|
35
|
+
"tango-api-schema": "^2.5.23",
|
|
36
36
|
"tango-app-api-middleware": "3.1.48",
|
|
37
37
|
"url": "^0.11.4",
|
|
38
38
|
"winston": "^3.17.0",
|
|
@@ -690,6 +690,8 @@ export async function TemplateStoresList( req, res ) {
|
|
|
690
690
|
storeName: 1,
|
|
691
691
|
planoId: 1,
|
|
692
692
|
floorId: 1,
|
|
693
|
+
isMerchEdited: 1,
|
|
694
|
+
isVmEdited: 1,
|
|
693
695
|
},
|
|
694
696
|
},
|
|
695
697
|
{
|
|
@@ -699,6 +701,8 @@ export async function TemplateStoresList( req, res ) {
|
|
|
699
701
|
planoId: { $first: '$planoId' },
|
|
700
702
|
storeId: { $first: '$storeId' },
|
|
701
703
|
floorId: { $first: '$floorId' },
|
|
704
|
+
isMerchEdited: { $push: '$isMerchEdited' },
|
|
705
|
+
isVmEdited: { $push: '$isVmEdited' },
|
|
702
706
|
},
|
|
703
707
|
},
|
|
704
708
|
{
|
|
@@ -758,6 +762,8 @@ export async function TemplateStoresList( req, res ) {
|
|
|
758
762
|
spocEmail: { $ifNull: [ '$storeData.spocDetails.email', '' ] },
|
|
759
763
|
floorDetails: 1,
|
|
760
764
|
_id: '$_id.store',
|
|
765
|
+
isMerchEdited: 1,
|
|
766
|
+
isVmEdited: 1,
|
|
761
767
|
},
|
|
762
768
|
},
|
|
763
769
|
);
|
|
@@ -818,6 +824,335 @@ export async function TemplateStoresList( req, res ) {
|
|
|
818
824
|
);
|
|
819
825
|
}
|
|
820
826
|
|
|
827
|
+
query.push(
|
|
828
|
+
{
|
|
829
|
+
$lookup: {
|
|
830
|
+
from: 'processedtasks',
|
|
831
|
+
let: { store: '$storeId' },
|
|
832
|
+
pipeline: [
|
|
833
|
+
{
|
|
834
|
+
$match: {
|
|
835
|
+
$expr: {
|
|
836
|
+
$and: [
|
|
837
|
+
{ $lte: [ '$date_iso', new Date( dayjs().format( 'YYYY-MM-DD' ) ) ] },
|
|
838
|
+
{ $eq: [ '$store_id', '$$store' ] },
|
|
839
|
+
{ $eq: [ '$isPlano', true ] },
|
|
840
|
+
{ $in: [ '$planoType', [ 'merchRollout', 'vmRollout' ] ] },
|
|
841
|
+
],
|
|
842
|
+
},
|
|
843
|
+
},
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
$sort: { _id: -1 },
|
|
847
|
+
},
|
|
848
|
+
{
|
|
849
|
+
$group: {
|
|
850
|
+
_id: '$planoType',
|
|
851
|
+
type: { $first: '$planoType' },
|
|
852
|
+
status: { $first: '$checklistStatus' },
|
|
853
|
+
taskId: { $first: '$_id' },
|
|
854
|
+
scheduleEndTime_iso: { $first: '$scheduleEndTime_iso' },
|
|
855
|
+
},
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
$project: {
|
|
859
|
+
_id: 0,
|
|
860
|
+
type: 1,
|
|
861
|
+
status: 1,
|
|
862
|
+
taskId: 1,
|
|
863
|
+
breach: {
|
|
864
|
+
$cond: {
|
|
865
|
+
if: {
|
|
866
|
+
$gte: [ '$scheduleEndTime_iso', new Date() ],
|
|
867
|
+
},
|
|
868
|
+
then: false,
|
|
869
|
+
else: true,
|
|
870
|
+
},
|
|
871
|
+
},
|
|
872
|
+
},
|
|
873
|
+
},
|
|
874
|
+
],
|
|
875
|
+
as: 'taskDetails',
|
|
876
|
+
},
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
$lookup: {
|
|
880
|
+
from: 'planotaskcompliances',
|
|
881
|
+
let: { taskId: '$taskDetails.taskId' },
|
|
882
|
+
pipeline: [
|
|
883
|
+
{
|
|
884
|
+
$match: {
|
|
885
|
+
$expr: {
|
|
886
|
+
$and: [
|
|
887
|
+
{ $in: [ '$taskId', '$$taskId' ] },
|
|
888
|
+
{ $in: [ '$type', [ 'merchRollout', 'vmRollout' ] ] },
|
|
889
|
+
// { $eq: [ '$status', 'incomplete' ] },
|
|
890
|
+
],
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
$sort: { _id: -1 },
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
$set: {
|
|
899
|
+
hasCompletedAnswers: {
|
|
900
|
+
$anyElementTrue: {
|
|
901
|
+
$map: {
|
|
902
|
+
input: '$answers',
|
|
903
|
+
as: 'ans',
|
|
904
|
+
in: { $eq: [ '$$ans.status', null ] },
|
|
905
|
+
},
|
|
906
|
+
},
|
|
907
|
+
},
|
|
908
|
+
hasPendingIssues: {
|
|
909
|
+
$anyElementTrue: {
|
|
910
|
+
$map: {
|
|
911
|
+
input: {
|
|
912
|
+
$concatArrays: [
|
|
913
|
+
{
|
|
914
|
+
$reduce: {
|
|
915
|
+
input: '$answers',
|
|
916
|
+
initialValue: [],
|
|
917
|
+
in: {
|
|
918
|
+
$concatArrays: [
|
|
919
|
+
'$$value',
|
|
920
|
+
{
|
|
921
|
+
$reduce: {
|
|
922
|
+
input: { $ifNull: [ '$$this.issues', [] ] },
|
|
923
|
+
initialValue: [],
|
|
924
|
+
in: {
|
|
925
|
+
$concatArrays: [
|
|
926
|
+
'$$value',
|
|
927
|
+
{ $ifNull: [ '$$this.Details', [] ] },
|
|
928
|
+
],
|
|
929
|
+
},
|
|
930
|
+
},
|
|
931
|
+
},
|
|
932
|
+
],
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
},
|
|
936
|
+
],
|
|
937
|
+
},
|
|
938
|
+
as: 'detail',
|
|
939
|
+
in: {
|
|
940
|
+
$or: [ { $eq: [ '$$detail.status', 'pending' ] } ],
|
|
941
|
+
},
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
},
|
|
945
|
+
hasDisagreeIssues: {
|
|
946
|
+
$anyElementTrue: {
|
|
947
|
+
$map: {
|
|
948
|
+
input: {
|
|
949
|
+
$concatArrays: [
|
|
950
|
+
'$answers',
|
|
951
|
+
{
|
|
952
|
+
$reduce: {
|
|
953
|
+
input: '$answers',
|
|
954
|
+
initialValue: [],
|
|
955
|
+
in: {
|
|
956
|
+
$concatArrays: [
|
|
957
|
+
'$$value',
|
|
958
|
+
{
|
|
959
|
+
$reduce: {
|
|
960
|
+
input: { $ifNull: [ '$$this.issues', [] ] },
|
|
961
|
+
initialValue: [],
|
|
962
|
+
in: {
|
|
963
|
+
$concatArrays: [
|
|
964
|
+
'$$value',
|
|
965
|
+
{ $ifNull: [ '$$this.Details', [] ] },
|
|
966
|
+
],
|
|
967
|
+
},
|
|
968
|
+
},
|
|
969
|
+
},
|
|
970
|
+
],
|
|
971
|
+
},
|
|
972
|
+
},
|
|
973
|
+
},
|
|
974
|
+
],
|
|
975
|
+
},
|
|
976
|
+
as: 'detail',
|
|
977
|
+
in: {
|
|
978
|
+
$or: [ { $eq: [ '$$detail.status', 'disagree' ] } ],
|
|
979
|
+
},
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
},
|
|
983
|
+
},
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
$group: {
|
|
987
|
+
_id: { taskId: '$taskId' },
|
|
988
|
+
|
|
989
|
+
// merch counters
|
|
990
|
+
merchDisagree: {
|
|
991
|
+
$sum: {
|
|
992
|
+
$cond: [
|
|
993
|
+
{ $and: [ { $eq: [ '$type', 'merchRollout' ] }, '$hasDisagreeIssues' ] },
|
|
994
|
+
1,
|
|
995
|
+
0,
|
|
996
|
+
],
|
|
997
|
+
},
|
|
998
|
+
},
|
|
999
|
+
merchPending: {
|
|
1000
|
+
$sum: {
|
|
1001
|
+
$cond: [
|
|
1002
|
+
{
|
|
1003
|
+
$and: [
|
|
1004
|
+
{ $eq: [ '$type', 'merchRollout' ] },
|
|
1005
|
+
{ $or: [ '$hasPendingIssues', '$hasCompletedAnswers' ] },
|
|
1006
|
+
],
|
|
1007
|
+
},
|
|
1008
|
+
1,
|
|
1009
|
+
0,
|
|
1010
|
+
],
|
|
1011
|
+
},
|
|
1012
|
+
},
|
|
1013
|
+
merchApproved: {
|
|
1014
|
+
$push: {
|
|
1015
|
+
$cond: [
|
|
1016
|
+
{
|
|
1017
|
+
$and: [
|
|
1018
|
+
{ $eq: [ '$type', 'merchRollout' ] },
|
|
1019
|
+
{ $eq: [ '$approvalStatus', 'approved' ] },
|
|
1020
|
+
],
|
|
1021
|
+
},
|
|
1022
|
+
'$approvalStatus',
|
|
1023
|
+
'$$REMOVE',
|
|
1024
|
+
],
|
|
1025
|
+
},
|
|
1026
|
+
},
|
|
1027
|
+
|
|
1028
|
+
// vm counters
|
|
1029
|
+
vmDisagree: {
|
|
1030
|
+
$sum: {
|
|
1031
|
+
$cond: [
|
|
1032
|
+
{ $and: [ { $eq: [ '$type', 'vmRollout' ] }, '$hasDisagreeIssues' ] },
|
|
1033
|
+
1,
|
|
1034
|
+
0,
|
|
1035
|
+
],
|
|
1036
|
+
},
|
|
1037
|
+
},
|
|
1038
|
+
vmPending: {
|
|
1039
|
+
$sum: {
|
|
1040
|
+
$cond: [
|
|
1041
|
+
{
|
|
1042
|
+
$and: [
|
|
1043
|
+
{ $eq: [ '$type', 'vmRollout' ] },
|
|
1044
|
+
{ $or: [ '$hasPendingIssues', '$hasCompletedAnswers' ] },
|
|
1045
|
+
],
|
|
1046
|
+
},
|
|
1047
|
+
1,
|
|
1048
|
+
0,
|
|
1049
|
+
],
|
|
1050
|
+
},
|
|
1051
|
+
},
|
|
1052
|
+
vmApproved: {
|
|
1053
|
+
$push: {
|
|
1054
|
+
$cond: [
|
|
1055
|
+
{
|
|
1056
|
+
$and: [
|
|
1057
|
+
{ $eq: [ '$type', 'vmRollout' ] },
|
|
1058
|
+
{ $eq: [ '$approvalStatus', 'approved' ] },
|
|
1059
|
+
],
|
|
1060
|
+
},
|
|
1061
|
+
'$approvalStatus',
|
|
1062
|
+
'$$REMOVE',
|
|
1063
|
+
],
|
|
1064
|
+
},
|
|
1065
|
+
},
|
|
1066
|
+
|
|
1067
|
+
// counts
|
|
1068
|
+
merchCount: {
|
|
1069
|
+
$sum: {
|
|
1070
|
+
$cond: [ { $eq: [ '$type', 'merchRollout' ] }, 1, 0 ],
|
|
1071
|
+
},
|
|
1072
|
+
},
|
|
1073
|
+
vmCount: {
|
|
1074
|
+
$sum: {
|
|
1075
|
+
$cond: [ { $eq: [ '$type', 'vmRollout' ] }, 1, 0 ],
|
|
1076
|
+
},
|
|
1077
|
+
},
|
|
1078
|
+
},
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
$project: {
|
|
1082
|
+
_id: 0,
|
|
1083
|
+
fixtureStatus: {
|
|
1084
|
+
$switch: {
|
|
1085
|
+
branches: [
|
|
1086
|
+
{
|
|
1087
|
+
case: { $eq: [ '$merchCount', 0 ] },
|
|
1088
|
+
then: '',
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
case: { $gt: [ '$merchPending', 0 ] },
|
|
1092
|
+
then: 'pending',
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
case: { $gt: [ '$merchDisagree', 0 ] },
|
|
1096
|
+
then: 'disagree',
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
case: {
|
|
1100
|
+
$and: [
|
|
1101
|
+
{ $eq: [ '$merchPending', 0 ] },
|
|
1102
|
+
{ $eq: [ '$merchDisagree', 0 ] },
|
|
1103
|
+
{ $eq: [ { $size: '$merchApproved' }, '$merchCount' ] },
|
|
1104
|
+
],
|
|
1105
|
+
},
|
|
1106
|
+
then: 'complete',
|
|
1107
|
+
},
|
|
1108
|
+
],
|
|
1109
|
+
default: 'pending',
|
|
1110
|
+
},
|
|
1111
|
+
},
|
|
1112
|
+
vmStatus: {
|
|
1113
|
+
$switch: {
|
|
1114
|
+
branches: [
|
|
1115
|
+
{
|
|
1116
|
+
case: { $eq: [ '$vmCount', 0 ] },
|
|
1117
|
+
then: '',
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
case: { $gt: [ '$vmPending', 0 ] },
|
|
1121
|
+
then: 'pending',
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
case: { $gt: [ '$vmDisagree', 0 ] },
|
|
1125
|
+
then: 'disagree',
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
case: {
|
|
1129
|
+
$and: [
|
|
1130
|
+
{ $eq: [ '$vmPending', 0 ] },
|
|
1131
|
+
{ $eq: [ '$vmDisagree', 0 ] },
|
|
1132
|
+
{ $eq: [ { $size: '$vmApproved' }, '$vmCount' ] },
|
|
1133
|
+
],
|
|
1134
|
+
},
|
|
1135
|
+
then: 'complete',
|
|
1136
|
+
},
|
|
1137
|
+
],
|
|
1138
|
+
default: 'pending',
|
|
1139
|
+
},
|
|
1140
|
+
},
|
|
1141
|
+
},
|
|
1142
|
+
},
|
|
1143
|
+
],
|
|
1144
|
+
as: 'taskFeedback',
|
|
1145
|
+
},
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
$set: {
|
|
1149
|
+
taskFeedback: {
|
|
1150
|
+
$ifNull: [ { $arrayElemAt: [ '$taskFeedback', 0 ] }, {} ],
|
|
1151
|
+
},
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1154
|
+
);
|
|
1155
|
+
|
|
821
1156
|
let floorQuery = [
|
|
822
1157
|
{
|
|
823
1158
|
$match: {
|
|
@@ -873,6 +1208,10 @@ export async function replaceFixtureDetails( req, res ) {
|
|
|
873
1208
|
if ( !replaceFixtureData ) {
|
|
874
1209
|
return res.sendError( 'No data found', 204 );
|
|
875
1210
|
}
|
|
1211
|
+
|
|
1212
|
+
if ( inputData?.revoke && inputData?.assignedStores?.length ) {
|
|
1213
|
+
await processedTaskService.deleteMany( { storeName: { $in: inputData?.assignedStores }, isPlano: true, planoType: { $nin: [ 'layout', 'fixture' ] }, checklistStatus: { $ne: 'submit' } } );
|
|
1214
|
+
}
|
|
876
1215
|
if ( inputData.storeList.length == 0 && inputData.publishAll ) {
|
|
877
1216
|
await fixtureConfigService.updateOne( { _id: inputData.replaceFixture }, { isEdited: false } );
|
|
878
1217
|
let query = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as floorService from '../service/storeBuilder.service.js';
|
|
2
|
-
import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData, getOpenSearchById } from 'tango-app-api-middleware';
|
|
3
|
-
|
|
2
|
+
import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData, getOpenSearchById, fileUpload } from 'tango-app-api-middleware';
|
|
3
|
+
import * as storeService from '../service/store.service.js';
|
|
4
4
|
import * as planoService from '../service/planogram.service.js';
|
|
5
5
|
import * as storeFixtureService from '../service/storeFixture.service.js';
|
|
6
6
|
import * as fixtureShelfService from '../service/fixtureShelf.service.js';
|
|
@@ -1372,7 +1372,7 @@ export async function updateStoreFixture( req, res ) {
|
|
|
1372
1372
|
};
|
|
1373
1373
|
vmDetails = await planoVmService.create( planovmData );
|
|
1374
1374
|
}
|
|
1375
|
-
vmConfig.push(
|
|
1375
|
+
vmConfig.push({ ...vm, vmId: vmDetails._id, vmName: vmDetails.vmName, vmImage: vmDetails.vmImageUrl });
|
|
1376
1376
|
}
|
|
1377
1377
|
data.vmConfig = vmConfig;
|
|
1378
1378
|
let groupName = {
|
|
@@ -1826,9 +1826,9 @@ export async function createPlanoRevision( req, res ) {
|
|
|
1826
1826
|
await planoRevisionService.create( data );
|
|
1827
1827
|
|
|
1828
1828
|
await storeBuilderService.updateOne( { _id: floorId },
|
|
1829
|
-
{ ...( req.body.type
|
|
1830
|
-
...( req.body.type
|
|
1831
|
-
...( !
|
|
1829
|
+
{ ...( req.body.type.includes( 'merchRollout' ) ) ? { merchRolloutStatus: true } :{},
|
|
1830
|
+
...( req.body.type.includes( 'vmRollout' ) ) ? { vmRolloutStatus: true } : {},
|
|
1831
|
+
...( !req.body?.type && { verificationStatus: true } ), planoProgress: 100 } );
|
|
1832
1832
|
|
|
1833
1833
|
res.sendSuccess( 'Plano published successfully' );
|
|
1834
1834
|
} catch ( e ) {
|
|
@@ -2363,3 +2363,261 @@ export async function getPlanoStoreVideoPageParams( req, res ) {
|
|
|
2363
2363
|
res.sendError( 'Failed to fetch plano store video page params', 500 );
|
|
2364
2364
|
}
|
|
2365
2365
|
}
|
|
2366
|
+
|
|
2367
|
+
export async function createPlanoFromCAD(req, res) {
|
|
2368
|
+
try {
|
|
2369
|
+
const user = req.user;
|
|
2370
|
+
const file = req.files.file;
|
|
2371
|
+
const { storeId, floorNumber } = req.body;
|
|
2372
|
+
|
|
2373
|
+
if (!req?.files?.file) return res.sendError('File is required', 400);
|
|
2374
|
+
|
|
2375
|
+
if (!storeId || !floorNumber) return res.sendError('storeId and floorNumber are required', 400);
|
|
2376
|
+
|
|
2377
|
+
if (!file.name.endsWith('.dxf')) return res.sendError('Only DXF files are allowed', 400);
|
|
2378
|
+
|
|
2379
|
+
|
|
2380
|
+
// if (file.size > 20 * 1024 * 1024) {
|
|
2381
|
+
// return res.sendError('File size exceeds 20MB limit', 400);
|
|
2382
|
+
// }
|
|
2383
|
+
|
|
2384
|
+
// File Upload
|
|
2385
|
+
const fileUploadPayload = {
|
|
2386
|
+
Bucket: JSON.parse(process.env.BUCKET).storeBuilder,
|
|
2387
|
+
Key: `planoCad/`,
|
|
2388
|
+
fileName: Date.now() + '.' + file.name?.split('.')?.slice(-1)?.[0],
|
|
2389
|
+
ContentType: file.mimetype,
|
|
2390
|
+
body: file.data,
|
|
2391
|
+
};
|
|
2392
|
+
|
|
2393
|
+
const fileRes = await fileUpload(fileUploadPayload);
|
|
2394
|
+
|
|
2395
|
+
if (!fileRes?.Key) return res.sendError('Failed to upload file to storage', 502);
|
|
2396
|
+
|
|
2397
|
+
// CAD Extraction
|
|
2398
|
+
const dataExtractPayload = {
|
|
2399
|
+
s3Bucket: fileUploadPayload.Bucket,
|
|
2400
|
+
filePath: fileRes.Key,
|
|
2401
|
+
};
|
|
2402
|
+
|
|
2403
|
+
const cadRes = await fetch(
|
|
2404
|
+
JSON.parse(process.env.LAMBDAURL).extractCADDetails,
|
|
2405
|
+
{
|
|
2406
|
+
method: 'POST',
|
|
2407
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2408
|
+
body: JSON.stringify(dataExtractPayload),
|
|
2409
|
+
}
|
|
2410
|
+
);
|
|
2411
|
+
|
|
2412
|
+
if (!cadRes.ok) {
|
|
2413
|
+
const errorText = await cadRes.text();
|
|
2414
|
+
logger.error({ cadLambdaError: errorText });
|
|
2415
|
+
return res.sendError('CAD extraction service failed', 502);
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
const cadData = await cadRes.json();
|
|
2419
|
+
|
|
2420
|
+
logger.info({
|
|
2421
|
+
functionName: 'CAD DATA: ',
|
|
2422
|
+
body: { cadData, input: dataExtractPayload },
|
|
2423
|
+
});
|
|
2424
|
+
|
|
2425
|
+
if (
|
|
2426
|
+
cadData?.status !== 'success' ||
|
|
2427
|
+
!cadData?.data?.layoutPolygon
|
|
2428
|
+
) {
|
|
2429
|
+
return res.sendError('Invalid CAD layout data', 502);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
const userMeta = {
|
|
2433
|
+
createdBy: user._id,
|
|
2434
|
+
createdByEmail: user.email,
|
|
2435
|
+
createdByName: user.userName,
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// PLANOGRAM
|
|
2439
|
+
let planoData = await planoService.findOne({ storeId }, { _id: 1, clientId: 1, storeName: 1, });
|
|
2440
|
+
|
|
2441
|
+
if (!planoData) {
|
|
2442
|
+
const storeData = await storeService.findOne({ storeId }, { clientId: 1, storeName: 1 });
|
|
2443
|
+
if (!storeData) return res.sendError('Unable to find the store to create planogram', 400);
|
|
2444
|
+
|
|
2445
|
+
const newPlano = {
|
|
2446
|
+
clientId: storeData.clientId,
|
|
2447
|
+
storeName: storeData.storeName,
|
|
2448
|
+
storeId,
|
|
2449
|
+
layoutName: `${storeData.storeName} - Layout`,
|
|
2450
|
+
attachments: [],
|
|
2451
|
+
status: 'completed',
|
|
2452
|
+
productResolutionLevel: 'L2',
|
|
2453
|
+
scanType: 'qr',
|
|
2454
|
+
planoStrategy: "nonIvm",
|
|
2455
|
+
...userMeta
|
|
2456
|
+
};
|
|
2457
|
+
|
|
2458
|
+
planoData = await planoService.create(newPlano);
|
|
2459
|
+
if (!planoData) return res.sendError('Failed to create new planogram', 400);
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
const floorPayload = {
|
|
2463
|
+
layoutPolygon: processWallData(cadData.data.layoutPolygon),
|
|
2464
|
+
planoProgress: 25,
|
|
2465
|
+
floorName: `Floor ${floorNumber}`,
|
|
2466
|
+
isEdited: false,
|
|
2467
|
+
cadLayout: true
|
|
2468
|
+
};
|
|
2469
|
+
|
|
2470
|
+
let floorData = await floorService.findOne({ planoId: planoData._id, floorNumber }, { _id: 1, clientId: 1, storeName: 1, storeId: 1, planoId: 1 });
|
|
2471
|
+
if (floorData) {
|
|
2472
|
+
await floorService.updateOne({ _id: floorData._id }, { ...floorPayload, updatedBy: user._id });
|
|
2473
|
+
} else {
|
|
2474
|
+
const newFloor = {
|
|
2475
|
+
clientId: planoData.clientId,
|
|
2476
|
+
planoId: planoData._id,
|
|
2477
|
+
layoutName: `${planoData.storeName} - Layout`,
|
|
2478
|
+
status: 'completed',
|
|
2479
|
+
storeName: planoData.storeName,
|
|
2480
|
+
floorNumber,
|
|
2481
|
+
storeId,
|
|
2482
|
+
...floorPayload,
|
|
2483
|
+
...userMeta,
|
|
2484
|
+
};
|
|
2485
|
+
|
|
2486
|
+
floorData = await floorService.create(newFloor);
|
|
2487
|
+
if (!floorData) return res.sendError('Failed to create new floor layout', 400);
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
const meta = {
|
|
2491
|
+
clientId: floorData.clientId,
|
|
2492
|
+
storeName: floorData.storeName,
|
|
2493
|
+
storeId: floorData.storeId,
|
|
2494
|
+
planoId: floorData.planoId,
|
|
2495
|
+
floorId: floorData._id,
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// Create Fixtures
|
|
2499
|
+
const processedFixtures = createStoreFixtures(cadData.data, meta);
|
|
2500
|
+
|
|
2501
|
+
try {
|
|
2502
|
+
await storeFixtureService.deleteMany({ floorId: meta.floorId });
|
|
2503
|
+
await fixtureShelfService.deleteMany({ floorId: meta.floorId });
|
|
2504
|
+
for (let i = 0; i < processedFixtures.length; i++) {
|
|
2505
|
+
const fix = processedFixtures[i];
|
|
2506
|
+
await storeFixtureService.create(fix);
|
|
2507
|
+
}
|
|
2508
|
+
} catch (e) {
|
|
2509
|
+
logger.error({
|
|
2510
|
+
functionName: 'createPlanoFromCAD [Create Fixtures]',
|
|
2511
|
+
error: e,
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
return res.sendSuccess(meta);
|
|
2516
|
+
|
|
2517
|
+
} catch (error) {
|
|
2518
|
+
logger.error({
|
|
2519
|
+
functionName: 'createPlanoFromCAD',
|
|
2520
|
+
error,
|
|
2521
|
+
});
|
|
2522
|
+
|
|
2523
|
+
return res.sendError('Failed to create planogram.', 500);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
function processWallData(cadRes) {
|
|
2528
|
+
return cadRes.map((w) => {
|
|
2529
|
+
return {
|
|
2530
|
+
"elementType": w?.elementType ?? 'wall',
|
|
2531
|
+
"distance": w?.distance ?? 16,
|
|
2532
|
+
"elementNumber": w?.elementNumber ?? 0,
|
|
2533
|
+
"unit": w?.unit ?? "ft",
|
|
2534
|
+
"direction": w?.direction ?? "right",
|
|
2535
|
+
"angle": w?.angle ?? 0,
|
|
2536
|
+
"relativePosition": w?.relativePosition,
|
|
2537
|
+
}
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
function createStoreFixtures(data, meta) {
|
|
2542
|
+
|
|
2543
|
+
let fixtures = [];
|
|
2544
|
+
const walls = data?.layoutPolygon ?? [];
|
|
2545
|
+
for (let i = 1; i <= walls.length; i++) {
|
|
2546
|
+
const w = walls[i - 1];
|
|
2547
|
+
const wFixtures = w?.fixtures ?? [];
|
|
2548
|
+
|
|
2549
|
+
for (let j = 1; j <= wFixtures.length; j++) {
|
|
2550
|
+
const f = wFixtures[j - 1];
|
|
2551
|
+
|
|
2552
|
+
const fixtureInfo = {
|
|
2553
|
+
f: f,
|
|
2554
|
+
meta: meta,
|
|
2555
|
+
wallNumber: w.elementNumber,
|
|
2556
|
+
fixtureNumber: j,
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
fixtures.push(processFixtureData(fixtureInfo));
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
const centerFixtures = data?.centerFixture ?? [];
|
|
2564
|
+
for (let i = 1; i <= centerFixtures.length; i++) {
|
|
2565
|
+
const f = centerFixtures[i - 1];
|
|
2566
|
+
|
|
2567
|
+
const fixtureInfo = {
|
|
2568
|
+
f: f,
|
|
2569
|
+
meta: meta,
|
|
2570
|
+
wallNumber: undefined,
|
|
2571
|
+
fixtureNumber: i,
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
fixtures.push(processFixtureData(fixtureInfo));
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
return fixtures;
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
function processFixtureData(data) {
|
|
2581
|
+
const f = data.f;
|
|
2582
|
+
|
|
2583
|
+
function normalizeCadText(value) {
|
|
2584
|
+
if (typeof value !== 'string') return value;
|
|
2585
|
+
return value.replace(/^\\[^;]+;/, '').trim();
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
return {
|
|
2589
|
+
...data.meta,
|
|
2590
|
+
fixtureName: normalizeCadText(f?.header?.label ?? ''),
|
|
2591
|
+
relativePosition: f?.relativePosition,
|
|
2592
|
+
fixtureType: f?.associatedElementType,
|
|
2593
|
+
header: {
|
|
2594
|
+
...f?.header,
|
|
2595
|
+
label: normalizeCadText(f?.header?.label ?? '')
|
|
2596
|
+
},
|
|
2597
|
+
footer: f?.footer,
|
|
2598
|
+
fixtureWidth: f?.fixtureWidth,
|
|
2599
|
+
fixtureLength: f?.fixtureLength,
|
|
2600
|
+
fixtureNumber: f?.fixtureNumber,
|
|
2601
|
+
associatedElementNumber: data?.wallNumber,
|
|
2602
|
+
associatedElementFixtureNumber: data.fixtureNumber,
|
|
2603
|
+
associatedElementType: f?.associatedElementType === 'wall' ? 'wall' : undefined,
|
|
2604
|
+
productBrandName: Array.isArray(f?.productBrandName) ? f?.productBrandName?.map(normalizeCadText) : normalizeCadText(f?.productBrandName),
|
|
2605
|
+
|
|
2606
|
+
fixtureHeight: {
|
|
2607
|
+
value: 0,
|
|
2608
|
+
unit: 'mm',
|
|
2609
|
+
},
|
|
2610
|
+
fixtureStaticLength: {
|
|
2611
|
+
value: 1524,
|
|
2612
|
+
unit: 'mm',
|
|
2613
|
+
},
|
|
2614
|
+
fixtureStaticWidth: {
|
|
2615
|
+
value: 1220,
|
|
2616
|
+
unit: 'mm',
|
|
2617
|
+
},
|
|
2618
|
+
productResolutionLevel: 'L2',
|
|
2619
|
+
isBodyEnabled: true,
|
|
2620
|
+
isMerchEdited: false,
|
|
2621
|
+
isVmEdited: false,
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
@@ -9573,8 +9573,8 @@ export async function productMappings( req, res ) {
|
|
|
9573
9573
|
|
|
9574
9574
|
const { fixtureId, Top, Mid, Bottom } = payload;
|
|
9575
9575
|
|
|
9576
|
-
const storeName = '
|
|
9577
|
-
const storeId = '11-
|
|
9576
|
+
const storeName = 'LKST2681';
|
|
9577
|
+
const storeId = '11-2362';
|
|
9578
9578
|
const clientId = '11';
|
|
9579
9579
|
|
|
9580
9580
|
if ( !fixtureId ) {
|