Subversion Repositories SmartDukaan

Rev

Rev 35791 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
35503 vikas 1
package com.spice.profitmandi.dao.service.shopify;
2
 
3
import com.fasterxml.jackson.databind.JsonNode;
4
import com.fasterxml.jackson.databind.ObjectMapper;
5
import com.spice.profitmandi.common.enumuration.SchemeType;
6
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
7
import com.spice.profitmandi.common.web.client.RestClient;
8
import com.spice.profitmandi.dao.entity.dtr.WebOffer;
9
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
10
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
11
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
12
import com.spice.profitmandi.dao.repository.dtr.WebOfferRepository;
13
import com.spice.profitmandi.dao.repository.fofo.CurrentInventorySnapshotRepository;
14
import com.spice.profitmandi.service.inventory.FofoAvailabilityInfo;
15
import com.spice.profitmandi.service.inventory.FofoCatalogResponse;
16
import com.spice.profitmandi.service.inventory.SaholicInventoryService;
17
import org.apache.commons.lang.StringUtils;
18
import org.apache.logging.log4j.LogManager;
19
import org.apache.logging.log4j.Logger;
20
import org.json.JSONArray;
21
import org.json.JSONObject;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.beans.factory.annotation.Value;
24
import org.springframework.stereotype.Service;
35930 vikas 25
import org.springframework.transaction.annotation.Propagation;
26
import org.springframework.transaction.annotation.Transactional;
35503 vikas 27
 
28
import java.util.*;
29
import java.util.stream.Collectors;
30
 
31
@Service
35930 vikas 32
@Transactional(propagation = Propagation.REQUIRES_NEW)
35503 vikas 33
public class ShopifyService {
34
 
35
    private static final Logger logger = LogManager.getLogger(ShopifyService.class);
36
 
37
    @Value("${new.solr.url}")
38
    private String solrUrl;
39
 
40
    @Autowired
41
    ObjectMapper objectMapper = new ObjectMapper();
42
    @Autowired
43
    ShopifyGraphQLService shopifyGraphQLService;
44
    @Autowired
45
    RestClient restClient;
46
    @Autowired
47
    FofoStoreRepository fofoStoreRepository;
48
    @Autowired
49
    ItemRepository itemRepository;
50
    @Autowired
51
    WebOfferRepository webOfferRepository;
52
    @Autowired
53
    CurrentInventorySnapshotRepository currentInventorySnapshotRepository;
54
    @Autowired
55
    SaholicInventoryService saholicInventoryService;
56
 
57
    // -------------------------------
58
    // ✅ 1. Create Product (with duplicate check)
59
    // -------------------------------
60
    public JsonNode createProduct(Map<String, Object> productInput) {
61
        try {
62
            return shopifyGraphQLService.productCreate(productInput);
63
        } catch (Exception e) {
64
            logger.error("createProduct Error: {}", e.getMessage());
65
            return objectMapper.createObjectNode();
66
        }
67
    }
68
 
69
    // -------------------------------
70
    // ✅ 2. Get All Products
71
    // -------------------------------
72
    public JsonNode getAllProducts() {
73
        try {
74
            String query = "query { products(first: 50) { edges { node { id title handle } } } }";
75
            return shopifyGraphQLService.execute(query, null);
76
        } catch (Exception e) {
77
            logger.error("getAllProducts Error: {}", e.getMessage());
78
            return objectMapper.createObjectNode();
79
        }
80
    }
81
 
82
    // -------------------------------
83
    // ✅ 3. Get Product by ID
84
    // -------------------------------
85
    public JsonNode getProductById(String productId) {
86
        try {
87
            String query = "query($id: ID!) { product(id: $id) { id title handle } }";
88
            Map<String, Object> vars = new HashMap<String, Object>();
89
            vars.put("id", productId);
90
            return shopifyGraphQLService.execute(query, vars);
91
        } catch (Exception e) {
92
            logger.error("getProductById Error: {}", e.getMessage());
93
            return objectMapper.createObjectNode();
94
        }
95
    }
96
 
97
    // -------------------------------
98
    // ✅ 4. Update Product by ID
99
    // -------------------------------
100
    public JsonNode updateProductById(String productId, Map<String, Object> params) {
101
        try {
102
            params.put("id", productId);
103
            String mutation = "mutation($input: ProductInput!) { productUpdate(input: $input) { product { id title } userErrors { field message } } }";
104
            Map<String, Object> vars = new HashMap<String, Object>();
105
            vars.put("input", params);
106
            return shopifyGraphQLService.execute(mutation, vars);
107
        } catch (Exception e) {
108
            logger.error("updateProductById Error: {}", e.getMessage());
109
            return objectMapper.createObjectNode();
110
        }
111
    }
112
 
113
    // -------------------------------
114
    // ✅ 5. Delete Product by ID
115
    // -------------------------------
116
    public JsonNode deleteProductById(String productId) {
117
        try {
118
            String mutation = "mutation($input: ProductDeleteInput!) { productDelete(input: $input) { deletedProductId userErrors { field message } } }";
119
            Map<String, Object> vars = new HashMap<String, Object>();
120
            Map<String, Object> input = new HashMap<String, Object>();
121
            input.put("id", productId);
122
            vars.put("input", input);
123
            return shopifyGraphQLService.execute(mutation, vars);
124
        } catch (Exception e) {
125
            logger.error("deleteProductById Error: {}", e.getMessage());
126
            return objectMapper.createObjectNode();
127
        }
128
    }
129
 
130
    public JsonNode getAllLocations() {
131
        try {
132
            String query = "query { locations(first: 10) { edges { node { id name } } } }";
133
            return shopifyGraphQLService.execute(query, null);
134
        } catch (Exception e) {
135
            logger.error("getAllLocations Error: {}", e.getMessage());
136
            return objectMapper.createObjectNode();
137
        }
138
    }
139
 
140
    public String getPrimaryLocationId() {
141
        try {
142
            JsonNode locationsResponse = getAllLocations();
143
            JsonNode edges = locationsResponse
144
                    .path("locations")
145
                    .path("edges");
146
 
35791 vikas 147
            if (edges.isArray() && edges.size() > 0) {
35503 vikas 148
                String locationId = edges.get(0).path("node").path("id").asText();
149
                logger.info("✅ Using Shopify Location ID: {}", locationId);
150
                return locationId;
151
            } else {
152
                logger.warn("⚠️ No Shopify locations found.");
153
                return null;
154
            }
155
        } catch (Exception e) {
156
            logger.error("getPrimaryLocationId Error: {}", e.getMessage());
157
            return null;
158
        }
159
    }
160
 
161
    public List<Map<String, Object>> buildAllVariantsBulk(List<FofoAvailabilityInfo> items, List<Map<String, String>> variantAttrs) {
162
 
163
        List<Map<String, Object>> list = new ArrayList<>();
164
 
165
        for (FofoAvailabilityInfo item : items) {
166
            String color = item.getColor().trim();
167
            String price = String.valueOf(item.getSellingPrice());
168
            String compareAt = String.valueOf(item.getMrp());
169
 
170
            for (Map<String, String> attr : variantAttrs) {
171
                String storageValue = attr.get("variantName").trim();
172
                String sku = String.valueOf(attr.get("catalogId"));
173
                list.add(buildVariant(color, storageValue, price, compareAt, sku));
174
            }
175
        }
176
 
177
        return list;
178
    }
179
 
180
    public Map<String, JsonNode> fetchVariantMapByOptions(String productId) throws Exception {
181
        String query =
182
            "query getVariants($id: ID!) { " +
183
                "  product(id: $id) { " +
184
                "    variants(first: 100) { " +
185
                "      edges { " +
186
                "        node { " +
187
                "          id " +
188
                "          title " +
189
                "          sku " +
190
                "          inventoryItem { id } " +
191
                "          selectedOptions { name value } " +
192
                "          image { originalSrc } " +
193
                "        } " +
194
                "      } " +
195
                "    } " +
196
                "  } " +
197
                "}";
198
 
199
        Map<String,Object> vars = new HashMap<>();
200
        vars.put("id", productId);
201
 
202
        JsonNode data = shopifyGraphQLService.execute(query, vars);
203
        JsonNode edges = data.path("product").path("variants").path("edges");
204
 
205
        Map<String, JsonNode> map = new HashMap<>();
206
 
207
        for (JsonNode edge : edges) {
208
            JsonNode node = edge.path("node");
209
 
35777 vikas 210
            String color = "", variant = "", insurance = "";
35503 vikas 211
 
212
            for (JsonNode opt : node.path("selectedOptions")) {
213
                String name = opt.path("name").asText();
214
                String value = opt.path("value").asText();
215
                if ("Color".equalsIgnoreCase(name)) color = value;
35777 vikas 216
                if ("Variant".equalsIgnoreCase(name)) variant = value;
217
                if ("Insurance".equalsIgnoreCase(name)) insurance = value;
35503 vikas 218
            }
219
 
35777 vikas 220
            String key = color + "|" + variant + "|" + insurance;
35503 vikas 221
            map.put(key.trim(), node);
222
        }
223
 
224
        return map;
225
    }
226
 
227
    public List<JsonNode> getAllOrders() {
228
        List<JsonNode> allOrders = new ArrayList<>();
229
        try {
230
            String cursor = null;
231
            while (true) {
232
                JsonNode page = shopifyGraphQLService.getOrders(cursor);
233
                JsonNode ordersNode = page.path("orders");
234
                JsonNode edges = ordersNode.path("edges");
235
                for (JsonNode edge : edges) {
236
                    allOrders.add(edge.path("node"));
237
                }
238
                boolean hasNext = ordersNode.path("pageInfo").path("hasNextPage").asBoolean();
239
                if (!hasNext) break;
240
                cursor = ordersNode.path("pageInfo").path("endCursor").asText();
241
            }
242
        } catch (Exception e) {
243
            logger.error("getAllOrders Error: {}", e.getMessage());
244
        }
245
        return allOrders;
246
    }
247
 
248
    public JsonNode getOrderDetailById(String id) {
249
        String graphQLId = "gid://shopify/Order/" + id;
250
        JsonNode order = null;
251
        try {
252
            JsonNode orderNode = shopifyGraphQLService.getOrderById(graphQLId);
253
            order = orderNode.path("order");
254
        } catch (Exception e) {
255
            logger.error("getAllOrders Error: {}", e.getMessage());
256
        }
257
 
258
        return order;
259
    }
260
 
261
    public List<FofoCatalogResponse> getAllDocs(FofoStore fofoStore) throws Exception {
262
 
263
        Map<String, String> params = new HashMap<String, String>();
264
        List<String> mandatoryQ = new ArrayList<String>();
265
        mandatoryQ.add("+active_b:true AND show_default_b:true");
266
 
267
        params.put("q", StringUtils.join(mandatoryQ, " "));
268
        params.put("fl", "*, [child parentFilter=id:catalog* childFilter=active_b:true ]");
269
        params.put("wt", "json");
270
        params.put("rows", "10");
271
 
272
        String response = restClient.get(SchemeType.HTTP, solrUrl, 8984, "solr/demo/select", params);
273
        JSONObject solrResponseJSONObj = new JSONObject(response).getJSONObject("response");
274
        JSONArray docs = solrResponseJSONObj.getJSONArray("docs");
275
 
276
        return getCatalogResponse(docs, fofoStore.getId());
277
 
278
    }
279
 
35777 vikas 280
    public List<FofoCatalogResponse> getAllDocsPaginated(FofoStore fofoStore, int batchSize) throws Exception {
281
        List<FofoCatalogResponse> allProducts = new ArrayList<>();
282
        int start = 0;
283
 
284
        while (true) {
285
            Map<String, String> params = new HashMap<>();
286
            params.put("q", "+active_b:true AND show_default_b:true");
287
            params.put("fl", "*, [child parentFilter=id:catalog* childFilter=active_b:true ]");
288
            params.put("wt", "json");
289
            params.put("rows", String.valueOf(batchSize));
290
            params.put("start", String.valueOf(start));
291
 
292
            String response = restClient.get(SchemeType.HTTP, solrUrl, 8984, "solr/demo/select", params);
293
            JSONObject solrResponseJSONObj = new JSONObject(response).getJSONObject("response");
294
            int numFound = solrResponseJSONObj.getInt("numFound");
295
            JSONArray docs = solrResponseJSONObj.getJSONArray("docs");
296
 
297
            if (docs.length() == 0) break;
298
 
299
            List<FofoCatalogResponse> batch = getCatalogResponse(docs, fofoStore.getId());
300
            allProducts.addAll(batch);
301
 
302
            start += batchSize;
303
            if (start >= numFound) break;
304
 
305
            logger.info("Fetched {} / {} products from Solr", Math.min(start, numFound), numFound);
306
        }
307
 
308
        logger.info("Total products fetched from Solr: {}", allProducts.size());
309
        return allProducts;
310
    }
311
 
312
    public List<FofoCatalogResponse> getAllDocsPaginatedForWarehouse(int batchSize) throws Exception {
313
        List<FofoCatalogResponse> allProducts = new ArrayList<>();
314
        int start = 0;
315
 
316
        while (true) {
317
            Map<String, String> params = new HashMap<>();
318
            params.put("q", "+active_b:true AND show_default_b:true");
319
            params.put("fl", "*, [child parentFilter=id:catalog* childFilter=active_b:true ]");
320
            params.put("wt", "json");
321
            params.put("rows", String.valueOf(batchSize));
322
            params.put("start", String.valueOf(start));
323
 
324
            String response = restClient.get(SchemeType.HTTP, solrUrl, 8984, "solr/demo/select", params);
325
            JSONObject solrResponseJSONObj = new JSONObject(response).getJSONObject("response");
326
            int numFound = solrResponseJSONObj.getInt("numFound");
327
            JSONArray docs = solrResponseJSONObj.getJSONArray("docs");
328
 
329
            if (docs.length() == 0) break;
330
 
331
            List<FofoCatalogResponse> batch = getCatalogResponse(docs, 0);
332
            allProducts.addAll(batch);
333
 
334
            start += batchSize;
335
            if (start >= numFound) break;
336
 
337
            logger.info("Fetched {} / {} products from Solr (warehouse)", Math.min(start, numFound), numFound);
338
        }
339
 
340
        logger.info("Total products fetched from Solr (warehouse): {}", allProducts.size());
341
        return allProducts;
342
    }
343
 
35503 vikas 344
    private List<FofoCatalogResponse> getCatalogResponse(JSONArray docs, int fofoId) throws ProfitMandiBusinessException {
345
        Map<Integer, Integer> ourItemAvailabilityMap = null;
35777 vikas 346
        Map<Integer, Integer> partnerStockAvailabilityMap = new HashMap<>();
35503 vikas 347
        List<FofoCatalogResponse> dealResponse = new ArrayList<>();
348
        if (docs.length() > 0) {
349
            HashSet<Integer> itemsSet = new HashSet<>();
350
            for (int i = 0; i < docs.length(); i++) {
351
                JSONObject doc = docs.getJSONObject(i);
352
                if (doc.has("_childDocuments_")) {
353
                    for (int j = 0; j < doc.getJSONArray("_childDocuments_").length(); j++) {
354
                        JSONObject childItem = doc.getJSONArray("_childDocuments_").getJSONObject(j);
355
                        int itemId = childItem.getInt("itemId_i");
356
                        itemsSet.add(itemId);
357
                    }
358
                }
359
            }
360
            if (itemsSet.isEmpty()) {
361
                return dealResponse;
362
            }
363
            if (fofoId > 0) {
364
                partnerStockAvailabilityMap = currentInventorySnapshotRepository.selectItemsStock(fofoId).stream().collect(Collectors.toMap(x -> x.getItemId(), x -> x.getAvailability()));
365
            }
366
            ourItemAvailabilityMap = saholicInventoryService.getTotalAvailabilityByItemIds(new ArrayList<>(itemsSet));
367
        }
368
 
369
        for (int i = 0; i < docs.length(); i++) {
370
            Map<Integer, FofoAvailabilityInfo> fofoAvailabilityInfoMap = new HashMap<>();
371
            JSONObject doc = docs.getJSONObject(i);
372
            FofoCatalogResponse ffdr = new FofoCatalogResponse();
373
            ffdr.setCatalogId(doc.getInt("catalogId_i"));
374
            ffdr.setImageUrl(doc.getString("imageUrl_s"));
375
            ffdr.setTitle(doc.getString("title_s"));
376
            ffdr.setSuperCatalogTitle(doc.getString("superCatalog_s"));
377
            ffdr.setSuperCatalogId(doc.getInt("superCatalog_i"));
378
            ffdr.setSuperCatalogVariants(doc.getString("superCatalogVariants_s"));
379
            List<WebOffer> webOffers = webOfferRepository.selectAllActiveOffers().get(ffdr.getCatalogId());
380
            if (webOffers != null && webOffers.size() > 0) {
381
                ffdr.setOffers(webOffers.stream().map(x -> x.getTitle()).collect(Collectors.toList()));
382
            }
383
            try {
384
                ffdr.setFeature(doc.getString("feature_s"));
385
            } catch (Exception e) {
386
                ffdr.setFeature(null);
387
            }
388
            ffdr.setBrand(doc.getJSONArray("brand_ss").getString(0));
389
 
390
            if (doc.has("_childDocuments_")) {
391
                for (int j = 0; j < doc.getJSONArray("_childDocuments_").length(); j++) {
35777 vikas 392
                    try {
393
                        JSONObject childItem = doc.getJSONArray("_childDocuments_").getJSONObject(j);
394
                        int itemId = childItem.getInt("itemId_i");
395
                        ffdr.setIsSmartPhone(itemRepository.selectById(itemId).isSmartPhone());
396
                        float sellingPrice = (float) childItem.getDouble("sellingPrice_f");
397
                        if (fofoAvailabilityInfoMap.containsKey(itemId)) {
398
                            if (fofoAvailabilityInfoMap.get(itemId).getSellingPrice() > sellingPrice) {
399
                                fofoAvailabilityInfoMap.get(itemId).setSellingPrice(sellingPrice);
400
                                fofoAvailabilityInfoMap.get(itemId).setMop((float) childItem.getDouble("mop_f"));
401
                            }
402
                        } else {
403
                            FofoAvailabilityInfo fdi = new FofoAvailabilityInfo();
404
                            fdi.setSellingPrice(sellingPrice);
405
                            fdi.setMrp(childItem.getDouble("mrp_f"));
406
                            fdi.setMop((float) childItem.getDouble("mop_f"));
407
                            fdi.setColor(childItem.has("color_s") ? childItem.getString("color_s") : "");
408
                            fdi.setTagId(childItem.getInt("tagId_i"));
409
                            fdi.setItem_id(itemId);
410
                            fdi.setCatalog_id(doc.getInt("catalogId_i"));
411
                            fdi.setCashback(0);
412
                            fdi.setMinBuyQuantity(1);
413
                            int partnerAvailability = partnerStockAvailabilityMap.get(itemId) == null ? 0 : partnerStockAvailabilityMap.get(itemId);
414
                            int ourStockAvailability = ourItemAvailabilityMap.get(itemId) == null ? 0 : Math.max(0, ourItemAvailabilityMap.get(itemId));
415
                            fdi.setActive(partnerAvailability > 0);
416
                            fdi.setPartnerAvailability(partnerAvailability);
417
                            fdi.setAvailability(Math.min(5, ourStockAvailability + partnerAvailability));
418
                            fdi.setQuantityStep(1);
419
                            fdi.setMaxQuantity(fdi.getAvailability());
420
                            fofoAvailabilityInfoMap.put(itemId, fdi);
35503 vikas 421
                        }
35777 vikas 422
                    } catch (Exception e) {
423
                        logger.warn("Skipping stale item in Solr doc catalogId={}: {}", doc.getInt("catalogId_i"), e.getMessage());
35503 vikas 424
                    }
425
                }
426
            }
427
            if (fofoAvailabilityInfoMap.values().size() > 0) {
428
                ffdr.setItems(fofoAvailabilityInfoMap.values().stream().sorted(Comparator.comparing(FofoAvailabilityInfo::isActive, Comparator.reverseOrder()).thenComparingInt(y -> -y.getAvailability())).collect(Collectors.toList()));
429
                dealResponse.add(ffdr);
430
            }
431
        }
432
        return dealResponse.stream().sorted(Comparator.comparing(FofoCatalogResponse::getItems, (s1, s2) -> (s2.get(0).isActive() ? 1 : 0) - (s1.get(0).isActive() ? 1 : 0)).thenComparing(FofoCatalogResponse::getItems, (x, y) -> y.get(0).getAvailability() - x.get(0).getAvailability())).collect(Collectors.toList());
433
    }
434
 
435
    private List<Map<String, String>> buildSelectedOptions(String color, String storage) {
436
 
437
        List<Map<String, String>> selectedOptions = new ArrayList<>();
438
 
439
        Map<String, String> c = new HashMap<>();
35777 vikas 440
        c.put("name", "Colour");
35503 vikas 441
        c.put("value", color);
442
        selectedOptions.add(c);
443
 
444
        Map<String, String> s = new HashMap<>();
445
        s.put("name", "Storage");
446
        s.put("value", storage);
447
        selectedOptions.add(s);
448
 
449
        return selectedOptions;
450
    }
451
 
452
    private Map<String, Object> buildVariant(String color, String storage, String price, String compareAt, String sku) {
453
        Map<String, Object> v = new HashMap<>();
454
 
455
        v.put("selectedOptions", this.buildSelectedOptions(color, storage));
456
        v.put("price", price);
457
        v.put("compareAtPrice", compareAt);
458
        v.put("sku", sku);
459
 
460
        return v;
461
    }
462
}