Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
23365 ashik.ali 1
package com.spice.profitmandi.service.order;
22859 ashik.ali 2
 
24264 amit.gupta 3
import com.spice.profitmandi.common.enumuration.ItemType;
23202 ashik.ali 4
import com.spice.profitmandi.common.enumuration.SearchType;
33838 ranu 5
import com.spice.profitmandi.common.enumuration.UpgradeOfferPaymentStatus;
22859 ashik.ali 6
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
32420 amit.gupta 7
import com.spice.profitmandi.common.model.*;
23650 amit.gupta 8
import com.spice.profitmandi.common.util.FormattingUtils;
22859 ashik.ali 9
import com.spice.profitmandi.common.util.StringUtils;
23172 ashik.ali 10
import com.spice.profitmandi.common.util.Utils;
29515 tejbeer 11
import com.spice.profitmandi.common.web.client.RestClient;
33873 ranu 12
import com.spice.profitmandi.dao.cart.SmartCartService;
35695 amit 13
import com.spice.profitmandi.dao.entity.catalog.Category;
22859 ashik.ali 14
import com.spice.profitmandi.dao.entity.catalog.Item;
25103 amit.gupta 15
import com.spice.profitmandi.dao.entity.catalog.TagListing;
33795 ranu 16
import com.spice.profitmandi.dao.entity.catalog.UpgradeOffer;
32420 amit.gupta 17
import com.spice.profitmandi.dao.entity.dtr.*;
18
import com.spice.profitmandi.dao.entity.fofo.*;
28978 amit.gupta 19
import com.spice.profitmandi.dao.entity.inventory.State;
24917 tejbeer 20
import com.spice.profitmandi.dao.entity.transaction.Order;
22859 ashik.ali 21
import com.spice.profitmandi.dao.entity.user.Address;
27516 amit.gupta 22
import com.spice.profitmandi.dao.entity.warehouse.WarehouseInventoryItem;
24264 amit.gupta 23
import com.spice.profitmandi.dao.enumuration.catalog.SchemeType;
23546 ashik.ali 24
import com.spice.profitmandi.dao.enumuration.dtr.PaymentOptionReferenceType;
23650 amit.gupta 25
import com.spice.profitmandi.dao.enumuration.fofo.ReturnType;
22859 ashik.ali 26
import com.spice.profitmandi.dao.enumuration.fofo.ScanType;
23655 amit.gupta 27
import com.spice.profitmandi.dao.enumuration.fofo.SettlementType;
29515 tejbeer 28
import com.spice.profitmandi.dao.enumuration.inventory.ScratchedGift;
28339 tejbeer 29
import com.spice.profitmandi.dao.enumuration.transaction.OrderStatus;
33795 ranu 30
import com.spice.profitmandi.dao.repository.catalog.*;
32420 amit.gupta 31
import com.spice.profitmandi.dao.repository.dtr.*;
32
import com.spice.profitmandi.dao.repository.fofo.*;
24854 amit.gupta 33
import com.spice.profitmandi.dao.repository.inventory.StateRepository;
24917 tejbeer 34
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
22859 ashik.ali 35
import com.spice.profitmandi.dao.repository.user.AddressRepository;
27516 amit.gupta 36
import com.spice.profitmandi.dao.repository.warehouse.WarehouseInventoryItemRepository;
35236 amit 37
import com.spice.profitmandi.service.catalog.BrandsService;
34798 ranu 38
import com.spice.profitmandi.service.integrations.bharti.model.PlanVariant;
25724 amit.gupta 39
import com.spice.profitmandi.service.integrations.zest.InsuranceService;
31274 amit.gupta 40
import com.spice.profitmandi.service.integrations.zest.MobileInsurancePlan;
36305 amit 41
import com.spice.profitmandi.service.PartnerInvestmentService;
23418 ashik.ali 42
import com.spice.profitmandi.service.inventory.InventoryService;
23655 amit.gupta 43
import com.spice.profitmandi.service.inventory.PurchaseReturnService;
26891 amit.gupta 44
import com.spice.profitmandi.service.inventory.SaholicInventoryService;
28166 tejbeer 45
import com.spice.profitmandi.service.offers.ItemCriteria;
22859 ashik.ali 46
import com.spice.profitmandi.service.pricing.PricingService;
47
import com.spice.profitmandi.service.scheme.SchemeService;
23655 amit.gupta 48
import com.spice.profitmandi.service.user.RetailerService;
32420 amit.gupta 49
import org.apache.logging.log4j.LogManager;
50
import org.apache.logging.log4j.Logger;
51
import org.hibernate.Session;
52
import org.hibernate.SessionFactory;
53
import org.json.JSONObject;
54
import org.springframework.beans.factory.annotation.Autowired;
55
import org.springframework.beans.factory.annotation.Qualifier;
56
import org.springframework.beans.factory.annotation.Value;
57
import org.springframework.cache.annotation.Cacheable;
58
import org.springframework.core.io.InputStreamResource;
59
import org.springframework.http.HttpHeaders;
60
import org.springframework.http.HttpStatus;
61
import org.springframework.http.ResponseEntity;
62
import org.springframework.stereotype.Component;
22859 ashik.ali 63
 
32420 amit.gupta 64
import javax.persistence.criteria.CriteriaBuilder;
65
import javax.persistence.criteria.CriteriaQuery;
66
import javax.persistence.criteria.Predicate;
67
import javax.persistence.criteria.Root;
68
import java.io.ByteArrayInputStream;
69
import java.io.InputStream;
70
import java.time.LocalDate;
71
import java.time.LocalDateTime;
72
import java.time.LocalTime;
73
import java.util.AbstractMap.SimpleEntry;
74
import java.util.*;
75
import java.util.function.Function;
76
import java.util.stream.Collectors;
77
 
22859 ashik.ali 78
@Component
79
public class OrderServiceImpl implements OrderService {
80
 
32145 tejbeer 81
    private static final Logger LOGGER = LogManager.getLogger(OrderServiceImpl.class);
22859 ashik.ali 82
 
32145 tejbeer 83
    private static Map<String, Integer> serialNumberOrderIdMap = new HashMap<>();
31030 amit.gupta 84
 
32145 tejbeer 85
    static {
86
        serialNumberOrderIdMap.put("862897055749275", 67228);
87
    }
31030 amit.gupta 88
 
32145 tejbeer 89
    @Autowired
35236 amit 90
    BrandsService brandsService;
91
 
92
    @Autowired
32145 tejbeer 93
    @Qualifier("fofoInventoryItemRepository")
94
    private InventoryItemRepository inventoryItemRepository;
27083 amit.gupta 95
 
32145 tejbeer 96
    @Autowired
97
    private StateGstRateRepository stateGstRateRepository;
23650 amit.gupta 98
 
32145 tejbeer 99
    @Autowired
100
    private SaholicInventoryService saholicInventoryService;
27083 amit.gupta 101
 
32145 tejbeer 102
    @Autowired
103
    private LiveDemoBillingRespository liveDemoBillingRespository;
24823 amit.gupta 104
 
32145 tejbeer 105
    @Autowired
106
    private InsuranceService insuranceService;
25724 amit.gupta 107
 
32145 tejbeer 108
    @Autowired
36305 amit 109
    private PartnerInvestmentService partnerInvestmentService;
110
 
111
    @Autowired
32145 tejbeer 112
    @Qualifier("fofoCurrentInventorySnapshotRepository")
113
    private CurrentInventorySnapshotRepository currentInventorySnapshotRepository;
22859 ashik.ali 114
 
32145 tejbeer 115
    @Autowired
116
    private InvoiceNumberGenerationSequenceRepository invoiceNumberGenerationSequenceRepository;
22859 ashik.ali 117
 
32145 tejbeer 118
    @Autowired
119
    private PurchaseReturnService purchaseReturnService;
23655 amit.gupta 120
 
32145 tejbeer 121
    @Autowired
122
    private RetailerService retailerService;
23655 amit.gupta 123
 
32145 tejbeer 124
    @Autowired
125
    private CustomerRepository customerRepository;
23650 amit.gupta 126
 
32145 tejbeer 127
    @Autowired
128
    private PurchaseReturnItemRepository purchaseReturnItemRepository;
22859 ashik.ali 129
 
32145 tejbeer 130
    @Autowired
131
    private AddressRepository addressRepository;
22859 ashik.ali 132
 
32145 tejbeer 133
    @Autowired
134
    private FofoLineItemRepository fofoLineItemRepository;
22859 ashik.ali 135
 
32145 tejbeer 136
    @Autowired
32816 ranu 137
    private FofoNonSerializeSerialRepository fofoNonSerializeSerialRepository;
138
 
139
    @Autowired
32145 tejbeer 140
    private WarehouseInventoryItemRepository warehouseInventoryItemRepository;
27516 amit.gupta 141
 
32145 tejbeer 142
    @Autowired
143
    private FofoOrderItemRepository fofoOrderItemRepository;
23650 amit.gupta 144
 
32145 tejbeer 145
    @Autowired
146
    private PaymentOptionRepository paymentOptionRepository;
22859 ashik.ali 147
 
32145 tejbeer 148
    @Autowired
149
    private CustomerReturnItemRepository customerReturnItemRepository;
23650 amit.gupta 150
 
32145 tejbeer 151
    @Autowired
152
    @Qualifier("fofoScanRecordRepository")
153
    private ScanRecordRepository scanRecordRepository;
22859 ashik.ali 154
 
32145 tejbeer 155
    @Autowired
156
    private FofoOrderRepository fofoOrderRepository;
22859 ashik.ali 157
 
32145 tejbeer 158
    @Autowired
159
    private RetailerRepository retailerRepository;
22859 ashik.ali 160
 
32145 tejbeer 161
    @Autowired
162
    private UserRepository userRepository;
22859 ashik.ali 163
 
32145 tejbeer 164
    @Autowired
165
    private UserAccountRepository userAccountRepository;
22859 ashik.ali 166
 
32145 tejbeer 167
    @Autowired
168
    private RetailerRegisteredAddressRepository retailerRegisteredAddressRepository;
22859 ashik.ali 169
 
32145 tejbeer 170
    @Autowired
171
    private CustomerAddressRepository customerAddressRepository;
22859 ashik.ali 172
 
32145 tejbeer 173
    @Autowired
174
    @Qualifier("catalogItemRepository")
175
    private ItemRepository itemRepository;
23650 amit.gupta 176
 
32145 tejbeer 177
    @Autowired
178
    private InsuranceProviderRepository insuranceProviderRepository;
23650 amit.gupta 179
 
32145 tejbeer 180
    @Autowired
181
    private InsurancePolicyRepository insurancePolicyRepository;
24917 tejbeer 182
 
32145 tejbeer 183
    @Autowired
184
    private StateRepository stateRepository;
23650 amit.gupta 185
 
32145 tejbeer 186
    @Autowired
187
    private PolicyNumberGenerationSequenceRepository policyNumberGenerationSequenceRepository;
23650 amit.gupta 188
 
32145 tejbeer 189
    @Autowired
190
    private PricingService pricingService;
23650 amit.gupta 191
 
32145 tejbeer 192
    @Autowired
193
    private TagListingRepository tagListingRepository;
24823 amit.gupta 194
 
32145 tejbeer 195
    @Autowired
196
    private FofoStoreRepository fofoStoreRepository;
23650 amit.gupta 197
 
32145 tejbeer 198
    @Autowired
199
    private PaymentOptionTransactionRepository paymentOptionTransactionRepository;
23650 amit.gupta 200
 
32145 tejbeer 201
    @Autowired
202
    private SchemeService schemeService;
23650 amit.gupta 203
 
32145 tejbeer 204
    private static final List<Integer> orderIdsConsumed = new ArrayList<>();
28166 tejbeer 205
 
32145 tejbeer 206
    @Autowired
207
    @Qualifier("fofoInventoryService")
208
    private InventoryService inventoryService;
23650 amit.gupta 209
 
32145 tejbeer 210
    @Autowired
211
    private CustomerCreditNoteRepository customerCreditNoteRepository;
23650 amit.gupta 212
 
32145 tejbeer 213
    @Autowired
214
    private OrderRepository orderRepository;
24917 tejbeer 215
 
32145 tejbeer 216
    @Autowired
35695 amit 217
    private CategoryRepository categoryRepository;
218
 
219
    @Autowired
32145 tejbeer 220
    private HygieneDataRepository hygieneDataRepository;
25640 tejbeer 221
 
32145 tejbeer 222
    @Autowired
223
    private SessionFactory sessionFactory;
28166 tejbeer 224
 
32145 tejbeer 225
    @Autowired
226
    private Mongo mongoClient;
28964 tejbeer 227
 
32145 tejbeer 228
    @Autowired
229
    private PendingOrderRepository pendingOrderRepository;
28964 tejbeer 230
 
32145 tejbeer 231
    @Autowired
33399 ranu 232
 
233
    private PendingOrderService pendingOrderService;
234
 
235
    @Autowired
32145 tejbeer 236
    private PendingOrderItemRepository pendingOrderItemRepository;
28166 tejbeer 237
 
32145 tejbeer 238
    @Autowired
239
    private ScratchOfferRepository scratchOfferRepository;
29515 tejbeer 240
 
32145 tejbeer 241
    @Autowired
242
    RestClient restClient;
29515 tejbeer 243
 
33715 ranu 244
    @Autowired
245
    UpSaleOrderRepository upSaleOrderRepository;
246
 
33795 ranu 247
    @Autowired
248
    private CustomerOfferRepository customerOfferRepository;
249
 
250
    @Autowired
251
    private CustomerOfferItemRepository customerOfferItemRepository;
252
 
253
    @Autowired
254
    private UpgradeOfferRepository upgradeOfferRepository;
255
 
33873 ranu 256
    @Autowired
257
    private SmartCartService smartCartService;
258
 
33895 ranu 259
    @Autowired
36560 amit 260
    private com.spice.profitmandi.service.transaction.SDCreditService sdCreditService;
261
 
262
    @Autowired
33895 ranu 263
    private PartnerTypeChangeService partnerTypeChangeService;
264
 
32145 tejbeer 265
    @Value("${prod}")
266
    private boolean prodEnv;
29515 tejbeer 267
 
32145 tejbeer 268
    private static final String SMS_GATEWAY = "http://api.pinnacle.in/index.php/sms/send";
269
    private static final String SENDER = "SMTDKN";
29515 tejbeer 270
 
32145 tejbeer 271
    public static final String APP_DOWNLOAD_BILLING_TEMPLATE_ID = "1507163542403945677";
29515 tejbeer 272
 
32145 tejbeer 273
    public static final String APP_DOWNLOAD_BILLING_OFFER = "Dear Customer, Thank you for purchasing from SmartDukaan pls click %s to download our app to see you invoice and special offers. SmartDukaan";
29515 tejbeer 274
 
34342 ranu 275
    static Map<Double, List<ScratchedGift>> GIFT_SERIES = new TreeMap<>(Comparator.reverseOrder());
276
 
34340 ranu 277
    // Define eligible partners for LED & Microwave Oven
34351 ranu 278
    private static final Set<Integer> PREMIUM_ELIGIBLE_PARTNERS = new HashSet<>(Arrays.asList(175139615, 175139583));
34342 ranu 279
    private static Map<ScratchedGift, Integer> GIFT_QUANTITIES = new HashMap<>();
280
    List<Double> PRICE_RANGE = Arrays.asList(0.0, Double.MAX_VALUE);
33899 ranu 281
 
34340 ranu 282
    static {
34365 ranu 283
        GIFT_QUANTITIES.put(ScratchedGift.ACCESSORIES_50_PERCENT_OFF, 500);
34340 ranu 284
        GIFT_QUANTITIES.put(ScratchedGift.NECK_BAND, 280);
285
        GIFT_QUANTITIES.put(ScratchedGift.LED, 1);
286
        GIFT_QUANTITIES.put(ScratchedGift.MICROWAVE_OVEN, 1);
287
    }
288
 
289
    static {
290
        GIFT_SERIES.put(0.0, Arrays.asList(ScratchedGift.ACCESSORIES_50_PERCENT_OFF, ScratchedGift.NECK_BAND));
34365 ranu 291
        GIFT_SERIES.put(30001.0, Arrays.asList(ScratchedGift.NECK_BAND, ScratchedGift.MICROWAVE_OVEN, ScratchedGift.LED));
34340 ranu 292
    }
293
 
33899 ranu 294
    private void persistNonSerializedWithCustomSerialNumber(CustomFofoOrderItem customFofoOrderItem, int orderItemId) {
295
        // Create a new instance of FofoNonSerializeSerial
296
        for (String accSerialNumber : customFofoOrderItem.getCustomSerialNumbers()) {
297
            if (!accSerialNumber.isEmpty()) {
298
                FofoNonSerializeSerial nonSerializeSerial = new FofoNonSerializeSerial();
299
 
300
                // Populate the entity with relevant information
301
                nonSerializeSerial.setOrderItemId(orderItemId);
302
                nonSerializeSerial.setSerialNumber(accSerialNumber);
303
 
304
                // Save the entity to the database
305
                fofoNonSerializeSerialRepository.persist(nonSerializeSerial);
306
            }
307
 
308
        }
309
    }
310
 
311
 
312
    public void sendAppDownloadBillingOffer(String mobileNumber) throws Exception {
313
        String sdurl = "http://surl.li/anhfn";
314
        try {
315
            if (prodEnv) {
316
                this.sendSms(APP_DOWNLOAD_BILLING_TEMPLATE_ID, String.format(APP_DOWNLOAD_BILLING_OFFER, sdurl), mobileNumber);
317
            }
318
        } catch (Exception e) {
319
            e.printStackTrace();
320
        }
321
 
322
    }
323
 
324
    public void sendSms(String dltTemplateId, String message, String mobileNumber) throws Exception {
325
        Map<String, String> map = new HashMap<>();
326
 
327
        map.put("sender", SENDER);
328
        map.put("messagetype", "TXT");
329
        map.put("apikey", "b866f7-c6c483-682ff5-054420-ad9e2c");
330
 
331
        map.put("numbers", "91" + mobileNumber);
332
        LOGGER.info("Message {}", message);
333
        // OTP Message Template
334
        map.put("message", message);
335
        map.put("dlttempid", dltTemplateId);
336
 
337
        String response = restClient.post(SMS_GATEWAY, map, new HashMap<>());
338
        LOGGER.info(response);
339
 
340
    }
341
 
342
 
343
    private void createScratchOffer(int fofoId, String invoiceNumber, int customerId) {
344
 
345
        //ScratchedGift gift = getScratchedGiftRandom(fofoId, customerId);
346
 
347
 
348
        //  LocalDateTime endDate = LocalDateTime.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), 27, 21, 00);
349
        List<ScratchOffer> scratchOffers = scratchOfferRepository.selectBycCustomerIdAndDate(customerId, ProfitMandiConstants.SCRATCH_OFFER_START_DATE, ProfitMandiConstants.SCRATCH_OFFER_END_DATE);
350
        if (scratchOffers.size() == 0) {
351
            ScratchOffer so2 = new ScratchOffer();
352
            so2.setInvoiceNumber(invoiceNumber);
353
            so2.setScratched(false);
354
            so2.setCreatedTimestamp(LocalDateTime.now());
355
            so2.setExpiredTimestamp(ProfitMandiConstants.SCRATCH_OFFER_END_DATE.plusDays(1).atTime(LocalTime.MAX));
34474 aman.kumar 356
            so2.setOfferName(String.valueOf(ScratchedGift.BLNT));
33899 ranu 357
            so2.setCustomerId(customerId);
358
 
359
            LocalDateTime today830PM = LocalDate.now().atTime(20, 30);
360
            LocalDateTime today9PM = LocalDate.now().atTime(21, 0);
361
            so2.setUnlockedAt(LocalDateTime.now());
362
 
363
//            if (LocalDateTime.now().isAfter(today830PM)) {
364
//                so2.setUnlockedAt(today9PM.plusDays(0));
365
//            } else {
366
//                so2.setUnlockedAt(today9PM);
367
//            }
368
            scratchOfferRepository.persist(so2);
369
        }
370
    }
371
 
34341 ranu 372
 
32145 tejbeer 373
    @Override
34194 ranu 374
    public int createOrder(CreateOrderRequest createOrderRequest, int fofoId, boolean accessoriesDeals) throws Exception {
32145 tejbeer 375
        LOGGER.info("fofoId -- {} Order Request -- {}", fofoId, createOrderRequest);
376
        CustomCustomer customCustomer = createOrderRequest.getCustomer();
377
        Customer customer = customerRepository.selectById(customCustomer.getCustomerId());
22872 ashik.ali 378
 
35156 aman 379
        if ((createOrderRequest.getCustomer().getGender() != null && createOrderRequest.getCustomer().getGender().equals("2"))) {
35097 ranu 380
            customer.setGender("Female");
381
        } else {
382
 
383
            customer.setGender("Male");
384
        }
385
 
32145 tejbeer 386
        if (!StringUtils.isValidGstNumber(customCustomer.getGstNumber())) {
387
            LOGGER.error("invalid customer gstNumber {} ", customCustomer.getGstNumber());
388
            throw new ProfitMandiBusinessException(ProfitMandiConstants.CUSTOMER_GST_NUMBER, customCustomer.getGstNumber(), "VE_1072");
389
        }
23650 amit.gupta 390
 
32145 tejbeer 391
        Map<Integer, Integer> itemIdQuantity = new HashMap<>(); // this is for error
392
        Map<Integer, CustomFofoOrderItem> itemIdCustomFofoOrderItemMap = new HashMap<>();
393
        Map<Integer, Float> lineItemPrice = new HashMap<>(); // this is for pricing error
23650 amit.gupta 394
 
32145 tejbeer 395
        float totalAmount = 0;
396
        boolean noGST = false;
35493 amit 397
 
398
        // N+1 fix: Batch fetch all PendingOrderItems before the validation loop
399
        List<Integer> validationPoiIds = createOrderRequest.getFofoOrderItems().stream()
400
                .map(CustomFofoOrderItem::getPoiId)
401
                .filter(id -> id > 0)
402
                .collect(Collectors.toList());
403
        Map<Integer, PendingOrderItem> pendingOrderItemMap = new HashMap<>();
404
        if (!validationPoiIds.isEmpty()) {
405
            List<PendingOrderItem> pendingOrderItems = pendingOrderItemRepository.selectByIds(validationPoiIds);
406
            pendingOrderItemMap = pendingOrderItems.stream()
407
                    .collect(Collectors.toMap(PendingOrderItem::getId, poi -> poi));
408
        }
409
 
32145 tejbeer 410
        for (CustomFofoOrderItem customFofoOrderItem : createOrderRequest.getFofoOrderItems()) {
33520 amit.gupta 411
            if (customFofoOrderItem.getPoiId() > 0) {
35493 amit 412
                // N+1 fix: Use pre-fetched map instead of querying per item
413
                PendingOrderItem pendingOrderItem = pendingOrderItemMap.get(customFofoOrderItem.getPoiId());
414
                if (pendingOrderItem == null) {
415
                    throw new ProfitMandiBusinessException("poiId", customFofoOrderItem.getPoiId(), "Pending order item not found");
416
                }
33520 amit.gupta 417
                if (customFofoOrderItem.getQuantity() > pendingOrderItem.getQuantity()) {
33414 amit.gupta 418
                    throw new ProfitMandiBusinessException("itemIdQuantity", customFofoOrderItem.getItemId(), "Quantity should not be greater than order item quantity");
33399 ranu 419
                }
33520 amit.gupta 420
                if (pendingOrderItem.getQuantity() > customFofoOrderItem.getQuantity()) {
421
                    pendingOrderService.duplicatePendingOrder(pendingOrderItem, customFofoOrderItem.getQuantity());
33399 ranu 422
                }
423
            }
32145 tejbeer 424
            // itemIds.add(customFofoOrderItem.getItemId());
425
            Set<String> serialNumbers = this.serialNumberDetailsToSerialNumbers(customFofoOrderItem.getSerialNumberDetails());
426
            if (!serialNumbers.isEmpty() && customFofoOrderItem.getQuantity() != serialNumbers.size()) {
427
                itemIdQuantity.put(customFofoOrderItem.getItemId(), customFofoOrderItem.getQuantity());
428
            }
429
            if (!(customFofoOrderItem.getSellingPrice() > 0)) {
430
                lineItemPrice.put(customFofoOrderItem.getItemId(), customFofoOrderItem.getSellingPrice());
431
            } else {
33554 tejus.loha 432
                totalAmount = totalAmount + customFofoOrderItem.getSellingPrice() * customFofoOrderItem.getQuantity();
32145 tejbeer 433
                for (SerialNumberDetail serialNumberDetail : customFofoOrderItem.getSerialNumberDetails()) {
434
                    if (serialNumberDetail.getAmount() > 0) {
435
                        totalAmount = totalAmount + serialNumberDetail.getAmount();
436
                    }
437
                }
438
            }
23650 amit.gupta 439
 
32145 tejbeer 440
            itemIdCustomFofoOrderItemMap.put(customFofoOrderItem.getItemId(), customFofoOrderItem);
441
        }
442
        if (!itemIdQuantity.isEmpty()) {
443
            // if item quantity does not match with given serialnumbers size
444
            LOGGER.error("itemId's quantity should be equal to given serialnumber size {} ", itemIdQuantity);
445
            throw new ProfitMandiBusinessException("itemIdQuantity", itemIdQuantity, "FFORDR_1001");
446
            // return "error";
447
        }
23650 amit.gupta 448
 
32145 tejbeer 449
        this.validatePaymentOptionsAndTotalAmount(createOrderRequest.getPaymentOptions(), totalAmount);
23650 amit.gupta 450
 
32145 tejbeer 451
        if (!lineItemPrice.isEmpty()) {
452
            // given fofo line item price must be greater than zero
453
            LOGGER.error("requested itemId's selling price must greater than 0");
454
            throw new ProfitMandiBusinessException(ProfitMandiConstants.PRICE, lineItemPrice, "FFORDR_1002");
455
        }
22859 ashik.ali 456
 
32145 tejbeer 457
        List<CurrentInventorySnapshot> currentInventorySnapshots = currentInventorySnapshotRepository.selectByFofoItemIds(fofoId, itemIdCustomFofoOrderItemMap.keySet());
23650 amit.gupta 458
 
32145 tejbeer 459
        this.validateCurrentInventorySnapshotQuantities(currentInventorySnapshots, itemIdCustomFofoOrderItemMap);
22859 ashik.ali 460
 
32145 tejbeer 461
        List<Item> items = itemRepository.selectByIds(itemIdCustomFofoOrderItemMap.keySet());
462
        if (items.size() != itemIdCustomFofoOrderItemMap.keySet().size()) {
463
            LOGGER.error("Requested ItemIds not found in catalog");
464
            // invalid itemIds
465
            throw new ProfitMandiBusinessException("invalidItemIds", itemIdCustomFofoOrderItemMap.keySet(), "FFORDR_1003");
466
        }
23650 amit.gupta 467
 
32145 tejbeer 468
        Map<Integer, Item> itemMap = this.toItemMap(items);
23650 amit.gupta 469
 
35800 amit 470
        FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(fofoId);
471
 
32145 tejbeer 472
        Set<Integer> nonSerializedItemIds = new HashSet<>();
473
        Set<String> serialNumbers = new HashSet<>();
474
        List<InsuranceModel> insuredModels = new ArrayList<>();
35733 amit 475
        noGST = items.stream().anyMatch(item -> "NOGST".equals(item.getHsnCode()));
32145 tejbeer 476
        for (CustomFofoOrderItem customFofoOrderItem : createOrderRequest.getFofoOrderItems()) {
477
            Item item = itemMap.get(customFofoOrderItem.getItemId());
478
            if (item.getType().equals(ItemType.SERIALIZED)) {
479
                for (SerialNumberDetail serialNumberDetail : customFofoOrderItem.getSerialNumberDetails()) {
480
                    serialNumbers.add(serialNumberDetail.getSerialNumber());
481
                    if (serialNumberDetail.getAmount() > 0) {
482
                        if (customer.getEmailId() == null || customer.getEmailId().equals("")) {
483
                            throw new ProfitMandiBusinessException("Email Id is required for insurance", "Email Id is required for insurance", "Email Id is required for insurance");
484
                        }
34194 ranu 485
 
32145 tejbeer 486
                        InsuranceModel im = new InsuranceModel();
487
                        im.setBrand(item.getBrand());
488
                        im.setColor(item.getColor());
489
                        im.setModelName(item.getModelName() + item.getModelNumber());
490
                        im.setInsuranceAmount(serialNumberDetail.getAmount());
491
                        im.setDeviceSellingPrice(customFofoOrderItem.getSellingPrice());
34194 ranu 492
                        im.setInsuranceUId(serialNumberDetail.getInsurance());
34798 ranu 493
                        im.setCorrelationId(serialNumberDetail.getCorrelationId());
494
 
495
                        PlanVariant oneAssistpremium = insuranceService.getOneAssistPremiumByVariantId(serialNumberDetail.getInsurance());
496
                        if (oneAssistpremium != null) {
497
                            im.setInsuranceId(String.valueOf(oneAssistpremium.getId()));
498
                        } else {
499
                            im.setInsuranceId(String.valueOf(insuranceService.getICICIPremiumByVariantId(serialNumberDetail.getInsurance()).getId()));
500
                        }
32145 tejbeer 501
                        im.setSerialNumber(serialNumberDetail.getSerialNumber());
502
                        im.setMemory(serialNumberDetail.getMemory());
503
                        im.setRam(serialNumberDetail.getRam());
504
                        im.setMfgDate(serialNumberDetail.getMfgDate());
505
                        insuredModels.add(im);
506
                        // Check for free insurance code
507
                        try {
33520 amit.gupta 508
                            Map<String, List<MobileInsurancePlan>> mobileInsurancePlanMap = insuranceService.getAllPlans(item.getId(), im.getDeviceSellingPrice(), false);
32145 tejbeer 509
                            MobileInsurancePlan mobileInsurancePlan = mobileInsurancePlanMap.entrySet().stream().flatMap(x -> x.getValue().stream()).filter(x -> x.getProductId().equals(serialNumberDetail.getInsurance())).findFirst().get();
34798 ranu 510
/*                            if (mobileInsurancePlan.getPlanName().equals("OneAssist Damage Protection Plan")) {
511
                                MobileInsurancePlan freePlan = mobileInsurancePlanMap.get("Prolong Extendended Warranty(SmartDukaan Special Price)").get(0);
512
                                InsuranceModel imFree = new InsuranceModel();
513
                                imFree.setBrand(item.getBrand());
514
                                imFree.setColor(item.getColor());
515
                                imFree.setModelName(item.getModelName() + item.getModelNumber());
516
                                imFree.setInsuranceAmount(0);
517
                                imFree.setDeviceSellingPrice(customFofoOrderItem.getSellingPrice());
518
                                LOGGER.info("freePlan.getProductId() {}", freePlan.getProductId());
519
                                imFree.setInsuranceUId(freePlan.getProductId());
520
                                imFree.setInsuranceId(String.valueOf(insuranceService.getOneAssistPremiumByVariantId(freePlan.getProductId()).getId()));
521
                                imFree.setSerialNumber(serialNumberDetail.getSerialNumber());
522
                                imFree.setMemory(serialNumberDetail.getMemory());
523
                                imFree.setRam(serialNumberDetail.getRam());
524
                                imFree.setMfgDate(serialNumberDetail.getMfgDate());
525
                                insuredModels.add(imFree);
526
                            }*/
32145 tejbeer 527
                        } catch (Exception e) {
528
                            LOGGER.error("Exception - {}", e);
529
                            throw new ProfitMandiBusinessException("problem fetching plans", "problem fetching plans", "problem fetching plans");
530
                        }
531
                    }
31274 amit.gupta 532
 
32145 tejbeer 533
                }
534
            } else {
535
                nonSerializedItemIds.add(customFofoOrderItem.getItemId());
536
            }
537
        }
23650 amit.gupta 538
 
32145 tejbeer 539
        Map<Integer, Set<InventoryItem>> serializedInventoryItemMap = new HashMap<>();
540
        Map<Integer, Set<InventoryItem>> nonSerializedInventoryItemMap = new HashMap<>();
541
        // Map<String, Float> serialNumberItemPrice = new HashMap<>();
23650 amit.gupta 542
 
32145 tejbeer 543
        if (!serialNumbers.isEmpty()) {
544
            List<InventoryItem> serializedInventoryItems = inventoryItemRepository.selectByFofoIdSerialNumbers(fofoId, serialNumbers, false);
545
            LOGGER.info("serializedInventoryItems {}", serializedInventoryItems);
546
            for (InventoryItem inventoryItem : serializedInventoryItems) {
547
                if (inventoryItem.getGoodQuantity() == 1) {
548
                    if (serializedInventoryItemMap.containsKey(inventoryItem.getItemId())) {
549
                        serializedInventoryItemMap.get(inventoryItem.getItemId()).add(inventoryItem);
550
                    } else {
551
                        Set<InventoryItem> itemIdInventoryItems = new HashSet<>();
552
                        itemIdInventoryItems.add(inventoryItem);
553
                        serializedInventoryItemMap.put(inventoryItem.getItemId(), itemIdInventoryItems);
554
                    }
555
                }
556
            }
557
        }
23418 ashik.ali 558
 
32145 tejbeer 559
        if (!nonSerializedItemIds.isEmpty()) {
560
            List<InventoryItem> nonSerializedInventoryItems = inventoryItemRepository.selectByFofoIdItemIds(fofoId, nonSerializedItemIds);
561
            LOGGER.info("nonSerializedInventoryItems {}", nonSerializedInventoryItems);
562
            for (InventoryItem it : nonSerializedInventoryItems) {
563
                if (it.getGoodQuantity() > 0) {
564
                    if (nonSerializedInventoryItemMap.containsKey(it.getItemId())) {
565
                        nonSerializedInventoryItemMap.get(it.getItemId()).add(it);
566
                    } else {
567
                        Set<InventoryItem> tmp = new HashSet<>();
568
                        tmp.add(it);
569
                        nonSerializedInventoryItemMap.put(it.getItemId(), tmp);
570
                    }
571
                }
572
            }
573
        }
23650 amit.gupta 574
 
32145 tejbeer 575
        this.validateItemsSerializedNonSerialized(items, itemIdCustomFofoOrderItemMap);
22859 ashik.ali 576
 
32145 tejbeer 577
        Map<Integer, Set<InventoryItem>> inventoryItemsToBill = new HashMap<>();
578
        Map<Integer, Integer> inventoryItemIdQuantityUsed = new HashMap<>(); // to keep track of inventoryitem quanity
579
        // used for scan records insertion
22859 ashik.ali 580
 
32145 tejbeer 581
        LOGGER.info("itemMap keys {}", itemMap.keySet());
35695 amit 582
 
35733 amit 583
        // Fetch live demo serial numbers only for this order's serials (not entire table)
584
        List<String> orderSerials = serializedInventoryItemMap.values().stream()
35695 amit 585
                .flatMap(Set::stream)
586
                .map(InventoryItem::getSerialNumber)
587
                .collect(Collectors.toList());
588
        Map<String, LiveDemoSerialNumber> liveDemoSerialNumberMap = new HashMap<>();
35733 amit 589
        if (!orderSerials.isEmpty()) {
590
            liveDemoSerialNumberMap = liveDemoBillingRespository.selectBySerialNumbers(orderSerials).stream()
35695 amit 591
                    .collect(Collectors.toMap(LiveDemoSerialNumber::getSerialNumber, ld -> ld, (a, b) -> a));
592
        }
593
 
32145 tejbeer 594
        // Lets reduce quantity and decide what inventory items to use.
595
        for (Item item : items) {
596
            if (item.getType().equals(ItemType.SERIALIZED)) {
35736 amit 597
                Set<InventoryItem> inventoryItemsSerializedserialized = serializedInventoryItemMap.get(item.getId());
598
                if (inventoryItemsSerializedserialized == null) {
599
                    List<String> invalidSerialNumbers = itemIdCustomFofoOrderItemMap.get(item.getId()).getSerialNumberDetails().stream().map(x -> x.getSerialNumber()).collect(Collectors.toList());
600
                    throw new ProfitMandiBusinessException("invalidSerialNumbers", invalidSerialNumbers, "FFORDR_1004");
601
                }
602
                if (itemIdCustomFofoOrderItemMap.get(item.getId()).getSerialNumberDetails().size() != inventoryItemsSerializedserialized.size()) {
35232 ranu 603
                    LOGGER.info("InsuredModels: {}, and Serialized: {}", insuredModels.size(), itemIdCustomFofoOrderItemMap.get(item.getId()).getSerialNumberDetails().size());
604
                    if (itemIdCustomFofoOrderItemMap.get(item.getId()).getSerialNumberDetails().size() != insuredModels.size()) {
605
                        List<String> invalidSerialNumbers = itemIdCustomFofoOrderItemMap.get(item.getId()).getSerialNumberDetails().stream().map(x -> x.getSerialNumber()).collect(Collectors.toList());
606
                        throw new ProfitMandiBusinessException("invalidSerialNumbers", invalidSerialNumbers, "FFORDR_1004");
607
                    }
32145 tejbeer 608
                }
609
                for (InventoryItem inventoryItem : inventoryItemsSerializedserialized) {
610
                    inventoryItem.setGoodQuantity(0);
611
                    inventoryItemIdQuantityUsed.put(inventoryItem.getId(), 1);
35695 amit 612
                    LiveDemoSerialNumber liveDemoSerialNumber = liveDemoSerialNumberMap.get(inventoryItem.getSerialNumber());
613
                    if (liveDemoSerialNumber != null) {
32145 tejbeer 614
                        liveDemoBillingRespository.delete(liveDemoSerialNumber);
615
                    }
616
                }
617
                inventoryItemsToBill.put(item.getId(), inventoryItemsSerializedserialized);
618
            } else {
619
                Set<InventoryItem> inventoryItemsNonSerialized = nonSerializedInventoryItemMap.get(item.getId());
620
                int quantityToBill = itemIdCustomFofoOrderItemMap.get(item.getId()).getQuantity();
621
                int totalLeft = quantityToBill;
622
                Set<InventoryItem> inventoryItemsNonSerializedUsed = new HashSet<>();
623
                if (inventoryItemsNonSerialized != null) {
624
                    for (InventoryItem inventoryItem : inventoryItemsNonSerialized) {
625
                        if (totalLeft > 0) {
626
                            int toUse = Math.min(totalLeft, inventoryItem.getGoodQuantity());
627
                            inventoryItemIdQuantityUsed.put(inventoryItem.getId(), toUse);
628
                            inventoryItem.setGoodQuantity(inventoryItem.getGoodQuantity() - toUse);
629
                            totalLeft = totalLeft - toUse;
630
                            inventoryItemsNonSerializedUsed.add(inventoryItem);
631
                        }
632
                    }
633
                }
23650 amit.gupta 634
 
32145 tejbeer 635
                if (totalLeft > 0) {
636
                    // not enough quanity for non-serialized
637
                    LOGGER.error("not enough quanity for non-serialized");
638
                    throw new ProfitMandiBusinessException("notEnoughQuantityForNonSerialized", totalLeft, "FFORDR_1005");
639
                }
640
                inventoryItemsToBill.put(item.getId(), inventoryItemsNonSerializedUsed);
641
            }
642
        }
23650 amit.gupta 643
 
35733 amit 644
        // DP/MOP price validation disabled as of 11 sep 2025 as per tarun sir
23650 amit.gupta 645
 
32145 tejbeer 646
        String fofoStoreCode = this.getFofoStoreCode(fofoId);
647
        String documentNumber = null;
648
        if (noGST) {
649
            documentNumber = this.getSecurityDepositNumber(fofoId, fofoStoreCode);
24275 amit.gupta 650
 
32145 tejbeer 651
        } else {
652
            documentNumber = this.getInvoiceNumber(fofoId, fofoStoreCode);
653
        }
22859 ashik.ali 654
 
32627 ranu 655
        CustomerAddress customerAddress = null;
656
        if (customCustomer.getCustomerAddressId() != 0) {
657
            customerAddress = customer.getCustomerAddress().stream().filter(x -> x.getId() == customCustomer.getCustomerAddressId()).findFirst().get();
658
        }
34381 vikas.jang 659
        FofoOrder fofoOrder = this.createAndGetFofoOrder(customer.getId(), customCustomer.getGstNumber(), fofoId, documentNumber, totalAmount, customCustomer.getCustomerAddressId(), createOrderRequest.getPoId());
36305 amit 660
        partnerInvestmentService.evictInvestmentCache(fofoId);
23650 amit.gupta 661
 
32145 tejbeer 662
        this.createPaymentOptions(fofoOrder, createOrderRequest.getPaymentOptions());
23650 amit.gupta 663
 
32145 tejbeer 664
        int retailerAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(fofoId);
23650 amit.gupta 665
 
32145 tejbeer 666
        Address retailerAddress = addressRepository.selectById(retailerAddressId);
23650 amit.gupta 667
 
32145 tejbeer 668
        Integer stateId = null;
32634 amit.gupta 669
        if (customerAddress == null || customerAddress.getState() == null || customerAddress.getState().equals(retailerAddress.getState())) {
32145 tejbeer 670
            try {
32634 amit.gupta 671
                State state = stateRepository.selectByName(retailerAddress.getState());
32145 tejbeer 672
                stateId = Long.valueOf(state.getId()).intValue();
673
            } catch (Exception e) {
35736 amit 674
                LOGGER.error("Unable to get state rates for state: {}", retailerAddress.getState(), e);
32145 tejbeer 675
            }
676
        }
23650 amit.gupta 677
 
35493 amit 678
        // N+1 fix: Pre-fetch tagListings and GST rates before the loop
679
        Map<Integer, TagListing> tagListingMap = tagListingRepository.selectByItemIds(itemIdCustomFofoOrderItemMap.keySet());
680
        Map<Integer, GstRate> gstRateMap = null;
681
        if (stateId != null) {
682
            gstRateMap = stateGstRateRepository.getStateTaxRate(new ArrayList<>(itemMap.keySet()), stateId);
683
        } else {
684
            gstRateMap = stateGstRateRepository.getIgstTaxRate(new ArrayList<>(itemMap.keySet()));
685
        }
686
 
35695 amit 687
        // N+1 fix: Collect created FofoOrderItems during the loop instead of re-querying
688
        List<FofoOrderItem> fofoItems = new ArrayList<>();
32145 tejbeer 689
        for (CustomFofoOrderItem customFofoOrderItem : createOrderRequest.getFofoOrderItems()) {
35493 amit 690
            FofoOrderItem fofoOrderItem = this.createAndGetFofoOrderItem(customFofoOrderItem, fofoOrder.getId(), itemMap, inventoryItemsToBill.get(customFofoOrderItem.getItemId()), tagListingMap, gstRateMap);
35695 amit 691
            fofoItems.add(fofoOrderItem);
23650 amit.gupta 692
 
32816 ranu 693
            Item item = itemMap.get(customFofoOrderItem.getItemId());
694
            if (item.getType().equals(ItemType.NON_SERIALIZED)) {
695
                if (customFofoOrderItem.getCustomSerialNumbers() != null && !customFofoOrderItem.getCustomSerialNumbers().isEmpty()) {
696
                    persistNonSerializedWithCustomSerialNumber(customFofoOrderItem, fofoOrderItem.getId());
697
                } else {
698
                    LOGGER.info("Custom serial numbers are empty. Not persisting data.");
699
                }
700
            }
701
 
702
 
32145 tejbeer 703
            Set<InventoryItem> inventoryItems = inventoryItemsToBill.get(customFofoOrderItem.getItemId());
23650 amit.gupta 704
 
32145 tejbeer 705
            this.createFofoLineItem(fofoOrderItem.getId(), inventoryItems, inventoryItemIdQuantityUsed);
23650 amit.gupta 706
 
32145 tejbeer 707
            this.updateCurrentInventorySnapshot(currentInventorySnapshots, fofoId, customFofoOrderItem.getItemId(), customFofoOrderItem.getQuantity());
23650 amit.gupta 708
 
32145 tejbeer 709
            this.updateInventoryItemsAndScanRecord(inventoryItems, fofoId, inventoryItemIdQuantityUsed, fofoOrder.getId());
710
        }
23650 amit.gupta 711
 
35493 amit 712
        // Use existing itemMap instead of querying DB per item (N+1 fix)
713
        boolean smartPhone = items.stream().anyMatch(Item::isSmartPhone);
714
        if (smartPhone) {
715
            LOGGER.info("Smartphone found in order items");
716
        } else {
32892 ranu 717
            LOGGER.warn("No smartphones found in fofoItems.");
32145 tejbeer 718
        }
31172 tejbeer 719
 
32892 ranu 720
 
32145 tejbeer 721
        if (smartPhone) {
722
            this.createAndGetHygieneData(fofoOrder.getId(), fofoOrder.getFofoId());
723
        }
724
        // insurance calculation is insurance flag is enabled
725
        //
726
        if (insuredModels.size() > 0) {
727
            LOGGER.info("Processing insurane for serialNumbers");
728
            LOGGER.info("InsuranceModels {}", insuredModels);
35695 amit 729
            if (createOrderRequest.getCustomer() == null || createOrderRequest.getCustomer().getDateOfBirth() == null) {
730
                throw new ProfitMandiBusinessException("Order", "Customer Date of Birth", "Customer date of birth is required for insurance");
731
            }
32145 tejbeer 732
            LocalDate customerDateOfBirth = LocalDate.from(createOrderRequest.getCustomer().getDateOfBirth());
733
            fofoOrder.setDateOfBirth(customerDateOfBirth);
734
            for (InsuranceModel insuranceModel : insuredModels) {
34207 ranu 735
                LOGGER.info("G- {}", insuranceModel.getInsuranceId());
736
                LOGGER.info("insuranceModel- {}", insuranceModel);
33715 ranu 737
                insuranceService.createInsurance(fofoOrder, insuranceModel, false);
32145 tejbeer 738
            }
739
        }
28339 tejbeer 740
 
32145 tejbeer 741
        schemeService.processSchemeOut(fofoOrder.getId(), fofoId);
31993 amit.gupta 742
 
32145 tejbeer 743
        if (createOrderRequest.getPoId() != 0) {
744
            PendingOrder po = pendingOrderRepository.selectById(createOrderRequest.getPoId());
745
            po.setBilledAmount(po.getBilledAmount() + totalAmount);
35493 amit 746
 
747
            // N+1 fix: Batch fetch pending order items instead of querying per item
748
            List<Integer> poiIds = createOrderRequest.getFofoOrderItems().stream()
749
                    .map(CustomFofoOrderItem::getPoiId)
750
                    .filter(id -> id != 0)
751
                    .collect(Collectors.toList());
752
            if (!poiIds.isEmpty()) {
753
                List<PendingOrderItem> pendingOrderItems = pendingOrderItemRepository.selectByIds(poiIds);
754
                LocalDateTime now = LocalDateTime.now();
755
                for (PendingOrderItem poi : pendingOrderItems) {
756
                    poi.setStatus(OrderStatus.BILLED);
757
                    poi.setBilledTimestamp(now);
758
                }
33399 ranu 759
            }
35493 amit 760
 
33436 ranu 761
            po.setStatus(OrderStatus.BILLED);
32145 tejbeer 762
        }
35736 amit 763
        //Process scratch (only if smartphone in order — processScratchOffer re-queries items)
764
        if (smartPhone) {
765
            this.processScratchOffer(fofoOrder);
766
        }
29515 tejbeer 767
 
33795 ranu 768
//        persist the data of upgrade offer table
769
        for (CustomFofoOrderItem customFofoOrderItem : createOrderRequest.getFofoOrderItems()) {
34805 ranu 770
            if (customFofoOrderItem.getCustomerOfferItemId().size() > 0) {
771
                for (Integer customerOfferItemId : customFofoOrderItem.getCustomerOfferItemId()) {
772
                    UpgradeOffer upgradeOffer = new UpgradeOffer();
773
                    upgradeOffer.setOrderId(fofoOrder.getId());
774
                    upgradeOffer.setCustomerOfferItemId(customerOfferItemId);
775
                    upgradeOffer.setItemId(customFofoOrderItem.getItemId());
33795 ranu 776
 
34805 ranu 777
                    Set<SerialNumberDetail> serialNumberDetails = customFofoOrderItem.getSerialNumberDetails();
33795 ranu 778
 
34805 ranu 779
                    if (!customFofoOrderItem.getSerialNumberDetails().isEmpty()) {
780
                        String serialNumber = serialNumberDetails.iterator().next().getSerialNumber();
781
                        upgradeOffer.setSerialNumber(serialNumber);
33795 ranu 782
 
34805 ranu 783
                        //                Set<String> serialNumbersSet = this.serialNumberDetailsToSerialNumbers(customFofoOrderItem.getSerialNumberDetails());
784
                        //                LOGGER.info("serialNumbersSet.toString() {}",serialNumbersSet.toString());
785
                        //                upgradeOffer.setSerialNumber(serialNumbersSet.toString());
786
                    } else {
787
                        upgradeOffer.setSerialNumber(null); // Handle case where there is no serial number detail
788
                    }
789
                    upgradeOffer.setCreatedTimestamp(LocalDateTime.now());
790
                    upgradeOffer.setPaymentStatus(UpgradeOfferPaymentStatus.PENDING);
791
                    upgradeOffer.setStatusDescription(UpgradeOfferPaymentStatus.PENDING.getValue());
792
                    upgradeOfferRepository.persist(upgradeOffer);
33795 ranu 793
                }
34805 ranu 794
 
33795 ranu 795
            }
796
        }
797
 
35493 amit 798
//        enable it fo upsell call - N+1 fix: smartPhone already determined, no need to re-query items
799
        if (smartPhone && fofoOrder.getId() > 0) {
800
            List<InsurancePolicy> insurancePolicies = insurancePolicyRepository
801
                    .selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());
802
            if (insurancePolicies.isEmpty()) {
803
                UpSaleOrder upSaleOrder = new UpSaleOrder();
804
                upSaleOrder.setCreatedTimestamp(LocalDateTime.now());
805
                upSaleOrder.setOrderId(fofoOrder.getId());
806
                upSaleOrder.setFofoId(fofoOrder.getFofoId());
807
                upSaleOrderRepository.persist(upSaleOrder);
33715 ranu 808
            }
809
        }
33674 ranu 810
 
35493 amit 811
        // Update Partner Opening Stock current qty - N+1 fix: use existing itemMap and batch update
33899 ranu 812
        if (fofoOrder.getId() > 0) {
35493 amit 813
            Map<Integer, Integer> itemIdQuantityMap = new HashMap<>();
814
            for (FofoOrderItem fofoOrderItem : fofoItems) {
815
                itemIdQuantityMap.merge(fofoOrderItem.getItemId(), fofoOrderItem.getQuantity(), Integer::sum);
33873 ranu 816
            }
35493 amit 817
            smartCartService.minusOpeningStockBatch(itemIdQuantityMap, fofoOrder.getFofoId());
33873 ranu 818
        }
819
 
36958 amit 820
        // Flagship credit conversion: convert exactly the sold devices by their IMEI/serial. Each flagship
821
        // limit row covers one IMEI, so the sold serials map straight to the rows to convert — same-model
822
        // siblings (this invoice or other billing tranches) keep their interest-free window.
36560 amit 823
        try {
36958 amit 824
            if (sdCreditService.hasActiveFlagshipLimits(fofoId) && !serialNumbers.isEmpty()) {
825
                sdCreditService.convertFlagshipOnSale(fofoId, serialNumbers);
36560 amit 826
            }
827
        } catch (Exception e) {
828
            LOGGER.error("Failed to convert flagship credits on sale for fofoId {}", fofoId, e);
829
        }
830
 
32961 amit.gupta 831
        return fofoOrder.getId();
832
    }
833
 
33665 ranu 834
    @Override
835
    public void processScratchOffer(FofoOrder fofoOrder) throws ProfitMandiBusinessException {
836
        boolean isSmartPhonePurchased = false;
837
        float maxPurchaseValue = 0;
838
        List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
35493 amit 839
 
840
        // N+1 fix: batch fetch all items instead of querying per order item
841
        Set<Integer> itemIds = fofoOrderItems.stream()
842
                .map(FofoOrderItem::getItemId)
843
                .collect(Collectors.toSet());
844
        Map<Integer, Item> itemMap = itemRepository.selectByIds(itemIds).stream()
845
                .collect(Collectors.toMap(Item::getId, item -> item));
846
 
33665 ranu 847
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
35493 amit 848
            Item item = itemMap.get(fofoOrderItem.getItemId());
33665 ranu 849
 
35493 amit 850
            if (item != null && item.isSmartPhone()) {
33665 ranu 851
                LOGGER.info("fofoItem {}", fofoOrderItem);
852
                isSmartPhonePurchased = true;
853
                maxPurchaseValue = Math.max(fofoOrderItem.getSellingPrice(), maxPurchaseValue);
854
            }
855
        }
856
        LocalDate startDate = ProfitMandiConstants.SCRATCH_OFFER_START_DATE;
857
        LocalDate endDate = ProfitMandiConstants.SCRATCH_OFFER_END_DATE;
858
        boolean specificPriceOffer = ProfitMandiConstants.SPECIFIC_PRICE_OFFER;
859
        boolean randomOffer = ProfitMandiConstants.RANDOM_OFFER;
860
 
861
        if (isSmartPhonePurchased) {
862
 
863
            if (LocalDateTime.now().isAfter(startDate.atStartOfDay()) && LocalDateTime.now().isBefore(endDate.atTime(Utils.MAX_TIME))) {
864
                Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
865
                try {
866
                    this.sendAppDownloadBillingOffer(customer.getMobileNumber());
867
                } catch (Exception e) {
35736 amit 868
                    LOGGER.error("Failed to send app download billing offer for customer {}", customer.getMobileNumber(), e);
33665 ranu 869
                }
870
                if (specificPriceOffer) {
33899 ranu 871
                    this.createSpecificPriceScratchOffer(fofoOrder.getInvoiceNumber(), fofoOrder.getCustomerId(), fofoOrder.getFofoId(), maxPurchaseValue);
33665 ranu 872
                } else if (randomOffer) {
873
                    this.createRandomScratchOffer(fofoOrder.getInvoiceNumber(), fofoOrder.getCustomerId());
874
                    LOGGER.info("randomOffer {}", randomOffer);
875
                } else {
876
                    this.createScratchOffer(fofoOrder.getFofoId(), fofoOrder.getInvoiceNumber(), fofoOrder.getCustomerId());
877
                }
878
 
879
            }
880
        }
881
    }
882
 
883
    @Override
33899 ranu 884
    public ScratchedGift getSelectedGift(double purchaseAmount, int fofoId) throws ProfitMandiBusinessException {
34351 ranu 885
        Map<ScratchedGift, Long> scratchOfferCountMap = scratchOfferRepository.countOffersByDateRange(
886
                ProfitMandiConstants.SCRATCH_OFFER_START_DATE, ProfitMandiConstants.SCRATCH_OFFER_END_DATE
887
        );
888
        LOGGER.info("scratchOfferCountMap {}", scratchOfferCountMap);
889
 
890
        LocalDateTime startDateTime = ProfitMandiConstants.SCRATCH_OFFER_START_DATE.atStartOfDay();
34365 ranu 891
        LocalDateTime endDateTime = ProfitMandiConstants.SCRATCH_OFFER_START_DATE.atTime(LocalTime.MAX);
34351 ranu 892
 
34365 ranu 893
        LOGGER.info("start date {}", startDateTime);
894
        LOGGER.info("end date {}", endDateTime);
895
 
33899 ranu 896
        RandomCollection<ScratchedGift> giftRandomCollection = createDynamicGiftSeries(scratchOfferCountMap, purchaseAmount, fofoId);
34351 ranu 897
 
33665 ranu 898
        if (giftRandomCollection.size() > 0) {
34340 ranu 899
            ScratchedGift selectedGift = giftRandomCollection.next();
900
 
34353 ranu 901
            // Ensure one LED for 175139615 and one Oven for 175139583
34351 ranu 902
            if (selectedGift == ScratchedGift.LED || selectedGift == ScratchedGift.MICROWAVE_OVEN) {
34340 ranu 903
                if (!PREMIUM_ELIGIBLE_PARTNERS.contains(fofoId)) {
904
                    LOGGER.info("Partner {} not eligible for {}", fofoId, selectedGift);
34351 ranu 905
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF; // Default alternate gift
34340 ranu 906
                }
907
 
34351 ranu 908
                // Restrict LED to Partner 175139615 and Oven to Partner 175139583
909
                if ((selectedGift == ScratchedGift.LED && fofoId != 175139615) ||
910
                        (selectedGift == ScratchedGift.MICROWAVE_OVEN && fofoId != 175139583)) {
911
                    LOGGER.info("Partner {} not eligible for {}", fofoId, selectedGift);
912
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
913
                }
914
 
34340 ranu 915
                // Ensure only one LED and one Microwave Oven per day
34351 ranu 916
                long ledCount = scratchOfferCountMap.getOrDefault(ScratchedGift.LED, 0L);
917
                long ovenCount = scratchOfferCountMap.getOrDefault(ScratchedGift.MICROWAVE_OVEN, 0L);
918
                if ((selectedGift == ScratchedGift.LED || selectedGift == ScratchedGift.MICROWAVE_OVEN)
919
                        && (ledCount > 0 && ovenCount > 0)) {
920
                    LOGGER.info("Both LED and Microwave Oven already given today.");
34340 ranu 921
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
922
                }
34354 ranu 923
 
924
                if ((selectedGift == ScratchedGift.LED && ledCount > 0)) {
925
                    LOGGER.info("LED already given today.");
926
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
927
                }
34367 ranu 928
 
929
                if ((selectedGift == ScratchedGift.LED)) {
930
                    LOGGER.info("LED already given today.");
931
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
932
                }
933
 
34354 ranu 934
                if ((selectedGift == ScratchedGift.MICROWAVE_OVEN && ovenCount > 0)) {
935
                    LOGGER.info("Oven already given today.");
936
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
937
                }
34340 ranu 938
            }
939
 
34353 ranu 940
            //  Ensure only one Neckband per partner per day
34351 ranu 941
            if (selectedGift == ScratchedGift.NECK_BAND) {
942
                List<FofoOrder> fofoOrders = fofoOrderRepository.selectByFofoId(fofoId, startDateTime, endDateTime, 0, 0);
943
                List<String> invoiceNumbers = fofoOrders.stream().map(FofoOrder::getInvoiceNumber).collect(Collectors.toList());
944
                List<ScratchOffer> offers = scratchOfferRepository.selectByInvoiceNumbers(invoiceNumbers);
945
                LOGGER.info("offers for partner {}", offers);
34340 ranu 946
 
34474 aman.kumar 947
                boolean neckbandGivenToday = offers.stream().anyMatch(offer -> offer.getOfferName().equals(ScratchedGift.NECK_BAND));
34351 ranu 948
                if (neckbandGivenToday) {
949
                    LOGGER.info("Neckband already given today for partner {}", fofoId);
34340 ranu 950
                    return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
951
                }
952
            }
953
 
954
            return selectedGift;
33665 ranu 955
        }
34351 ranu 956
 
957
        return ScratchedGift.ACCESSORIES_50_PERCENT_OFF;
33665 ranu 958
    }
959
 
34340 ranu 960
 
34351 ranu 961
    public RandomCollection<ScratchedGift> createDynamicGiftSeries(Map<ScratchedGift, Long> soldGiftContMap, Double sellingPrice, int fofoId) throws ProfitMandiBusinessException {
33665 ranu 962
        int index = 0;
963
        RandomCollection<ScratchedGift> randomCollection = new RandomCollection<>();
33899 ranu 964
        PartnerType partnerType = partnerTypeChangeService.getTypeOnDate(fofoId, LocalDate.now());
965
        LOGGER.info("partnerType {}", partnerType);
966
 
33895 ranu 967
        if (partnerType.equals(PartnerType.BRONZE)) {
33899 ranu 968
            LOGGER.info("partnerType if- {}", partnerType);
33895 ranu 969
            sellingPrice = 0.0;
970
        }
33899 ranu 971
 
972
        for (int i = 0; i < PRICE_RANGE.size(); i++) {
973
            Double price = PRICE_RANGE.get(i);
34351 ranu 974
            Double nextPrice = Double.MAX_VALUE;
975
            if (i != PRICE_RANGE.size() - 1) {
976
                nextPrice = PRICE_RANGE.get(i + 1);
977
            }
33899 ranu 978
            if (sellingPrice >= price && sellingPrice < nextPrice) {
33665 ranu 979
                int divisor = PRICE_RANGE.size() - index;
33899 ranu 980
                LOGGER.info("Processing price range: {}, sellingPrice: {}", price, sellingPrice);
981
 
33665 ranu 982
                for (ScratchedGift gift : GIFT_SERIES.get(price)) {
34351 ranu 983
                    int remainingQty = GIFT_QUANTITIES.get(gift) - soldGiftContMap.getOrDefault(gift, 0L).intValue();
33899 ranu 984
                    LOGGER.info("Checking gift: {}, remainingQty: {}", gift, remainingQty);
985
 
33897 ranu 986
                    if (remainingQty > 0) {
987
                        int weight = (remainingQty > divisor) ? remainingQty / divisor : remainingQty;
34351 ranu 988
                        randomCollection.add(weight, gift);
989
                        LOGGER.info("Added gift: {}, weight: {}", gift, weight);
33665 ranu 990
                    }
991
                }
34351 ranu 992
                break; // Exit the loop once the correct price range is processed
33665 ranu 993
            }
33897 ranu 994
            index++;
33665 ranu 995
        }
33899 ranu 996
 
34351 ranu 997
        // If no gifts were added, log and handle potential issues here
33899 ranu 998
        if (randomCollection.size() == 0) {
999
            LOGGER.info("No gifts added for sellingPrice: {} in createDynamicGiftSeries", sellingPrice);
1000
        }
1001
 
34351 ranu 1002
        LOGGER.info("randomCollectionSize {}, partnerType {}, sellingPrice {}", randomCollection.size(), partnerType, sellingPrice);
33665 ranu 1003
        return randomCollection;
1004
    }
1005
 
33899 ranu 1006
 
1007
 
33665 ranu 1008
    /*static {
32960 amit.gupta 1009
        RandomCollection<ScratchedGift> map1 = new RandomCollection<ScratchedGift>().
1010
                add(100d, ScratchedGift.GIFT_BOWL);
1011
        GIFT_SERIES.put(0.0, map1);
1012
        //Map<ScratchedGift, Double> map2 = new HashMap<>();
1013
        RandomCollection<ScratchedGift> map2 = new RandomCollection<ScratchedGift>()
1014
                .add(40d, ScratchedGift.GIFT_BOWL)
1015
                .add(20d, ScratchedGift.NECK_BAND)
1016
                .add(30d, ScratchedGift.FLASKNMUG)
1017
                .add(10d, ScratchedGift.ELECTRIC_KETTLE);
1018
        GIFT_SERIES.put(10001.0, map2);
1019
        RandomCollection<ScratchedGift> map3 = new RandomCollection<ScratchedGift>()
1020
                .add(25d, ScratchedGift.GIFT_BOWL)
1021
                .add(30d, ScratchedGift.NECK_BAND)
1022
                .add(10d, ScratchedGift.SPEAKER)
1023
                .add(25d, ScratchedGift.FLASKNMUG)
1024
                .add(10d, ScratchedGift.ELECTRIC_KETTLE);
1025
        GIFT_SERIES.put(18001.0, map3);
1026
        RandomCollection<ScratchedGift> map4 = new RandomCollection<ScratchedGift>()
1027
                .add(30d, ScratchedGift.NECK_BAND)
1028
                .add(20d, ScratchedGift.SPEAKER)
1029
                .add(20d, ScratchedGift.FLASKNMUG)
1030
                .add(30d, ScratchedGift.ELECTRIC_KETTLE);
1031
        GIFT_SERIES.put(25001.0, map4);
1032
        RandomCollection<ScratchedGift> map5 = new RandomCollection<ScratchedGift>()
1033
                .add(40d, ScratchedGift.SPEAKER)
1034
                .add(60d, ScratchedGift.SMART_WATCH);
32892 ranu 1035
 
32960 amit.gupta 1036
        GIFT_SERIES.put(50001.0, map5);
33665 ranu 1037
    }*/
32892 ranu 1038
 
32960 amit.gupta 1039
 
33895 ranu 1040
    private void createSpecificPriceScratchOffer(String invoiceNumber, int customerId, int fofoId, float purchaseAmount) throws ProfitMandiBusinessException {
33899 ranu 1041
        ScratchedGift selectedGift = getSelectedGift(purchaseAmount, fofoId);
33142 ranu 1042
        List<ScratchOffer> scratchOffers = scratchOfferRepository.selectBycCustomerIdAndDate(customerId, ProfitMandiConstants.SCRATCH_OFFER_START_DATE, ProfitMandiConstants.SCRATCH_OFFER_END_DATE);
1043
        if (scratchOffers.size() == 0) {
1044
            ScratchOffer so2 = new ScratchOffer();
1045
            so2.setInvoiceNumber(invoiceNumber);
1046
            so2.setScratched(false);
1047
            so2.setCreatedTimestamp(LocalDateTime.now());
33679 ranu 1048
            so2.setExpiredTimestamp(ProfitMandiConstants.SCRATCH_OFFER_END_DATE.plusDays(1).atTime(LocalTime.MAX));
34474 aman.kumar 1049
            so2.setOfferName(String.valueOf(selectedGift));
33142 ranu 1050
            so2.setCustomerId(customerId);
1051
            so2.setUnlockedAt(LocalDateTime.now());
1052
            scratchOfferRepository.persist(so2);
1053
        }
1054
    }
32960 amit.gupta 1055
 
33142 ranu 1056
    private void createRandomScratchOffer(String invoiceNumber, int customerId) {
1057
        ScratchedGift selectedGift = getScratchedGiftRandomAccordingQuantity(customerId);
32892 ranu 1058
        List<ScratchOffer> scratchOffers = scratchOfferRepository.selectBycCustomerIdAndDate(customerId, ProfitMandiConstants.SCRATCH_OFFER_START_DATE, ProfitMandiConstants.SCRATCH_OFFER_END_DATE);
1059
        if (scratchOffers.size() == 0) {
1060
            ScratchOffer so2 = new ScratchOffer();
1061
            so2.setInvoiceNumber(invoiceNumber);
1062
            so2.setScratched(false);
1063
            so2.setCreatedTimestamp(LocalDateTime.now());
33679 ranu 1064
            so2.setExpiredTimestamp(ProfitMandiConstants.SCRATCH_OFFER_END_DATE.plusDays(1).atTime(LocalTime.MAX));
34474 aman.kumar 1065
            so2.setOfferName(String.valueOf(selectedGift));
32892 ranu 1066
            so2.setCustomerId(customerId);
1067
            so2.setUnlockedAt(LocalDateTime.now());
1068
            scratchOfferRepository.persist(so2);
1069
        }
1070
    }
1071
 
33247 ranu 1072
    private ScratchedGift getScratchedGiftRandom(int fofoId, int customerId) throws ProfitMandiBusinessException {
32218 tejbeer 1073
        Map<Integer, ScratchedGift> giftSeries = new HashMap<>();
1074
        giftSeries.put(1, ScratchedGift.MINI_CHOPPER);
1075
        giftSeries.put(2, ScratchedGift.FRUIT_JUICER);
1076
        giftSeries.put(3, ScratchedGift.STEAM_IRON);
1077
 
1078
 
32579 amit.gupta 1079
        List<FofoOrder> fofoOrders = fofoOrderRepository.selectByFofoIdBetweenCreatedTimeStamp(fofoId, ProfitMandiConstants.SCRATCH_OFFER_START_DATE.atStartOfDay(),
1080
                ProfitMandiConstants.SCRATCH_OFFER_END_DATE.atTime(Utils.MAX_TIME));
32218 tejbeer 1081
 
1082
        ScratchedGift gift = ScratchedGift.BLNT;
1083
 
1084
        Random random = new Random();
32672 amit.gupta 1085
        int rand;
32218 tejbeer 1086
        while (true) {
1087
            rand = random.nextInt(4);
1088
            if (rand != 0) break;
1089
        }
1090
        if (fofoOrders.isEmpty()) {
1091
            gift = giftSeries.get(rand);
1092
        } else {
1093
 
1094
            List<String> invoiceNumbers = fofoOrders.stream().filter(x -> x.getCancelledTimestamp() == null).map(x -> x.getInvoiceNumber()).collect(Collectors.toList());
1095
 
1096
            List<ScratchOffer> scratchOffers = scratchOfferRepository.selectByInvoiceNumbers(invoiceNumbers);
1097
            if (scratchOffers.isEmpty()) {
1098
                gift = giftSeries.get(rand);
1099
            } else {
1100
                List<ScratchOffer> bigGifts = scratchOffers.stream().filter(x -> !x.getOfferName().equals(ScratchedGift.BLNT) && !x.getOfferName().equals(ScratchedGift.EW)).collect(Collectors.toList());
1101
                if (bigGifts.size() <= 10) {
1102
                    List<Integer> scratchCustomerIds = scratchOffers.stream().map(x -> x.getCustomerId()).collect(Collectors.toList());
1103
                    if (scratchCustomerIds.contains(customerId)) {
1104
 
1105
 
1106
                        gift = ScratchedGift.BLNT;
1107
 
1108
                        LOGGER.info("gift2 {}", gift);
1109
 
1110
                    } else {
1111
 
1112
                        int miniChopper = (int) bigGifts.stream().filter(x -> x.getOfferName().equals(ScratchedGift.MINI_CHOPPER)).count();
1113
                        int fruitJuicer = (int) bigGifts.stream().filter(x -> x.getOfferName().equals(ScratchedGift.FRUIT_JUICER)).count();
1114
                        int streanIron = (int) bigGifts.stream().filter(x -> x.getOfferName().equals(ScratchedGift.STEAM_IRON)).count();
1115
 
1116
                        if (rand == 1) {
1117
                            if (miniChopper < 4) {
1118
                                LOGGER.info("miniChopper {}", miniChopper);
1119
 
1120
 
1121
                                gift = giftSeries.get(rand);
1122
                            }
1123
                        }
1124
 
1125
                        if (rand == 2) {
1126
                            if (fruitJuicer < 3) {
1127
 
1128
                                LOGGER.info("fruitJuicer {}", fruitJuicer);
1129
 
1130
                                gift = giftSeries.get(rand);
1131
                            }
1132
                        }
1133
 
1134
                        if (rand == 3) {
1135
                            if (streanIron < 3) {
1136
 
1137
                                LOGGER.info("streanIron {}", streanIron);
1138
 
1139
 
1140
                                gift = giftSeries.get(rand);
1141
 
1142
                            }
1143
                        }
1144
 
1145
                        LOGGER.info("gift4 {}", gift);
1146
                    }
1147
                }
1148
            }
1149
 
1150
 
1151
        }
32586 ranu 1152
        return gift;
32145 tejbeer 1153
    }
29515 tejbeer 1154
 
33142 ranu 1155
    private ScratchedGift getScratchedGiftRandomAccordingQuantity(int customerId) {
1156
        RandomCollection<ScratchedGift> map1 = new RandomCollection<ScratchedGift>().
1157
                add(50d, ScratchedGift.SOLOR_LAMP)
1158
                .add(100d, ScratchedGift.BLUETOOTH_SPEAKER)
1159
                .add(150d, ScratchedGift.RED_WATER_BOTTLE)
1160
                .add(200d, ScratchedGift.GIFT_BOWL)
1161
                .add(100d, ScratchedGift.EARBUDS);
1162
 
33665 ranu 1163
        ScratchedGift gift;
33142 ranu 1164
 
33665 ranu 1165
        List<ScratchOffer> lastScratchOffers = scratchOfferRepository.selectBycCustomerIdAndDate(customerId, ProfitMandiConstants.LAST_SCRATCH_OFFER_START_DATE, ProfitMandiConstants.LAST_SCRATCH_OFFER_END_DATE);
1166
 
1167
        if (lastScratchOffers.isEmpty()) {
1168
            gift = map1.next();
1169
        } else {
1170
            gift = ScratchedGift.RED_WATER_BOTTLE;
1171
            LOGGER.info("RED_WATER_BOTTLE {}", gift);
33142 ranu 1172
        }
1173
        return gift;
1174
    }
1175
 
32145 tejbeer 1176
    private HygieneData createAndGetHygieneData(int id, int fofoId) {
1177
        HygieneData hygieneData = new HygieneData();
1178
        hygieneData.setOrderId(id);
1179
        hygieneData.setFofoId(fofoId);
1180
        hygieneData.setCreatedTimestamp(LocalDateTime.now());
1181
        hygieneDataRepository.persist(hygieneData);
25640 tejbeer 1182
 
32145 tejbeer 1183
        return hygieneData;
1184
    }
25640 tejbeer 1185
 
33665 ranu 1186
 
32145 tejbeer 1187
    @Override
1188
    public String getInvoiceNumber(int fofoId, String fofoStoreCode) {
1189
        InvoiceNumberGenerationSequence invoiceNumberGenerationSequence = null;
1190
        try {
1191
            invoiceNumberGenerationSequence = invoiceNumberGenerationSequenceRepository.selectByFofoId(fofoId);
1192
            invoiceNumberGenerationSequence.setSequence(invoiceNumberGenerationSequence.getSequence() + 1);
1193
        } catch (ProfitMandiBusinessException profitMandiBusinessException) {
1194
            invoiceNumberGenerationSequence = new InvoiceNumberGenerationSequence();
1195
            invoiceNumberGenerationSequence.setFofoId(fofoId);
1196
            invoiceNumberGenerationSequence.setPrefix(fofoStoreCode);
1197
            invoiceNumberGenerationSequence.setSequence(1);
1198
        }
1199
        invoiceNumberGenerationSequenceRepository.persist(invoiceNumberGenerationSequence);
1200
        return invoiceNumberGenerationSequence.getPrefix() + "/" + invoiceNumberGenerationSequence.getSequence();
1201
    }
24275 amit.gupta 1202
 
32145 tejbeer 1203
    private String getSecurityDepositNumber(int fofoId, String fofoStoreCode) {
1204
        InvoiceNumberGenerationSequence invoiceNumberGenerationSequence = null;
1205
        try {
1206
            invoiceNumberGenerationSequence = invoiceNumberGenerationSequenceRepository.selectByFofoId(fofoId);
1207
            invoiceNumberGenerationSequence.setChallanNumberSequence(invoiceNumberGenerationSequence.getChallanNumberSequence() + 1);
1208
        } catch (ProfitMandiBusinessException profitMandiBusinessException) {
1209
            invoiceNumberGenerationSequence = new InvoiceNumberGenerationSequence();
1210
            invoiceNumberGenerationSequence.setFofoId(fofoId);
1211
            invoiceNumberGenerationSequence.setPrefix(fofoStoreCode);
1212
            invoiceNumberGenerationSequence.setChallanNumberSequence(1);
1213
        }
1214
        invoiceNumberGenerationSequenceRepository.persist(invoiceNumberGenerationSequence);
1215
        return invoiceNumberGenerationSequence.getPrefix() + "/SEC" + invoiceNumberGenerationSequence.getChallanNumberSequence();
1216
    }
24226 amit.gupta 1217
 
32145 tejbeer 1218
    private Set<String> serialNumberDetailsToSerialNumbers(Set<SerialNumberDetail> serialNumberDetails) {
1219
        Set<String> serialNumbers = new HashSet<>();
1220
        for (SerialNumberDetail serialNumberDetail : serialNumberDetails) {
1221
            if (serialNumberDetail.getSerialNumber() != null && !serialNumberDetail.getSerialNumber().isEmpty()) {
1222
                serialNumbers.add(serialNumberDetail.getSerialNumber());
1223
            }
1224
        }
1225
        return serialNumbers;
1226
    }
23650 amit.gupta 1227
 
32145 tejbeer 1228
    @Override
1229
    public InvoicePdfModel getInvoicePdfModel(int orderId) throws ProfitMandiBusinessException {
1230
        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(orderId);
1231
        return this.getInvoicePdfModel(fofoOrder);
1232
    }
23650 amit.gupta 1233
 
32145 tejbeer 1234
    @Override
1235
    @Cacheable(value = "order.dummymodel", cacheManager = "oneDayCacheManager")
1236
    public InvoicePdfModel getDummyPdfModel(String serialNumber) throws ProfitMandiBusinessException {
1237
        List<WarehouseInventoryItem> warehouseInventoryItems = warehouseInventoryItemRepository.selectWarehouseInventoryItemBySerailNumbers(Arrays.asList(serialNumber));
1238
        if (warehouseInventoryItems.size() > 0) {
1239
            WarehouseInventoryItem warehouseInventoryItem = warehouseInventoryItems.get(0);
1240
            int currentQuantity = warehouseInventoryItems.get(0).getCurrentQuantity();
1241
            if (currentQuantity > 0) {
1242
                throw new ProfitMandiBusinessException("Serial Number", serialNumber, "Serial Number exist in our warehouse");
1243
            } else {
1244
                try {
1245
                    InventoryItem inventoryItem = inventoryItemRepository.selectBySerialNumber(serialNumber);
1246
                    if (inventoryItem.getGoodQuantity() > 0) {
1247
                        throw new ProfitMandiBusinessException("Serial Number", serialNumber, "Serial Number is not yet billed by the partner");
1248
                    } else {
1249
                        List<ScanRecord> scanRecords = scanRecordRepository.selectByInventoryItemId(inventoryItem.getId());
1250
                        Optional<ScanRecord> scanRecord = scanRecords.stream().filter(x -> x.getOrderId() != 0).findFirst();
1251
                        if (scanRecord.isPresent()) {
1252
                            FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(scanRecord.get().getOrderId());
1253
                            orderIdsConsumed.add(fofoOrder.getId());
1254
                            return this.getInvoicePdfModel(fofoOrder);
1255
                        } else {
1256
                            throw new ProfitMandiBusinessException("Serial Number", serialNumber, "Serial Number returned by partner, but in transit");
1257
                        }
1258
                    }
1259
                } catch (Exception e) {
1260
                    int itemId = warehouseInventoryItem.getItemId();
1261
                    if (serialNumberOrderIdMap.containsKey(serialNumber)) {
1262
                        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(serialNumberOrderIdMap.get(serialNumber));
1263
                        InvoicePdfModel pdfModel = this.getInvoicePdfModel(fofoOrder.getId());
1264
                        this.modifyDummyModel(fofoOrder, pdfModel, itemId, serialNumber);
1265
                        return pdfModel;
1266
                    }
1267
                    // Map this serialNumber for dummy billing
1268
                    LocalDateTime grnDate = warehouseInventoryItem.getCreated();
1269
                    Random random = new Random();
1270
                    int randomDays = random.ints(2, 15).findFirst().getAsInt();
1271
                    LocalDateTime saleDate = grnDate.plusDays(randomDays);
1272
                    if (saleDate.isAfter(LocalDate.now().atStartOfDay())) {
1273
                        saleDate = LocalDateTime.now().minusDays(2);
1274
                    }
1275
                    Random offsetRandom = new Random();
1276
                    int offset = offsetRandom.ints(2, 100).findFirst().getAsInt();
1277
                    FofoOrder fofoOrder = fofoOrderRepository.selectFirstOrderAfterDate(saleDate, offset);
1278
                    while (orderIdsConsumed.contains(fofoOrder.getId())) {
1279
                        Random offsetRandom2 = new Random();
1280
                        int offset2 = offsetRandom2.ints(2, 100).findFirst().getAsInt();
1281
                        FofoOrder fofoOrder2 = fofoOrderRepository.selectFirstOrderAfterDate(saleDate, offset2);
1282
                        if (fofoOrder2 != null) {
1283
                            fofoOrder = fofoOrder2;
1284
                        }
1285
                    }
1286
                    InvoicePdfModel pdfModel = this.getInvoicePdfModel(fofoOrder.getId());
1287
                    orderIdsConsumed.add(fofoOrder.getId());
1288
                    this.modifyDummyModel(fofoOrder, pdfModel, itemId, serialNumber);
1289
                    return pdfModel;
27516 amit.gupta 1290
 
32145 tejbeer 1291
                }
1292
            }
1293
        } else {
1294
            throw new ProfitMandiBusinessException("Serial Number", serialNumber, "Serial Number does not exist in our warehouse");
1295
        }
1296
    }
27516 amit.gupta 1297
 
33665 ranu 1298
    void modifyDummyModel(FofoOrder fofoOrder, InvoicePdfModel pdfModel, int itemId, String serialNumber) throws
1299
            ProfitMandiBusinessException {
28166 tejbeer 1300
 
32145 tejbeer 1301
        int retailerAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(fofoOrder.getFofoId());
27516 amit.gupta 1302
 
32145 tejbeer 1303
        Address retailerAddress = addressRepository.selectById(retailerAddressId);
1304
        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
27516 amit.gupta 1305
 
32145 tejbeer 1306
        CustomerAddress customerAddress = customer.getCustomerAddress().stream().filter(x -> x.getId() == fofoOrder.getCustomerAddressId()).findFirst().get();
27516 amit.gupta 1307
 
32145 tejbeer 1308
        Integer stateId = null;
1309
        if (customerAddress.getState().equals(retailerAddress.getState())) {
1310
            try {
1311
                // stateId =
1312
                // Long.valueOf(Utils.getStateInfo(customerAddress.getState()).getId()).intValue();
30527 tejbeer 1313
 
32145 tejbeer 1314
                stateId = Long.valueOf(stateRepository.selectByName(customerAddress.getState()).getId()).intValue();
1315
            } catch (Exception e) {
1316
                LOGGER.error("Unable to get state rates");
1317
            }
1318
        }
1319
        CustomOrderItem cli = pdfModel.getOrderItems().stream().findFirst().get();
1320
        List<FofoOrderItem> fofoOrderItems = Arrays.asList(this.getDummyFofoOrderItem(itemId, fofoOrder.getId(), serialNumber, stateId));
1321
        pdfModel.setPaymentOptions(pdfModel.getPaymentOptions().stream().limit(1).collect(Collectors.toList()));
1322
        CustomPaymentOption paymentOption = pdfModel.getPaymentOptions().get(0);
1323
        paymentOption.setAmount(fofoOrderItems.get(0).getMop());
33298 amit.gupta 1324
        List<CustomOrderItem> customerFofoOrderItems = new ArrayList<>();
32145 tejbeer 1325
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1326
            CustomOrderItem customFofoOrderItem = new CustomOrderItem();
1327
            float totalTaxRate = fofoOrderItem.getIgstRate() + fofoOrderItem.getSgstRate() + fofoOrderItem.getCgstRate();
1328
            float taxableSellingPrice = fofoOrderItem.getSellingPrice() / (1 + totalTaxRate / 100);
1329
            float taxableDiscountPrice = fofoOrderItem.getDiscount() / (1 + totalTaxRate / 100);
27516 amit.gupta 1330
 
32145 tejbeer 1331
            customFofoOrderItem.setAmount(fofoOrderItem.getQuantity() * (taxableSellingPrice - taxableDiscountPrice));
1332
            customFofoOrderItem.setDescription(fofoOrderItem.getBrand() + " " + fofoOrderItem.getModelName() + " " + fofoOrderItem.getModelNumber() + "-" + fofoOrderItem.getColor());
1333
            Set<String> serialNumbers = this.toSerialNumbers(fofoOrderItem.getFofoLineItems());
1334
            // LOGGER.info("serialNumbers {}", serialNumbers);
1335
            // LOGGER.info("serialNumbers is empty {}", serialNumbers.isEmpty());
1336
            if (!serialNumbers.isEmpty()) {
1337
                customFofoOrderItem.setDescription(
1338
                        customFofoOrderItem.getDescription() + "\n IMEIS - " + String.join(", ", serialNumbers));
1339
            }
1340
            customFofoOrderItem.setRate(taxableSellingPrice);
1341
            customFofoOrderItem.setDiscount(taxableDiscountPrice);
1342
            customFofoOrderItem.setQuantity(fofoOrderItem.getQuantity());
1343
            customFofoOrderItem.setNetAmount(
1344
                    (fofoOrderItem.getSellingPrice() - fofoOrderItem.getDiscount()) * fofoOrderItem.getQuantity());
1345
            float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
1346
            float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
1347
            float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
1348
            customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
1349
            customFofoOrderItem.setIgstAmount(igstAmount);
1350
            customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
1351
            customFofoOrderItem.setCgstAmount(cgstAmount);
1352
            customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
1353
            customFofoOrderItem.setSgstAmount(sgstAmount);
1354
            customFofoOrderItem.setHsnCode(fofoOrderItem.getHsnCode());
1355
            customerFofoOrderItems.add(customFofoOrderItem);
1356
        }
1357
        pdfModel.setTotalAmount(paymentOption.getAmount());
1358
        pdfModel.setOrderItems(customerFofoOrderItems);
28166 tejbeer 1359
 
32145 tejbeer 1360
    }
27516 amit.gupta 1361
 
35034 amit 1362
    @Override
1363
    public InvoicePdfModel getInvoicePdfModel(FofoOrder fofoOrder) throws ProfitMandiBusinessException {
23650 amit.gupta 1364
 
32145 tejbeer 1365
        List<PaymentOptionTransaction> paymentOptionTransactions = paymentOptionTransactionRepository.selectByReferenceIdAndTypes(fofoOrder.getId(), Arrays.asList(PaymentOptionReferenceType.ORDER, PaymentOptionReferenceType.INSURANCE));
23650 amit.gupta 1366
 
32145 tejbeer 1367
        List<CustomPaymentOption> paymentOptions = new ArrayList<>();
23552 amit.gupta 1368
 
32145 tejbeer 1369
        InvoicePdfModel pdfModel = new InvoicePdfModel();
33795 ranu 1370
 
1371
 
1372
        List<FofoOrderItem> fofoOrderItems = this.getByOrderId(fofoOrder.getId());
1373
 
1374
        double upgradePartnerDiscount = 0;
1375
 
35055 ranu 1376
       /* for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
33795 ranu 1377
 
1378
            Set<String> serialNumbers = this.toSerialNumbers(fofoOrderItem.getFofoLineItems());
1379
            for (String serialNumber : serialNumbers) {
1380
                UpgradeOffer upgradeOffer = upgradeOfferRepository.selectBySerialNumber(serialNumber);
1381
                if (upgradeOffer != null) {
1382
                    CustomerOfferItem customerOfferItem = customerOfferItemRepository.selectById(upgradeOffer.getCustomerOfferItemId());
1383
                    upgradePartnerDiscount += customerOfferItem.getDealerPayout();
1384
                }
1385
            }
35055 ranu 1386
        }*/
33795 ranu 1387
 
1388
        boolean hasSamsungUpgrade = paymentOptionTransactions.stream()
1389
                .anyMatch(transaction ->
1390
                        "SAMSUNG UPGRADE".equals(paymentOptionRepository
1391
                                .selectById(transaction.getPaymentOptionId())
1392
                                .getName()));
1393
 
1394
        LOGGER.info("paymentOptionTransactions - {}", paymentOptionTransactions);
1395
        LOGGER.info("hasSamsungUpgrade - {}", hasSamsungUpgrade);
1396
 
1397
        double cashDiscount = paymentOptionTransactions.stream()
1398
                .filter(x -> "CASH DISCOUNT".equals(paymentOptionRepository.selectById(x.getPaymentOptionId()).getName())).mapToDouble(x -> x.getAmount()).findFirst().orElse(0);
1399
 
1400
        LOGGER.info("cashDiscount - {}", cashDiscount);
1401
 
32145 tejbeer 1402
        for (PaymentOptionTransaction paymentOptionTransaction : paymentOptionTransactions) {
33795 ranu 1403
            String paymentOptionName = paymentOptionRepository.selectById(paymentOptionTransaction.getPaymentOptionId()).getName();
1404
 
32145 tejbeer 1405
            CustomPaymentOption cpi = new CustomPaymentOption();
33795 ranu 1406
            LOGGER.info("paymentOptionName {}", paymentOptionName);
1407
 
1408
            float amountToSet = paymentOptionTransaction.getAmount();
1409
 
1410
            if ("SAMSUNG UPGRADE".equals(paymentOptionName) && hasSamsungUpgrade) {
1411
                if (cashDiscount > upgradePartnerDiscount) {
1412
                    amountToSet += (float) upgradePartnerDiscount;
1413
                } else {
1414
                    amountToSet += (float) cashDiscount;
1415
                }
1416
 
1417
            } else if ("CASH".equals(paymentOptionName) && !hasSamsungUpgrade) {
1418
                amountToSet += ((float) cashDiscount - (float) upgradePartnerDiscount);
1419
 
1420
            } else if ("CASH".equals(paymentOptionName) && hasSamsungUpgrade && (cashDiscount > upgradePartnerDiscount)) {
1421
                amountToSet += ((float) cashDiscount - (float) upgradePartnerDiscount);
1422
 
1423
            }
1424
 
1425
            cpi.setAmount(amountToSet);
1426
            cpi.setPaymentOption(paymentOptionName);
1427
 
32145 tejbeer 1428
            paymentOptions.add(cpi);
1429
        }
24215 amit.gupta 1430
 
33795 ranu 1431
 
36126 amit 1432
        pdfModel.setTitle("Tax Invoice");
32145 tejbeer 1433
        Optional<FofoOrderItem> fofoOrderItemOptional = fofoOrderItems.stream().findAny();
1434
        if (fofoOrderItemOptional.isPresent() && fofoOrderItemOptional.get().equals("NOGST")) {
1435
            pdfModel.setTitle("Security Deposit Receipt");
1436
        }
1437
        pdfModel.setPaymentOptions(paymentOptions);
1438
        pdfModel.setAuther("SmartDukaan");
1439
        pdfModel.setInvoiceDate(FormattingUtils.formatDate(fofoOrder.getCreateTimestamp()));
23650 amit.gupta 1440
 
32145 tejbeer 1441
        // insurance calculation
1442
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());
33298 amit.gupta 1443
        List<CustomInsurancePolicy> customInsurancePolicies = new ArrayList<>();
32145 tejbeer 1444
        final float totalInsuranceTaxRate = 18;
1445
        for (InsurancePolicy insurancePolicy : insurancePolicies) {
1446
            float taxableInsurancePrice = insurancePolicy.getSaleAmount() / (1 + totalInsuranceTaxRate / 100);
1447
            CustomInsurancePolicy customInsurancePolicy = new CustomInsurancePolicy();
1448
            customInsurancePolicy.setDescription(insurancePolicy.getPolicyPlan() + " for Device #" + insurancePolicy.getSerialNumber() + "\n Plan Reference - " + insurancePolicy.getPolicyNumber());
1449
            customInsurancePolicy.setHsnCode("998716");
1450
            customInsurancePolicy.setRate(taxableInsurancePrice);
1451
            customInsurancePolicy.setIgstRate(18);
1452
            customInsurancePolicy.setIgstAmount(taxableInsurancePrice * 18 / 100);
1453
            customInsurancePolicy.setCgstRate(9);
1454
            customInsurancePolicy.setCgstAmount(taxableInsurancePrice * 9 / 100);
1455
            customInsurancePolicy.setSgstRate(9);
1456
            customInsurancePolicy.setSgstAmount(taxableInsurancePrice * 9 / 100);
1457
            customInsurancePolicy.setNetAmount(insurancePolicy.getSaleAmount());
1458
            customInsurancePolicies.add(customInsurancePolicy);
1459
        }
1460
        pdfModel.setInsurancePolicies(customInsurancePolicies);
24275 amit.gupta 1461
 
32145 tejbeer 1462
        Retailer retailer = retailerRepository.selectById(fofoOrder.getFofoId());
1463
        User user = userRepository.selectById(userAccountRepository.selectUserIdByRetailerId(retailer.getId()));
35896 amit 1464
        FofoStore fofoStoreForGst = fofoStoreRepository.selectByRetailerId(retailer.getId());
32145 tejbeer 1465
        CustomRetailer customRetailer = new CustomRetailer();
1466
        customRetailer.setBusinessName(retailer.getName());
1467
        customRetailer.setMobileNumber(user.getMobileNumber());
35896 amit 1468
        customRetailer.setGstNumber(fofoStoreForGst != null ? fofoStoreForGst.getGstNumber() : null);
32145 tejbeer 1469
        Address retailerAddress = addressRepository.selectById(retailerRegisteredAddressRepository.selectAddressIdByRetailerId(retailer.getId()));
1470
        customRetailer.setAddress(this.createCustomAddress(retailerAddress));
1471
        pdfModel.setRetailer(customRetailer);
23650 amit.gupta 1472
 
33089 amit.gupta 1473
        pdfModel.setCustomer(getCustomCustomer(fofoOrder, customRetailer.getAddress()));
1474
        pdfModel.setInvoiceNumber(fofoOrder.getInvoiceNumber());
1475
        pdfModel.setTotalAmount(fofoOrder.getTotalAmount());
1476
 
1477
 
35695 amit 1478
        List<CustomOrderItem> regularFofoItems = new ArrayList<>();
1479
        List<CustomOrderItem> marginSchemeFofoItems = new ArrayList<>();
1480
        boolean hasMarginSchemeItems = false;
32145 tejbeer 1481
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1482
            float discount = fofoOrderItem.getDiscount();
1483
            CustomOrderItem customFofoOrderItem = new CustomOrderItem();
1484
            float totalTaxRate = fofoOrderItem.getIgstRate() + fofoOrderItem.getSgstRate() + fofoOrderItem.getCgstRate();
23650 amit.gupta 1485
 
32145 tejbeer 1486
            customFofoOrderItem.setDescription(fofoOrderItem.getBrand() + " " + fofoOrderItem.getModelName() + " " + fofoOrderItem.getModelNumber() + "-" + fofoOrderItem.getColor());
1487
            Set<String> serialNumbers = this.toSerialNumbers(fofoOrderItem.getFofoLineItems());
32816 ranu 1488
            List<FofoNonSerializeSerial> nonSerializeSerials = fofoNonSerializeSerialRepository.selectByItemIdAndOrderId(fofoOrderItem.getId());
1489
            List<String> customSerialNumbers = nonSerializeSerials.stream().map(FofoNonSerializeSerial::getSerialNumber).collect(Collectors.toList());
1490
            LOGGER.info("nonSerializeSerials {}", nonSerializeSerials);
32145 tejbeer 1491
            if (!serialNumbers.isEmpty()) {
1492
                customFofoOrderItem.setDescription(
1493
                        customFofoOrderItem.getDescription() + "\n IMEIS - " + String.join(", ", serialNumbers));
1494
            }
32816 ranu 1495
            if (!customSerialNumbers.isEmpty()) {
1496
                customFofoOrderItem.setDescription(
1497
                        customFofoOrderItem.getDescription() + "\n SerialNumber - " + String.join(", ", customSerialNumbers));
1498
            }
32145 tejbeer 1499
            customFofoOrderItem.setQuantity(fofoOrderItem.getQuantity());
1500
            customFofoOrderItem.setHsnCode(fofoOrderItem.getHsnCode());
35695 amit 1501
 
1502
            // Check if this is a margin scheme item
1503
            boolean isMarginItem = false;
1504
            try {
1505
                Item item = itemRepository.selectById(fofoOrderItem.getItemId());
1506
                Category category = categoryRepository.selectById(item.getCategoryId());
1507
                isMarginItem = category.isMarginOnly() && !serialNumbers.isEmpty();
1508
            } catch (Exception e) {
1509
                LOGGER.warn("Could not check margin scheme for fofo order item {}", fofoOrderItem.getId(), e);
1510
            }
1511
 
1512
            if (isMarginItem) {
1513
                // Margin Scheme: GST on margin only
1514
                // Purchase price = what FOFO paid (from fofo.inventory_item.unitPrice)
1515
                float purchasePrice = getFofoPurchasePrice(serialNumbers.iterator().next(), fofoOrder.getFofoId());
1516
                float sellingPrice = fofoOrderItem.getSellingPrice();
1517
                float margin = Math.max(0, sellingPrice - purchasePrice);
1518
                float taxableMargin = margin / (1 + totalTaxRate / 100);
1519
 
1520
                customFofoOrderItem.setMarginScheme(true);
1521
                customFofoOrderItem.setPurchasePrice(purchasePrice);
1522
                customFofoOrderItem.setSellingPrice(sellingPrice);
1523
                customFofoOrderItem.setMargin(margin);
1524
                customFofoOrderItem.setRate(sellingPrice);
1525
                customFofoOrderItem.setDiscount(0);
1526
                customFofoOrderItem.setAmount(taxableMargin * fofoOrderItem.getQuantity());
1527
                customFofoOrderItem.setNetAmount(fofoOrderItem.getSellingPrice() * fofoOrderItem.getQuantity());
1528
 
1529
                float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
1530
                float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
1531
                float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
1532
                customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
1533
                customFofoOrderItem.setIgstAmount(igstAmount);
1534
                customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
1535
                customFofoOrderItem.setCgstAmount(cgstAmount);
1536
                customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
1537
                customFofoOrderItem.setSgstAmount(sgstAmount);
1538
 
1539
                marginSchemeFofoItems.add(customFofoOrderItem);
1540
                hasMarginSchemeItems = true;
1541
            } else {
1542
                // Regular: GST on full selling price
1543
                float taxableSellingPrice = (fofoOrderItem.getSellingPrice() + discount) / (1 + totalTaxRate / 100);
1544
                float taxableDiscountPrice = discount / (1 + totalTaxRate / 100);
1545
 
1546
                customFofoOrderItem.setAmount(fofoOrderItem.getQuantity() * (taxableSellingPrice - taxableDiscountPrice));
1547
                customFofoOrderItem.setRate(taxableSellingPrice);
1548
                customFofoOrderItem.setDiscount(taxableDiscountPrice);
1549
                customFofoOrderItem.setNetAmount(fofoOrderItem.getSellingPrice() * fofoOrderItem.getQuantity());
1550
 
1551
                float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
1552
                float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
1553
                float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
1554
                customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
1555
                customFofoOrderItem.setIgstAmount(igstAmount);
1556
                customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
1557
                customFofoOrderItem.setCgstAmount(cgstAmount);
1558
                customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
1559
                customFofoOrderItem.setSgstAmount(sgstAmount);
1560
 
1561
                regularFofoItems.add(customFofoOrderItem);
1562
            }
32145 tejbeer 1563
        }
35695 amit 1564
        // Regular items first, then margin scheme items
1565
        List<CustomOrderItem> customerFofoOrderItems = new ArrayList<>(regularFofoItems);
1566
        customerFofoOrderItems.addAll(marginSchemeFofoItems);
32145 tejbeer 1567
        pdfModel.setOrderItems(customerFofoOrderItems);
35695 amit 1568
        pdfModel.setHasMarginSchemeItems(hasMarginSchemeItems);
1569
        if (hasMarginSchemeItems) {
1570
            List<String> declarations = new ArrayList<>();
1571
            declarations.add("Items marked under Margin Scheme are taxed under Rule 32(5) of CGST Rules, 2017.");
1572
            declarations.add("GST is charged on the margin (Selling Price - Purchase Price) and not on the full value of supply.");
1573
            declarations.add("Input Tax Credit is not available on margin scheme items.");
1574
            pdfModel.setMarginSchemeDeclarations(declarations);
1575
        }
32627 ranu 1576
        String customerAddressStateCode = "";
32145 tejbeer 1577
        String partnerAddressStateCode = stateRepository.selectByName(pdfModel.getRetailer().getAddress().getState()).getCode();
32627 ranu 1578
        if (pdfModel.getCustomer() != null && pdfModel.getCustomer().getAddress() != null &&
1579
                pdfModel.getCustomer().getAddress().getState() != null &&
1580
                !pdfModel.getCustomer().getAddress().getState().trim().isEmpty()) {
1581
            customerAddressStateCode = stateRepository.selectByName(pdfModel.getCustomer().getAddress().getState()).getCode();
1582
        }
1583
 
32145 tejbeer 1584
        pdfModel.setPartnerAddressStateCode(partnerAddressStateCode);
32627 ranu 1585
        if (!customerAddressStateCode.equals("")) {
1586
            pdfModel.setCustomerAddressStateCode(customerAddressStateCode);
1587
        }
32145 tejbeer 1588
        pdfModel.setCancelled(fofoOrder.getCancelledTimestamp() != null);
1589
        List<String> tncs = new ArrayList<>();
34999 amit 1590
        tncs.add("I agree that goods received are in good working condition.");
1591
        tncs.add("Goods once sold cannot be exchanged or taken back.");
32145 tejbeer 1592
        tncs.add("Warranty for the goods received by me is the responsibility of the manufacturer only.");
1593
        if (pdfModel.getInsurancePolicies() != null && pdfModel.getInsurancePolicies().size() > 0) {
35000 amit 1594
            tncs.add("Extended Warranty/ Damage Protection related issues are to be handled directly by the respective providers.");
32145 tejbeer 1595
        }
1596
        pdfModel.setTncs(tncs);
1597
        return pdfModel;
23650 amit.gupta 1598
 
32145 tejbeer 1599
    }
23650 amit.gupta 1600
 
35695 amit 1601
    private float getFofoPurchasePrice(String serialNumber, int fofoId) {
1602
        try {
1603
            InventoryItem fofoInventoryItem = inventoryItemRepository.selectBySerialNumberFofoId(serialNumber, fofoId);
1604
            if (fofoInventoryItem != null) {
1605
                return fofoInventoryItem.getUnitPrice();
1606
            }
1607
        } catch (Exception e) {
1608
            LOGGER.error("Could not fetch FOFO purchase price for serial: {}, fofoId: {}", serialNumber, fofoId, e);
1609
        }
1610
        return 0;
1611
    }
1612
 
33665 ranu 1613
    private CustomCustomer getCustomCustomer(FofoOrder fofoOrder, CustomAddress retailerAddress) throws
1614
            ProfitMandiBusinessException {
32145 tejbeer 1615
        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
1616
        CustomCustomer customCustomer = new CustomCustomer();
1617
        customCustomer.setFirstName(customer.getFirstName());
1618
        customCustomer.setLastName(customer.getLastName());
1619
        customCustomer.setEmailId(customer.getEmailId());
1620
        customCustomer.setMobileNumber(customer.getMobileNumber());
1621
        customCustomer.setGstNumber(fofoOrder.getCustomerGstNumber());
32627 ranu 1622
        if (fofoOrder.getCustomerAddressId() != 0) {
1623
            CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
1624
            customCustomer.setAddress(this.createCustomAddress(customerAddress));
1625
        } else {
33089 amit.gupta 1626
 
1627
            customCustomer.setAddress(this.createCustomAddressWithoutId(customCustomer, retailerAddress));
32627 ranu 1628
        }
32145 tejbeer 1629
        return customCustomer;
32627 ranu 1630
 
32145 tejbeer 1631
    }
23655 amit.gupta 1632
 
32145 tejbeer 1633
    @Override
1634
    public InvoicePdfModel getInvoicePdfModel(int fofoId, int orderId) throws ProfitMandiBusinessException {
1635
        FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndOrderId(fofoId, orderId);
1636
        return this.getInvoicePdfModel(fofoOrder);
1637
    }
23650 amit.gupta 1638
 
32145 tejbeer 1639
    public String getBillingAddress(CustomerAddress customerAddress) {
1640
        StringBuilder address = new StringBuilder();
1641
        if ((customerAddress.getLine1() != null) && (!customerAddress.getLine1().isEmpty())) {
1642
            address.append(customerAddress.getLine1());
1643
            address.append(", ");
1644
        }
22859 ashik.ali 1645
 
32145 tejbeer 1646
        if ((customerAddress.getLine2() != null) && (!customerAddress.getLine2().isEmpty())) {
1647
            address.append(customerAddress.getLine2());
1648
            address.append(", ");
1649
        }
22859 ashik.ali 1650
 
32145 tejbeer 1651
        if ((customerAddress.getLandmark() != null) && (!customerAddress.getLandmark().isEmpty())) {
1652
            address.append(customerAddress.getLandmark());
1653
            address.append(", ");
1654
        }
22859 ashik.ali 1655
 
32145 tejbeer 1656
        if ((customerAddress.getCity() != null) && (!customerAddress.getCity().isEmpty())) {
1657
            address.append(customerAddress.getCity());
1658
            address.append(", ");
1659
        }
22859 ashik.ali 1660
 
32145 tejbeer 1661
        if ((customerAddress.getState() != null) && (!customerAddress.getState().isEmpty())) {
1662
            address.append(customerAddress.getState());
1663
        }
22859 ashik.ali 1664
 
32145 tejbeer 1665
        if ((customerAddress.getPinCode() != null) && (!customerAddress.getPinCode().isEmpty())) {
1666
            address.append("- ");
1667
            address.append(customerAddress.getPinCode());
1668
        }
22859 ashik.ali 1669
 
32145 tejbeer 1670
        return address.toString();
1671
    }
23650 amit.gupta 1672
 
32145 tejbeer 1673
    @Override
1674
    public List<CartFofo> cartCheckout(String cartJson) throws ProfitMandiBusinessException {
1675
        try {
1676
            JSONObject cartObject = new JSONObject(cartJson);
1677
            Iterator<?> keys = cartObject.keys();
23650 amit.gupta 1678
 
32145 tejbeer 1679
            Set<Integer> itemIds = new HashSet<>();
1680
            List<CartFofo> cartItems = new ArrayList<CartFofo>();
23650 amit.gupta 1681
 
32145 tejbeer 1682
            while (keys.hasNext()) {
1683
                String key = (String) keys.next();
1684
                if (cartObject.get(key) instanceof JSONObject) {
1685
                    LOGGER.info(cartObject.get(key).toString());
1686
                }
1687
                CartFofo cf = new CartFofo();
1688
                cf.setItemId(cartObject.getJSONObject(key).getInt("itemId"));
1689
                cf.setQuantity(cartObject.getJSONObject(key).getInt("quantity"));
1690
                if (cartObject.getJSONObject(key).has("poId")) {
23650 amit.gupta 1691
 
32145 tejbeer 1692
                    cf.setPoId(cartObject.getJSONObject(key).getInt("poId"));
1693
                    cf.setPoItemId(cartObject.getJSONObject(key).getInt("poItemId"));
1694
                }
1695
                if (cf.getQuantity() <= 0) {
1696
                    continue;
1697
                }
1698
                cartItems.add(cf);
1699
                itemIds.add(cartObject.getJSONObject(key).getInt("itemId"));
1700
            }
1701
            Map<Integer, Item> itemMap = new HashMap<Integer, Item>();
1702
            if (itemIds.size() > 0) {
1703
                List<Item> items = itemRepository.selectByIds(itemIds);
1704
                for (Item i : items) {
1705
                    itemMap.put(i.getId(), i);
1706
                }
23650 amit.gupta 1707
 
32145 tejbeer 1708
            }
1709
            for (CartFofo cf : cartItems) {
1710
                Item i = itemMap.get(cf.getItemId());
1711
                if (i == null) {
1712
                    continue;
1713
                }
1714
                cf.setDisplayName(getValidName(i.getBrand()) + " " + getValidName(i.getModelName()) + " " + getValidName(i.getModelNumber()) + " " + getValidName(i.getColor()).replaceAll("\\s+", " "));
1715
                cf.setItemType(i.getType());
1716
            }
1717
            return cartItems;
1718
        } catch (Exception e) {
1719
            LOGGER.error("Unable to Prepare cart to place order...", e);
1720
            throw new ProfitMandiBusinessException("cartData", cartJson, "FFORDR_1006");
1721
        }
1722
    }
23650 amit.gupta 1723
 
32145 tejbeer 1724
    @Override
33665 ranu 1725
    public Map<String, Object> getSaleHistory(int fofoId, SearchType searchType, String searchValue, LocalDateTime
1726
            startDate, LocalDateTime endDate, int offset, int limit) throws ProfitMandiBusinessException {
32145 tejbeer 1727
        long countItems = 0;
1728
        List<FofoOrder> fofoOrders = new ArrayList<>();
23650 amit.gupta 1729
 
32145 tejbeer 1730
        if (searchType == SearchType.CUSTOMER_MOBILE_NUMBER && !searchValue.isEmpty()) {
1731
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerMobileNumber(fofoId, searchValue, null, null, offset, limit);
1732
            countItems = fofoOrderRepository.selectCountByCustomerMobileNumber(fofoId, searchValue, null, null);
1733
        } else if (searchType == SearchType.CUSTOMER_NAME && !searchValue.isEmpty()) {
1734
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerName(fofoId, searchValue, null, null, offset, limit);
1735
            countItems = fofoOrderRepository.selectCountByCustomerName(fofoId, searchValue, null, null);
1736
        } else if (searchType == SearchType.IMEI && !searchValue.isEmpty()) {
1737
            fofoOrders = fofoOrderRepository.selectByFofoIdAndSerialNumber(fofoId, searchValue, null, null, offset, limit);
1738
            countItems = fofoOrderRepository.selectCountBySerialNumber(fofoId, searchValue, null, null);
1739
        } else if (searchType == SearchType.ITEM_NAME && !searchValue.isEmpty()) {
1740
            fofoOrders = fofoOrderRepository.selectByFofoIdAndItemName(fofoId, searchValue, null, null, offset, limit);
1741
            countItems = fofoOrderRepository.selectCountByItemName(fofoId, searchValue, null, null);
1742
        } else if (searchType == SearchType.INVOICE_NUMBER && !searchValue.isEmpty()) {
1743
            fofoOrders = Arrays.asList(fofoOrderRepository.selectByFofoIdAndInvoiceNumber(fofoId, searchValue));
1744
            countItems = fofoOrders.size();
1745
        } else if (searchType == SearchType.DATE_RANGE) {
1746
            fofoOrders = fofoOrderRepository.selectByFofoId(fofoId, startDate, endDate, offset, limit);
1747
            countItems = fofoOrderRepository.selectCountByFofoId(fofoId, startDate, endDate);
1748
        }
1749
        Map<String, Object> map = new HashMap<>();
23650 amit.gupta 1750
 
32145 tejbeer 1751
        map.put("saleHistories", fofoOrders);
1752
        map.put("start", offset + 1);
1753
        map.put("size", countItems);
1754
        map.put("searchType", searchType);
1755
        map.put("searchTypes", SearchType.values());
1756
        map.put("startDate", startDate);
1757
        map.put("searchValue", searchValue);
1758
        map.put(ProfitMandiConstants.END_TIME, endDate);
1759
        if (fofoOrders.size() < limit) {
1760
            map.put("end", offset + fofoOrders.size());
1761
        } else {
1762
            map.put("end", offset + limit);
1763
        }
1764
        return map;
1765
    }
30426 tejbeer 1766
 
33665 ranu 1767
    public ResponseEntity<?> downloadReportInCsv(org.apache.commons.io.output.ByteArrayOutputStream
1768
                                                         baos, List<List<?>> rows, String fileName) {
32145 tejbeer 1769
        final HttpHeaders headers = new HttpHeaders();
1770
        headers.set("Content-Type", "text/csv");
30426 tejbeer 1771
 
32145 tejbeer 1772
        headers.set("Content-disposition", "inline; filename=" + fileName + ".csv");
1773
        headers.setContentLength(baos.toByteArray().length);
23202 ashik.ali 1774
 
32145 tejbeer 1775
        final InputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
1776
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
30426 tejbeer 1777
 
33454 amit.gupta 1778
        return new ResponseEntity<>(inputStreamResource, headers, HttpStatus.OK);
32145 tejbeer 1779
    }
30157 manish 1780
 
32145 tejbeer 1781
    @Override
33665 ranu 1782
    public Map<String, Object> getSaleHistoryPaginated(int fofoId, SearchType searchType, String
1783
            searchValue, LocalDateTime startDate, LocalDateTime endDate, int offset, int limit) throws
1784
            ProfitMandiBusinessException {
32145 tejbeer 1785
        List<FofoOrder> fofoOrders = new ArrayList<>();
23650 amit.gupta 1786
 
32145 tejbeer 1787
        if (searchType == SearchType.CUSTOMER_MOBILE_NUMBER && !searchValue.isEmpty()) {
1788
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerMobileNumber(fofoId, searchValue, startDate, endDate, offset, limit);
1789
        } else if (searchType == SearchType.CUSTOMER_NAME && !searchValue.isEmpty()) {
1790
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerName(fofoId, searchValue, startDate, endDate, offset, limit);
1791
        } else if (searchType == SearchType.IMEI && !searchValue.isEmpty()) {
1792
            fofoOrders = fofoOrderRepository.selectByFofoIdAndSerialNumber(fofoId, searchValue, startDate, endDate, offset, limit);
1793
        } else if (searchType == SearchType.ITEM_NAME && !searchValue.isEmpty()) {
1794
            fofoOrders = fofoOrderRepository.selectByFofoIdAndItemName(fofoId, searchValue, startDate, endDate, offset, limit);
24275 amit.gupta 1795
 
32145 tejbeer 1796
        } else if (searchType == SearchType.DATE_RANGE) {
1797
            fofoOrders = fofoOrderRepository.selectByFofoId(fofoId, startDate, endDate, offset, limit);
1798
        }
1799
        Map<String, Object> map = new HashMap<>();
1800
        map.put("saleHistories", fofoOrders);
1801
        map.put("searchType", searchType);
1802
        map.put("searchTypes", SearchType.values());
1803
        map.put("startDate", startDate);
1804
        map.put("searchValue", searchValue);
1805
        map.put(ProfitMandiConstants.END_TIME, endDate);
1806
        return map;
1807
    }
23650 amit.gupta 1808
 
32145 tejbeer 1809
    private String getFofoStoreCode(int fofoId) throws ProfitMandiBusinessException {
1810
        FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(fofoId);
1811
        return fofoStore.getCode();
1812
    }
23650 amit.gupta 1813
 
32145 tejbeer 1814
    private String getValidName(String name) {
1815
        return name != null ? name : "";
1816
    }
23650 amit.gupta 1817
 
32145 tejbeer 1818
    private Set<String> toSerialNumbers(Set<FofoLineItem> fofoLineItems) {
1819
        Set<String> serialNumbers = new HashSet<>();
1820
        for (FofoLineItem fofoLineItem : fofoLineItems) {
1821
            if (fofoLineItem.getSerialNumber() != null && !fofoLineItem.getSerialNumber().isEmpty()) {
1822
                serialNumbers.add(fofoLineItem.getSerialNumber());
1823
            }
1824
        }
1825
        return serialNumbers;
1826
    }
23650 amit.gupta 1827
 
33520 amit.gupta 1828
    static final List<String> MOP_VOILATED_BRANDS = Arrays.asList("Live Demo", "Almost New");
1829
 
35733 amit 1830
    // DP price validation disabled as of 11 sep 2025 as per tarun sir
33665 ranu 1831
    private void validateDpPrice(int fofoId, Map<
1832
            Integer, PriceModel> itemIdMopPriceMap, Map<Integer, CustomFofoOrderItem> itemIdCustomFofoLineItemMap) throws
1833
            ProfitMandiBusinessException {
32145 tejbeer 1834
    }
24275 amit.gupta 1835
 
35733 amit 1836
    // MOP price validation disabled as of 11 sep 2025 as per tarun sir
33665 ranu 1837
    private void validateMopPrice(int fofoId, Map<
1838
            Integer, PriceModel> itemIdMopPriceMap, Map<Integer, CustomFofoOrderItem> itemIdCustomFofoLineItemMap) throws
1839
            ProfitMandiBusinessException {
32145 tejbeer 1840
    }
23650 amit.gupta 1841
 
33665 ranu 1842
    private void updateInventoryItemsAndScanRecord(Set<InventoryItem> inventoryItems, int fofoId, Map<
1843
            Integer, Integer> inventoryItemQuantityUsed, int fofoOrderId) {
32145 tejbeer 1844
        for (InventoryItem inventoryItem : inventoryItems) {
1845
            inventoryItem.setLastScanType(ScanType.SALE);
33087 amit.gupta 1846
            inventoryItem.setUpdateTimestamp(LocalDateTime.now());
32145 tejbeer 1847
            ScanRecord scanRecord = new ScanRecord();
1848
            scanRecord.setInventoryItemId(inventoryItem.getId());
1849
            scanRecord.setFofoId(fofoId);
1850
            scanRecord.setOrderId(fofoOrderId);
1851
            // correct this
1852
            scanRecord.setQuantity(inventoryItemQuantityUsed.get(inventoryItem.getId()));
1853
            scanRecord.setType(ScanType.SALE);
1854
            scanRecordRepository.persist(scanRecord);
1855
            purchaseReturnItemRepository.deleteById(inventoryItem.getId());
23650 amit.gupta 1856
 
32145 tejbeer 1857
        }
1858
    }
23650 amit.gupta 1859
 
33665 ranu 1860
    private void createFofoLineItem(int fofoOrderItemId, Set<
1861
            InventoryItem> inventoryItems, Map<Integer, Integer> inventoryItemIdQuantityUsed) {
32145 tejbeer 1862
        for (InventoryItem inventoryItem : inventoryItems) {
1863
            FofoLineItem fofoLineItem = new FofoLineItem();
1864
            fofoLineItem.setFofoOrderItemId(fofoOrderItemId);
1865
            fofoLineItem.setSerialNumber(inventoryItem.getSerialNumber());
1866
            fofoLineItem.setInventoryItemId(inventoryItem.getId());
1867
            fofoLineItem.setQuantity(inventoryItemIdQuantityUsed.get(inventoryItem.getId()));
1868
            fofoLineItemRepository.persist(fofoLineItem);
1869
        }
1870
    }
23650 amit.gupta 1871
 
33665 ranu 1872
    private FofoOrderItem createAndGetFofoOrderItem(CustomFofoOrderItem customFofoOrderItem, int fofoOrderId, Map<
35493 amit 1873
            Integer, Item> itemMap, Set<InventoryItem> inventoryItems, Map<Integer, TagListing> tagListingMap,
1874
            Map<Integer, GstRate> gstRateMap) throws ProfitMandiBusinessException {
32145 tejbeer 1875
        FofoOrderItem fofoOrderItem = new FofoOrderItem();
1876
        fofoOrderItem.setItemId(customFofoOrderItem.getItemId());
1877
        fofoOrderItem.setQuantity(customFofoOrderItem.getQuantity());
1878
        fofoOrderItem.setSellingPrice(customFofoOrderItem.getSellingPrice());
34381 vikas.jang 1879
        fofoOrderItem.setPendingOrderItemId(customFofoOrderItem.getPoiId());
32145 tejbeer 1880
        fofoOrderItem.setOrderId(fofoOrderId);
35493 amit 1881
 
1882
        // N+1 fix: Use pre-fetched tagListingMap instead of querying per item
1883
        TagListing tl = tagListingMap.get(customFofoOrderItem.getItemId());
32145 tejbeer 1884
        // In case listing gets removed rebill it using the selling price
1885
        if (tl != null) {
1886
            fofoOrderItem.setDp(tl.getSellingPrice());
1887
            fofoOrderItem.setMop(tl.getMop());
1888
        } else {
1889
            fofoOrderItem.setDp(customFofoOrderItem.getSellingPrice());
1890
            fofoOrderItem.setMop(customFofoOrderItem.getSellingPrice());
1891
        }
1892
        fofoOrderItem.setDiscount(customFofoOrderItem.getDiscountAmount());
24823 amit.gupta 1893
 
32145 tejbeer 1894
        Item item = itemMap.get(customFofoOrderItem.getItemId());
35493 amit 1895
 
35736 amit 1896
        // Use first inventory item to get HSN code and GST rates
1897
        InventoryItem firstInventoryItem = inventoryItems.iterator().next();
1898
        GstRate gstRate = gstRateMap.get(firstInventoryItem.getItemId());
1899
        if (gstRate != null) {
1900
            fofoOrderItem.setIgstRate(gstRate.getIgstRate());
1901
            fofoOrderItem.setCgstRate(gstRate.getCgstRate());
1902
            fofoOrderItem.setSgstRate(gstRate.getSgstRate());
32145 tejbeer 1903
        }
35736 amit 1904
        fofoOrderItem.setHsnCode(firstInventoryItem.getHsnCode());
32145 tejbeer 1905
        fofoOrderItem.setBrand(item.getBrand());
1906
        fofoOrderItem.setModelName(item.getModelName());
1907
        fofoOrderItem.setModelNumber(item.getModelNumber());
1908
        fofoOrderItem.setColor(item.getColor());
1909
        fofoOrderItemRepository.persist(fofoOrderItem);
1910
        return fofoOrderItem;
1911
    }
27516 amit.gupta 1912
 
33665 ranu 1913
    private FofoOrderItem getDummyFofoOrderItem(int itemId, int fofoOrderId, String serialNumber, Integer stateId) throws
1914
            ProfitMandiBusinessException {
32145 tejbeer 1915
        Item item = itemRepository.selectById(itemId);
1916
        TagListing tl = tagListingRepository.selectByItemId(itemId);
1917
        FofoOrderItem fofoOrderItem = new FofoOrderItem();
1918
        fofoOrderItem.setItemId(itemId);
1919
        fofoOrderItem.setQuantity(1);
1920
        fofoOrderItem.setSellingPrice(tl.getMop());
1921
        fofoOrderItem.setOrderId(fofoOrderId);
1922
        // In case listing gets removed rebill it using the selling price
1923
        fofoOrderItem.setDp(tl.getSellingPrice());
1924
        fofoOrderItem.setMop(tl.getMop());
1925
        fofoOrderItem.setDiscount(0);
27516 amit.gupta 1926
 
32145 tejbeer 1927
        Map<Integer, GstRate> itemIdStateTaxRateMap = null;
1928
        if (stateId != null) {
1929
            itemIdStateTaxRateMap = stateGstRateRepository.getStateTaxRate(Arrays.asList(itemId), stateId);
1930
        } else {
1931
            itemIdStateTaxRateMap = stateGstRateRepository.getIgstTaxRate(Arrays.asList(itemId));
1932
        }
27516 amit.gupta 1933
 
32145 tejbeer 1934
        fofoOrderItem.setIgstRate(itemIdStateTaxRateMap.get(itemId).getIgstRate());
27516 amit.gupta 1935
 
32145 tejbeer 1936
        fofoOrderItem.setCgstRate(itemIdStateTaxRateMap.get(itemId).getCgstRate());
1937
        fofoOrderItem.setSgstRate(itemIdStateTaxRateMap.get(itemId).getSgstRate());
23650 amit.gupta 1938
 
1939
 
32145 tejbeer 1940
        fofoOrderItem.setHsnCode(item.getHsnCode());
1941
        fofoOrderItem.setBrand(item.getBrand());
1942
        fofoOrderItem.setModelName(item.getModelName());
1943
        fofoOrderItem.setModelNumber(item.getModelNumber());
1944
        fofoOrderItem.setColor(item.getColor());
23650 amit.gupta 1945
 
32145 tejbeer 1946
        Set<FofoLineItem> fofoLineItems = new HashSet<>();
1947
        FofoLineItem fli = new FofoLineItem();
1948
        fli.setQuantity(1);
1949
        fli.setSerialNumber(serialNumber);
1950
        fofoLineItems.add(fli);
1951
        fofoOrderItem.setFofoLineItems(fofoLineItems);
22859 ashik.ali 1952
 
32145 tejbeer 1953
        return fofoOrderItem;
1954
    }
22859 ashik.ali 1955
 
33665 ranu 1956
    private void updateCurrentInventorySnapshot(List<CurrentInventorySnapshot> currentInventorySnapshots,
1957
                                                int fofoId, int itemId, int quantity) throws ProfitMandiBusinessException {
32145 tejbeer 1958
        for (CurrentInventorySnapshot currentInventorySnapshot : currentInventorySnapshots) {
1959
            if (currentInventorySnapshot.getItemId() == itemId && currentInventorySnapshot.getFofoId() == fofoId) {
1960
                currentInventorySnapshotRepository.updateAvailabilityByItemIdAndFofoId(itemId, fofoId, currentInventorySnapshot.getAvailability() - quantity);
1961
            }
1962
        }
1963
    }
23650 amit.gupta 1964
 
33665 ranu 1965
    private void createPaymentOptions(FofoOrder fofoOrder, Set<CustomPaymentOption> customPaymentOptions) throws
1966
            ProfitMandiBusinessException {
32145 tejbeer 1967
        for (CustomPaymentOption customPaymentOption : customPaymentOptions) {
1968
            if (customPaymentOption.getAmount() > 0) {
1969
                PaymentOptionTransaction paymentOptionTransaction = new PaymentOptionTransaction();
1970
                paymentOptionTransaction.setReferenceId(fofoOrder.getId());
1971
                paymentOptionTransaction.setPaymentOptionId(customPaymentOption.getPaymentOptionId());
1972
                paymentOptionTransaction.setReferenceType(PaymentOptionReferenceType.ORDER);
1973
                paymentOptionTransaction.setAmount(customPaymentOption.getAmount());
1974
                paymentOptionTransaction.setFofoId(fofoOrder.getFofoId());
1975
                paymentOptionTransactionRepository.persist(paymentOptionTransaction);
1976
            }
1977
        }
1978
    }
22859 ashik.ali 1979
 
33665 ranu 1980
    private FofoOrder createAndGetFofoOrder(int customerId, String customerGstNumber, int fofoId, String
34381 vikas.jang 1981
            documentNumber, float totalAmount, int customerAddressId, int poId) {
36362 amit 1982
        // Idempotency: concurrent duplicate requests (double-click, upstream retries) used
1983
        // to deadlock on idx_invoice_number. Fast path — if the row already exists for
1984
        // this (fofo, invoice) return it instead of attempting a duplicate insert.
1985
        FofoOrder existing = findExistingFofoOrder(fofoId, documentNumber);
1986
        if (existing != null) return existing;
1987
 
32145 tejbeer 1988
        FofoOrder fofoOrder = new FofoOrder();
1989
        fofoOrder.setCustomerGstNumber(customerGstNumber);
1990
        fofoOrder.setCustomerId(customerId);
1991
        fofoOrder.setFofoId(fofoId);
34381 vikas.jang 1992
        fofoOrder.setPendingOrderId(poId);
32145 tejbeer 1993
        fofoOrder.setInvoiceNumber(documentNumber);
1994
        fofoOrder.setTotalAmount(totalAmount);
1995
        fofoOrder.setCustomerAddressId(customerAddressId);
36362 amit 1996
        try {
1997
            fofoOrderRepository.persist(fofoOrder);
1998
        } catch (org.springframework.dao.DataIntegrityViolationException dup) {
1999
            // Narrow race: another concurrent request won the insert after our select.
2000
            // Re-fetch and return the winner's row. Requires the uk_fofo_order_fofo_invoice
2001
            // unique key on fofo_order to surface the duplicate as this exception.
2002
            FofoOrder winner = findExistingFofoOrder(fofoId, documentNumber);
2003
            if (winner != null) return winner;
2004
            throw dup;
2005
        }
32145 tejbeer 2006
        return fofoOrder;
2007
    }
23650 amit.gupta 2008
 
36362 amit 2009
    private FofoOrder findExistingFofoOrder(int fofoId, String invoiceNumber) {
2010
        try {
2011
            return fofoOrderRepository.selectByFofoIdAndInvoiceNumber(fofoId, invoiceNumber);
2012
        } catch (ProfitMandiBusinessException ignored) {
2013
            return null;
2014
        }
2015
    }
2016
 
33665 ranu 2017
    private void validateItemsSerializedNonSerialized
2018
            (List<Item> items, Map<Integer, CustomFofoOrderItem> customFofoOrderItemMap) throws
2019
            ProfitMandiBusinessException {
32145 tejbeer 2020
        List<Integer> invalidItemIdSerialNumbers = new ArrayList<Integer>();
2021
        List<Integer> itemIdNonSerializedSerialNumbers = new ArrayList<Integer>();
2022
        for (Item i : items) {
2023
            CustomFofoOrderItem customFofoOrderItem = customFofoOrderItemMap.get(i.getId());
2024
            if (i.getType().equals(ItemType.SERIALIZED)) {
2025
                if (customFofoOrderItem == null || customFofoOrderItem.getSerialNumberDetails().isEmpty()) {
2026
                    invalidItemIdSerialNumbers.add(i.getId());
2027
                }
2028
            } else {
2029
                Set<String> serialNumbers = this.serialNumberDetailsToSerialNumbers(customFofoOrderItem.getSerialNumberDetails());
2030
                if (customFofoOrderItem == null || !serialNumbers.isEmpty()) {
2031
                    itemIdNonSerializedSerialNumbers.add(i.getId());
2032
                }
2033
            }
2034
        }
23650 amit.gupta 2035
 
32145 tejbeer 2036
        if (!invalidItemIdSerialNumbers.isEmpty()) {
2037
            LOGGER.error("Invalid itemId's serialNumbers for serialized{}", invalidItemIdSerialNumbers);
2038
            // itemId's are serialized you are saying these are not serialized
2039
            throw new ProfitMandiBusinessException("invalidItemIdSerialNumbers", invalidItemIdSerialNumbers, "FFORDR_1013");
2040
        }
22859 ashik.ali 2041
 
32145 tejbeer 2042
        if (!itemIdNonSerializedSerialNumbers.isEmpty()) {
2043
            LOGGER.error("Invalid itemId's serialNumbers for non serialized{}", itemIdNonSerializedSerialNumbers);
2044
            // itemId's are non serialized you are saying these are serialized
2045
            throw new ProfitMandiBusinessException("itemIdNonSerializedSerialNumbers", itemIdNonSerializedSerialNumbers, "FFORDR_1014");
2046
        }
2047
    }
22859 ashik.ali 2048
 
33665 ranu 2049
    private void validateCurrentInventorySnapshotQuantities
2050
            (List<CurrentInventorySnapshot> currentInventorySnapshots, Map<Integer, CustomFofoOrderItem> itemIdCustomFofoOrderItemMap) throws
2051
            ProfitMandiBusinessException {
32145 tejbeer 2052
        if (itemIdCustomFofoOrderItemMap.keySet().size() != currentInventorySnapshots.size()) {
2053
            throw new ProfitMandiBusinessException("quantiiesSize", currentInventorySnapshots.size(), "");
2054
        }
2055
        List<ItemIdQuantityAvailability> itemIdQuantityAvailabilities = new ArrayList<>(); // this is for error
2056
        LOGGER.info("currentInventorySnapshots " + currentInventorySnapshots);
2057
        LOGGER.info("CustomFofoLineItemMap {}", itemIdCustomFofoOrderItemMap);
2058
        for (CurrentInventorySnapshot currentInventorySnapshot : currentInventorySnapshots) {
2059
            CustomFofoOrderItem customFofoOrderItem = itemIdCustomFofoOrderItemMap.get(currentInventorySnapshot.getItemId());
2060
            LOGGER.info("customFofoOrderItem {}", customFofoOrderItem);
2061
            if (customFofoOrderItem.getQuantity() > currentInventorySnapshot.getAvailability()) {
2062
                ItemIdQuantityAvailability itemIdQuantityAvailability = new ItemIdQuantityAvailability();
2063
                itemIdQuantityAvailability.setItemId(customFofoOrderItem.getItemId());
2064
                Quantity quantity = new Quantity();
2065
                quantity.setAvailable(currentInventorySnapshot.getAvailability());
2066
                quantity.setRequested(customFofoOrderItem.getQuantity());
2067
                itemIdQuantityAvailability.setQuantity(quantity);
2068
                itemIdQuantityAvailabilities.add(itemIdQuantityAvailability);
2069
            }
2070
        }
22859 ashik.ali 2071
 
32145 tejbeer 2072
        if (!itemIdQuantityAvailabilities.isEmpty()) {
2073
            // itemIdQuantity request is not valid
2074
            LOGGER.error("Requested quantities should not be greater than currently available quantities {}", itemIdQuantityAvailabilities);
2075
            throw new ProfitMandiBusinessException("itemIdQuantityAvailabilities", itemIdQuantityAvailabilities, "FFORDR_1015");
2076
        }
2077
    }
22859 ashik.ali 2078
 
33665 ranu 2079
    private int getItemIdFromSerialNumber(Map<Integer, CustomFofoOrderItem> itemIdCustomFofoOrderItemMap, String
2080
            serialNumber) {
32145 tejbeer 2081
        int itemId = 0;
2082
        for (Map.Entry<Integer, CustomFofoOrderItem> entry : itemIdCustomFofoOrderItemMap.entrySet()) {
2083
            Set<SerialNumberDetail> serialNumberDetails = entry.getValue().getSerialNumberDetails();
2084
            for (SerialNumberDetail serialNumberDetail : serialNumberDetails) {
2085
                if (serialNumberDetail.getSerialNumber().equals(serialNumber)) {
2086
                    itemId = entry.getKey();
2087
                    break;
2088
                }
2089
            }
2090
        }
2091
        return itemId;
2092
    }
23650 amit.gupta 2093
 
32145 tejbeer 2094
    private Map<Integer, Item> toItemMap(List<Item> items) {
2095
        Function<Item, Integer> itemIdFunction = new Function<Item, Integer>() {
2096
            @Override
2097
            public Integer apply(Item item) {
2098
                return item.getId();
2099
            }
2100
        };
2101
        Function<Item, Item> itemFunction = new Function<Item, Item>() {
2102
            @Override
2103
            public Item apply(Item item) {
2104
                return item;
2105
            }
2106
        };
2107
        return items.stream().collect(Collectors.toMap(itemIdFunction, itemFunction));
2108
    }
23650 amit.gupta 2109
 
32145 tejbeer 2110
    private void setCustomerAddress(CustomerAddress customerAddress, CustomAddress customAddress) {
2111
        customerAddress.setName(customAddress.getName());
2112
        customerAddress.setLastName(customAddress.getLastName());
2113
        customerAddress.setLine1(customAddress.getLine1());
2114
        customerAddress.setLine2(customAddress.getLine2());
2115
        customerAddress.setLandmark(customAddress.getLandmark());
2116
        customerAddress.setCity(customAddress.getCity());
2117
        customerAddress.setPinCode(customAddress.getPinCode());
2118
        customerAddress.setState(customAddress.getState());
2119
        customerAddress.setCountry(customAddress.getCountry());
2120
        customerAddress.setPhoneNumber(customAddress.getPhoneNumber());
2121
    }
23650 amit.gupta 2122
 
32145 tejbeer 2123
    private CustomAddress createCustomAddress(Address address) {
2124
        CustomAddress customAddress = new CustomAddress();
2125
        customAddress.setName(address.getName());
2126
        customAddress.setLine1(address.getLine1());
2127
        customAddress.setLine2(address.getLine2());
2128
        customAddress.setLandmark(address.getLandmark());
2129
        customAddress.setCity(address.getCity());
2130
        customAddress.setPinCode(address.getPinCode());
2131
        customAddress.setState(address.getState());
2132
        customAddress.setCountry(address.getCountry());
2133
        customAddress.setPhoneNumber(address.getPhoneNumber());
2134
        return customAddress;
2135
    }
23650 amit.gupta 2136
 
32145 tejbeer 2137
    private CustomAddress createCustomAddress(CustomerAddress customerAddress) {
2138
        CustomAddress customAddress = new CustomAddress();
2139
        customAddress.setName(customerAddress.getName());
2140
        customAddress.setLastName(customerAddress.getLastName());
2141
        customAddress.setLine1(customerAddress.getLine1());
2142
        customAddress.setLine2(customerAddress.getLine2());
2143
        customAddress.setLandmark(customerAddress.getLandmark());
2144
        customAddress.setCity(customerAddress.getCity());
2145
        customAddress.setPinCode(customerAddress.getPinCode());
2146
        customAddress.setState(customerAddress.getState());
2147
        customAddress.setCountry(customerAddress.getCountry());
2148
        customAddress.setPhoneNumber(customerAddress.getPhoneNumber());
2149
        return customAddress;
2150
    }
23650 amit.gupta 2151
 
33665 ranu 2152
    private CustomAddress createCustomAddressWithoutId(CustomCustomer customerAddress, CustomAddress
2153
            retailerAddress) {
32627 ranu 2154
        CustomAddress customAddress = new CustomAddress();
2155
        customAddress.setName(customerAddress.getFirstName());
2156
        customAddress.setLastName(customerAddress.getLastName());
2157
        customAddress.setLine1("");
2158
        customAddress.setLine2("");
2159
        customAddress.setLandmark("");
33089 amit.gupta 2160
        customAddress.setCity(retailerAddress.getCity());
2161
        customAddress.setPinCode(retailerAddress.getPinCode());
2162
        customAddress.setState(retailerAddress.getState());
32627 ranu 2163
        customAddress.setCountry("");
2164
        customAddress.setPhoneNumber(customerAddress.getMobileNumber());
2165
        return customAddress;
2166
    }
2167
 
33665 ranu 2168
    private void validatePaymentOptionsAndTotalAmount(Set<CustomPaymentOption> customPaymentOptions,
2169
                                                      float totalAmount) throws ProfitMandiBusinessException {
32145 tejbeer 2170
        Set<Integer> paymentOptionIds = new HashSet<>();
23650 amit.gupta 2171
 
32145 tejbeer 2172
        float calculatedAmount = 0;
2173
        for (CustomPaymentOption customPaymentOption : customPaymentOptions) {
2174
            paymentOptionIds.add(customPaymentOption.getPaymentOptionId());
2175
            calculatedAmount = calculatedAmount + customPaymentOption.getAmount();
2176
        }
2177
        if (calculatedAmount != totalAmount) {
2178
            LOGGER.warn("Error occured while validating payment options amount - {} != TotalAmount {}", calculatedAmount, totalAmount);
2179
            throw new ProfitMandiBusinessException(ProfitMandiConstants.PAYMENT_OPTION_CALCULATED_AMOUNT, calculatedAmount, "FFORDR_1016");
2180
        }
23418 ashik.ali 2181
 
32145 tejbeer 2182
        List<Integer> foundPaymentOptionIds = paymentOptionRepository.selectIdsByIds(paymentOptionIds);
2183
        if (foundPaymentOptionIds.size() != paymentOptionIds.size()) {
2184
            paymentOptionIds.removeAll(foundPaymentOptionIds);
2185
            throw new ProfitMandiBusinessException(ProfitMandiConstants.PAYMENT_OPTION_ID, paymentOptionIds, "FFORDR_1017");
2186
        }
2187
    }
25101 amit.gupta 2188
 
32145 tejbeer 2189
    @Override
2190
    public List<FofoOrderItem> getByOrderId(int orderId) throws ProfitMandiBusinessException {
2191
        List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(orderId);
2192
        if (!fofoOrderItems.isEmpty()) {
2193
            List<FofoOrderItem> newFofoOrderItems = new ArrayList<>();
2194
            Map<Integer, Set<FofoLineItem>> fofoOrderItemIdFofoLineItemsMap = this.toFofoOrderItemIdFofoLineItems(fofoOrderItems);
2195
            Iterator<FofoOrderItem> fofoOrderItemsIterator = fofoOrderItems.iterator();
2196
            while (fofoOrderItemsIterator.hasNext()) {
2197
                FofoOrderItem fofoOrderItem = fofoOrderItemsIterator.next();
2198
                fofoOrderItem.setFofoLineItems(fofoOrderItemIdFofoLineItemsMap.get(fofoOrderItem.getId()));
2199
                newFofoOrderItems.add(fofoOrderItem);
2200
                fofoOrderItemsIterator.remove();
2201
            }
2202
            fofoOrderItems = newFofoOrderItems;
2203
        }
2204
        return fofoOrderItems;
2205
    }
25101 amit.gupta 2206
 
32145 tejbeer 2207
    private Set<Integer> toFofoOrderItemIds(List<FofoOrderItem> fofoOrderItems) {
2208
        Function<FofoOrderItem, Integer> fofoOrderItemToFofoOrderItemIdFunction = new Function<FofoOrderItem, Integer>() {
2209
            @Override
2210
            public Integer apply(FofoOrderItem fofoOrderItem) {
2211
                return fofoOrderItem.getId();
2212
            }
2213
        };
2214
        return fofoOrderItems.stream().map(fofoOrderItemToFofoOrderItemIdFunction).collect(Collectors.toSet());
2215
    }
25101 amit.gupta 2216
 
33665 ranu 2217
    private Map<Integer, Set<FofoLineItem>> toFofoOrderItemIdFofoLineItems(List<FofoOrderItem> fofoOrderItems) throws
2218
            ProfitMandiBusinessException {
32145 tejbeer 2219
        Set<Integer> fofoOrderItemIds = this.toFofoOrderItemIds(fofoOrderItems);
2220
        List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
2221
        Map<Integer, Set<FofoLineItem>> fofoOrderItemIdFofoLineItemsMap = new HashMap<>();
2222
        for (FofoLineItem fofoLineItem : fofoLineItems) {
2223
            if (!fofoOrderItemIdFofoLineItemsMap.containsKey(fofoLineItem.getFofoOrderItemId())) {
2224
                Set<FofoLineItem> fofoLineItems2 = new HashSet<>();
2225
                fofoLineItems2.add(fofoLineItem);
2226
                fofoOrderItemIdFofoLineItemsMap.put(fofoLineItem.getFofoOrderItemId(), fofoLineItems2);
2227
            } else {
2228
                fofoOrderItemIdFofoLineItemsMap.get(fofoLineItem.getFofoOrderItemId()).add(fofoLineItem);
2229
            }
2230
        }
2231
        return fofoOrderItemIdFofoLineItemsMap;
2232
    }
25101 amit.gupta 2233
 
32145 tejbeer 2234
    @Override
33665 ranu 2235
    public void updateCustomerDetails(CustomCustomer customCustomer, String invoiceNumber) throws
2236
            ProfitMandiBusinessException {
32145 tejbeer 2237
        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
34718 aman.kumar 2238
        LOGGER.info("fofoOrder{}", fofoOrder);
32145 tejbeer 2239
        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
34718 aman.kumar 2240
        LOGGER.info("customer{}", customer);
32145 tejbeer 2241
        customer.setFirstName(customCustomer.getFirstName());
2242
        customer.setLastName(customCustomer.getLastName());
2243
        customer.setMobileNumber(customCustomer.getMobileNumber());
2244
        customer.setEmailId(customCustomer.getEmailId());
2245
        customerRepository.persist(customer);
34338 ranu 2246
        if (fofoOrder.getCustomerAddressId() == 0) {
2247
            CustomAddress customAddress = customCustomer.getAddress();
2248
 
2249
            if (customAddress == null ||
2250
                    isNullOrEmpty(customAddress.getName()) ||
2251
                    isNullOrEmpty(customAddress.getLastName()) ||
2252
                    isNullOrEmpty(customAddress.getLine1()) ||
2253
                    isNullOrEmpty(customAddress.getCity()) ||
2254
                    isNullOrEmpty(customAddress.getPinCode()) ||
2255
                    isNullOrEmpty(customAddress.getState()) ||
34718 aman.kumar 2256
//                    isNullOrEmpty(customAddress.getCountry()) ||
34338 ranu 2257
                    isNullOrEmpty(customAddress.getPhoneNumber())) {
2258
                throw new IllegalArgumentException("Required customer address fields are missing.");
2259
            }
2260
 
2261
            CustomerAddress customerAddress = new CustomerAddress();
2262
            customerAddress.setCustomerId(fofoOrder.getCustomerId());
2263
            customerAddress.setName(customAddress.getName());
2264
            customerAddress.setLastName(customAddress.getLastName());
2265
            customerAddress.setLine1(customAddress.getLine1());
2266
            customerAddress.setLine2(customAddress.getLine2());
2267
            customerAddress.setLandmark(customAddress.getLandmark());
2268
            customerAddress.setCity(customAddress.getCity());
2269
            customerAddress.setPinCode(customAddress.getPinCode());
2270
            customerAddress.setState(customAddress.getState());
34718 aman.kumar 2271
//            customerAddress.setCountry(customAddress.getCountry());
34338 ranu 2272
            customerAddress.setPhoneNumber(customAddress.getPhoneNumber());
2273
            customerAddressRepository.persist(customerAddress);
2274
            fofoOrder.setCustomerAddressId(customerAddress.getId());
2275
 
2276
        }
32145 tejbeer 2277
        CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
2278
        if (!customerAddress.getState().equalsIgnoreCase(customCustomer.getAddress().getState())) {
2279
            List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
2280
            resetTaxation(fofoOrder.getFofoId(), customerAddress, fofoOrderItems);
2281
        }
2282
        this.setCustomerAddress(customerAddress, customCustomer.getAddress());
2283
        fofoOrder.setCustomerGstNumber(customCustomer.getGstNumber());
2284
    }
23638 amit.gupta 2285
 
34338 ranu 2286
    private boolean isNullOrEmpty(String str) {
2287
        return str == null || str.trim().isEmpty();
2288
    }
2289
 
33665 ranu 2290
    private void resetTaxation(int fofoId, CustomerAddress customerAddress, List<FofoOrderItem> fofoOrderItems) throws
2291
            ProfitMandiBusinessException {
32145 tejbeer 2292
        int retailerAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(fofoId);
23650 amit.gupta 2293
 
32145 tejbeer 2294
        Address retailerAddress = addressRepository.selectById(retailerAddressId);
24275 amit.gupta 2295
 
32145 tejbeer 2296
        Integer stateId = null;
2297
        if (customerAddress.getState().equalsIgnoreCase(retailerAddress.getState())) {
2298
            try {
2299
                stateId = Long.valueOf(stateRepository.selectByName(customerAddress.getState()).getId()).intValue();
2300
            } catch (Exception e) {
2301
                LOGGER.error("Unable to get state rates");
2302
            }
2303
        }
2304
        List<Integer> itemIds = fofoOrderItems.stream().map(x -> x.getItemId()).collect(Collectors.toList());
2305
        final Map<Integer, GstRate> gstRates;
2306
        if (stateId != null) {
2307
            gstRates = stateGstRateRepository.getStateTaxRate(itemIds, stateId);
2308
        } else {
2309
            gstRates = stateGstRateRepository.getIgstTaxRate(itemIds);
2310
        }
2311
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
2312
            GstRate rate = gstRates.get(fofoOrderItem.getItemId());
2313
            fofoOrderItem.setCgstRate(rate.getCgstRate());
2314
            fofoOrderItem.setSgstRate(rate.getSgstRate());
2315
            fofoOrderItem.setIgstRate(rate.getIgstRate());
2316
        }
2317
    }
2318
    @Override
33665 ranu 2319
    public CustomerCreditNote badReturn(int fofoId, FoiBadReturnRequest foiBadReturnRequest) throws
2320
            ProfitMandiBusinessException {
34141 tejus.loha 2321
        return this.badReturn(null, fofoId, foiBadReturnRequest);
2322
    }
2323
    @Override
2324
    public CustomerCreditNote badReturn(String loginMail,int fofoId, FoiBadReturnRequest foiBadReturnRequest) throws
2325
            ProfitMandiBusinessException {
32145 tejbeer 2326
        FofoOrderItem foi = fofoOrderItemRepository.selectById(foiBadReturnRequest.getFofoOrderItemId());
2327
        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(foi.getOrderId());
2328
        if (fofoOrder.getFofoId() != fofoId) {
2329
            throw new ProfitMandiBusinessException("Partner Auth", "", "Invalid Order");
2330
        }
2331
        int billedQty = foi.getQuantity() - customerReturnItemRepository.selectAllByOrderItemId(foi.getId()).size();
2332
        if (foiBadReturnRequest.getMarkedBadArr().size() > billedQty) {
2333
            throw new ProfitMandiBusinessException("Cant bad return more than what is billed", "", "Invalid Quantity");
2334
        }
2335
        List<CustomerReturnItem> customerReturnItems = new ArrayList<>();
2336
        for (BadReturnRequest badReturnRequest : foiBadReturnRequest.getMarkedBadArr()) {
2337
            CustomerReturnItem customerReturnItem = new CustomerReturnItem();
2338
            customerReturnItem.setFofoId(fofoId);
2339
            customerReturnItem.setFofoOrderItemId(foiBadReturnRequest.getFofoOrderItemId());
2340
            customerReturnItem.setFofoOrderId(fofoOrder.getId());
2341
            customerReturnItem.setRemarks(badReturnRequest.getRemarks());
2342
            customerReturnItem.setInventoryItemId(badReturnRequest.getInventoryItemId());
2343
            customerReturnItem.setQuantity(1);
2344
            customerReturnItem.setType(ReturnType.BAD);
2345
            // customerReturnItemRepository.persist(customerReturnItem);
2346
            inventoryService.saleReturnInventoryItem(customerReturnItem);
2347
            customerReturnItems.add(customerReturnItem);
2348
        }
2349
        CustomerCreditNote creditNote = generateCreditNote(fofoOrder, customerReturnItems);
2350
        for (CustomerReturnItem customerReturnItem : customerReturnItems) {
2351
            purchaseReturnService.returnInventoryItem(fofoId, false, customerReturnItem.getInventoryItemId(), ReturnType.BAD);
2352
        }
2353
        // This should cancel the order
2354
        fofoOrder.setCancelledTimestamp(LocalDateTime.now());
36305 amit 2355
        partnerInvestmentService.evictInvestmentCache(fofoOrder.getFofoId());
32145 tejbeer 2356
        this.reverseScheme(fofoOrder);
2357
        return creditNote;
2358
    }
23638 amit.gupta 2359
 
33665 ranu 2360
    private CustomerCreditNote generateCreditNote(FofoOrder
2361
                                                          fofoOrder, List<CustomerReturnItem> customerReturnItems) throws ProfitMandiBusinessException {
24275 amit.gupta 2362
 
32145 tejbeer 2363
        InvoiceNumberGenerationSequence sequence = invoiceNumberGenerationSequenceRepository.selectByFofoId(fofoOrder.getFofoId());
2364
        sequence.setCreditNoteSequence(sequence.getCreditNoteSequence() + 1);
2365
        invoiceNumberGenerationSequenceRepository.persist(sequence);
24275 amit.gupta 2366
 
32145 tejbeer 2367
        String creditNoteNumber = sequence.getPrefix() + "/" + sequence.getCreditNoteSequence();
2368
        CustomerCreditNote creditNote = new CustomerCreditNote();
2369
        creditNote.setCreditNoteNumber(creditNoteNumber);
2370
        creditNote.setFofoId(fofoOrder.getFofoId());
2371
        creditNote.setFofoOrderId(fofoOrder.getId());
2372
        creditNote.setFofoOrderItemId(customerReturnItems.get(0).getFofoOrderItemId());
2373
        creditNote.setSettlementType(SettlementType.UNSETTLED);
2374
        customerCreditNoteRepository.persist(creditNote);
24275 amit.gupta 2375
 
32145 tejbeer 2376
        for (CustomerReturnItem customerReturnItem : customerReturnItems) {
2377
            customerReturnItem.setCreditNoteId(creditNote.getId());
2378
            customerReturnItemRepository.persist(customerReturnItem);
2379
        }
2380
        // this.returnInventoryItems(inventoryItems, debitNote);
23655 amit.gupta 2381
 
32145 tejbeer 2382
        return creditNote;
2383
    }
23655 amit.gupta 2384
 
32145 tejbeer 2385
    @Override
2386
    public CreditNotePdfModel getCreditNotePdfModel(int customerCreditNoteId) throws ProfitMandiBusinessException {
2387
        CustomerCreditNote creditNote = customerCreditNoteRepository.selectById(customerCreditNoteId);
2388
        return getCreditNotePdfModel(creditNote);
2389
    }
24275 amit.gupta 2390
 
33665 ranu 2391
    private CreditNotePdfModel getCreditNotePdfModel(CustomerCreditNote creditNote) throws
2392
            ProfitMandiBusinessException {
32145 tejbeer 2393
        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(creditNote.getFofoOrderId());
2394
        List<CustomerReturnItem> customerReturnItems = customerReturnItemRepository.selectAllByCreditNoteId(creditNote.getId());
33090 amit.gupta 2395
        CustomRetailer customRetailer = retailerService.getFofoRetailer(fofoOrder.getFofoId());
2396
        CustomCustomer customCustomer = getCustomCustomer(fofoOrder, customRetailer.getAddress());
24275 amit.gupta 2397
 
33298 amit.gupta 2398
        List<CustomOrderItem> customerFofoOrderItems = new ArrayList<>();
23655 amit.gupta 2399
 
32145 tejbeer 2400
        FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(creditNote.getFofoOrderItemId());
2401
        float totalTaxRate = fofoOrderItem.getIgstRate() + fofoOrderItem.getSgstRate() + fofoOrderItem.getCgstRate();
24275 amit.gupta 2402
 
32145 tejbeer 2403
        CustomOrderItem customFofoOrderItem = new CustomOrderItem();
2404
        customFofoOrderItem.setDescription(fofoOrderItem.getBrand() + " " + fofoOrderItem.getModelName() + " " + fofoOrderItem.getModelNumber() + "-" + fofoOrderItem.getColor());
24275 amit.gupta 2405
 
35695 amit 2406
        List<String> serialNumbers = new ArrayList<>();
32145 tejbeer 2407
        if (ItemType.SERIALIZED.equals(itemRepository.selectById(fofoOrderItem.getItemId()).getType())) {
2408
            Set<Integer> inventoryItemIds = customerReturnItems.stream().map(x -> x.getInventoryItemId()).collect(Collectors.toSet());
35695 amit 2409
            serialNumbers = inventoryItemRepository.selectByIds(inventoryItemIds).stream().map(x -> x.getSerialNumber()).collect(Collectors.toList());
32145 tejbeer 2410
            customFofoOrderItem.setDescription(
2411
                    customFofoOrderItem.getDescription() + "\n IMEIS - " + String.join(", ", serialNumbers));
2412
        }
23638 amit.gupta 2413
 
35695 amit 2414
        // Check if margin scheme item
2415
        boolean isMarginItem = false;
2416
        try {
2417
            Item item = itemRepository.selectById(fofoOrderItem.getItemId());
2418
            Category category = categoryRepository.selectById(item.getCategoryId());
2419
            isMarginItem = category.isMarginOnly() && !serialNumbers.isEmpty();
2420
        } catch (Exception e) {
2421
            LOGGER.warn("Could not check margin scheme for credit note item {}", fofoOrderItem.getId(), e);
2422
        }
2423
 
2424
        if (isMarginItem) {
2425
            // Margin Scheme credit note: reverse GST on margin only
2426
            float purchasePrice = getFofoPurchasePrice(serialNumbers.get(0), fofoOrder.getFofoId());
2427
            float sellingPrice = fofoOrderItem.getSellingPrice();
2428
            float margin = Math.max(0, sellingPrice - purchasePrice);
2429
            float taxableMargin = margin / (1 + totalTaxRate / 100);
2430
 
2431
            customFofoOrderItem.setMarginScheme(true);
2432
            customFofoOrderItem.setPurchasePrice(purchasePrice);
2433
            customFofoOrderItem.setSellingPrice(sellingPrice);
2434
            customFofoOrderItem.setMargin(margin);
2435
            customFofoOrderItem.setRate(sellingPrice);
2436
            customFofoOrderItem.setDiscount(0);
2437
            customFofoOrderItem.setAmount(taxableMargin * customerReturnItems.size());
2438
        } else {
2439
            float taxableSellingPrice = fofoOrderItem.getSellingPrice() / (1 + totalTaxRate / 100);
2440
            float taxableDiscountPrice = fofoOrderItem.getDiscount() / (1 + totalTaxRate / 100);
2441
            customFofoOrderItem.setAmount(customerReturnItems.size() * (taxableSellingPrice - taxableDiscountPrice));
2442
            customFofoOrderItem.setRate(taxableSellingPrice);
2443
            customFofoOrderItem.setDiscount(taxableDiscountPrice);
2444
        }
2445
 
32145 tejbeer 2446
        customFofoOrderItem.setQuantity(customerReturnItems.size());
2447
        customFofoOrderItem.setNetAmount(
2448
                (fofoOrderItem.getSellingPrice() - fofoOrderItem.getDiscount()) * customFofoOrderItem.getQuantity());
29707 tejbeer 2449
 
32145 tejbeer 2450
        float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
2451
        float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
2452
        float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
2453
        LOGGER.info("fofoOrderItem - {}", fofoOrderItem);
2454
        customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
2455
        customFofoOrderItem.setIgstAmount(igstAmount);
2456
        customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
2457
        customFofoOrderItem.setCgstAmount(cgstAmount);
2458
        customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
2459
        customFofoOrderItem.setSgstAmount(sgstAmount);
2460
        customFofoOrderItem.setHsnCode(fofoOrderItem.getHsnCode());
2461
        customFofoOrderItem.setOrderId(1);
2462
        customerFofoOrderItems.add(customFofoOrderItem);
29707 tejbeer 2463
 
32145 tejbeer 2464
        InvoicePdfModel pdfModel = new InvoicePdfModel();
2465
        pdfModel.setAuther("NSSPL");
2466
        pdfModel.setCustomer(customCustomer);
2467
        pdfModel.setInvoiceNumber(fofoOrder.getInvoiceNumber());
2468
        pdfModel.setInvoiceDate(FormattingUtils.formatDate(fofoOrder.getCreateTimestamp()));
2469
        pdfModel.setTitle("Credit Note");
2470
        pdfModel.setRetailer(customRetailer);
2471
        pdfModel.setTotalAmount(customFofoOrderItem.getNetAmount());
2472
        pdfModel.setOrderItems(customerFofoOrderItems);
35695 amit 2473
        pdfModel.setHasMarginSchemeItems(isMarginItem);
29707 tejbeer 2474
 
37067 amit 2475
        // State codes (were unset, so the note printed "Code: null"). Partner = supplier, customer = buyer.
2476
        pdfModel.setPartnerAddressStateCode(
2477
                stateRepository.selectByName(customRetailer.getAddress().getState()).getCode());
2478
        if (customCustomer.getAddress() != null && customCustomer.getAddress().getState() != null
2479
                && !customCustomer.getAddress().getState().trim().isEmpty()) {
2480
            pdfModel.setCustomerAddressStateCode(
2481
                    stateRepository.selectByName(customCustomer.getAddress().getState()).getCode());
2482
        }
2483
 
32145 tejbeer 2484
        CreditNotePdfModel creditNotePdfModel = new CreditNotePdfModel();
2485
        creditNotePdfModel.setCreditNoteDate(FormattingUtils.formatDate(creditNote.getCreateTimestamp()));
2486
        creditNotePdfModel.setCreditNoteNumber(creditNote.getCreditNoteNumber());
2487
        creditNotePdfModel.setPdfModel(pdfModel);
2488
        return creditNotePdfModel;
2489
    }
24264 amit.gupta 2490
 
32145 tejbeer 2491
    // This will remove the order and maintain order record and reverse inventory
2492
    // and scheme
2493
    @Override
2494
    public void cancelOrder(List<String> invoiceNumbers) throws ProfitMandiBusinessException {
2495
        for (String invoiceNumber : invoiceNumbers) {
2496
            // Cancel only when not cancelled
2497
            FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
2498
            if (fofoOrder.getCancelledTimestamp() == null) {
2499
                fofoOrder.setCancelledTimestamp(LocalDateTime.now());
36305 amit 2500
                partnerInvestmentService.evictInvestmentCache(fofoOrder.getFofoId());
32145 tejbeer 2501
                PaymentOptionTransaction paymentTransaction = new PaymentOptionTransaction();
2502
                paymentTransaction.setAmount(-fofoOrder.getTotalAmount());
2503
                paymentTransaction.setFofoId(fofoOrder.getFofoId());
2504
                paymentTransaction.setReferenceId(fofoOrder.getId());
2505
                paymentTransaction.setReferenceType(PaymentOptionReferenceType.ORDER);
2506
                paymentTransaction.setPaymentOptionId(1);
2507
                paymentOptionTransactionRepository.persist(paymentTransaction);
31030 amit.gupta 2508
 
32145 tejbeer 2509
                List<FofoOrderItem> fois = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
2510
                if (fois.size() > 0) {
2511
                    List<InventoryItem> inventoryItems = new ArrayList<>();
2512
                    fois.stream().forEach(x -> {
2513
                        x.getFofoLineItems().stream().forEach(y -> {
2514
                            inventoryService.rollbackInventory(y.getInventoryItemId(), y.getQuantity(), fofoOrder.getFofoId());
2515
                            inventoryItems.add(inventoryItemRepository.selectById(y.getInventoryItemId()));
2516
                        });
2517
                    });
2518
                    // if(invoice)
2519
                    this.reverseScheme(fofoOrder);
2520
                }
2521
                insuranceService.cancelInsurance(fofoOrder);
2522
            }
2523
        }
2524
    }
31030 amit.gupta 2525
 
32145 tejbeer 2526
    @Override
2527
    public void reverseScheme(FofoOrder fofoOrder) throws ProfitMandiBusinessException {
2528
        String reversalReason = "Order Rolledback/Cancelled/Returned for Invoice #" + fofoOrder.getInvoiceNumber();
2529
        List<FofoOrderItem> fois = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
2530
        Set<Integer> inventoryItemIds = fois.stream().flatMap(x -> x.getFofoLineItems().stream().map(y -> y.getInventoryItemId())).collect(Collectors.toSet());
2531
        List<InventoryItem> inventoryItems = inventoryItemRepository.selectByIds(inventoryItemIds);
34486 amit.gupta 2532
        schemeService.reverseSchemes(inventoryItems, fofoOrder.getId(), reversalReason, SchemeType.OUT_SCHEME_TYPES);
34504 amit.gupta 2533
        //schemeService.reverseSchemes(inventoryItems, fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.INVESTMENT));
32145 tejbeer 2534
        schemeService.reverseSchemes(inventoryItems, fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.SPECIAL_SUPPORT));
31030 amit.gupta 2535
 
32145 tejbeer 2536
    }
24271 amit.gupta 2537
 
32145 tejbeer 2538
    @Override
2539
    public void reverseActivationScheme(List<Integer> inventoryItemIds) throws ProfitMandiBusinessException {
2540
        List<InventoryItem> inventoryItems = inventoryItemRepository.selectAllByIds(inventoryItemIds);
2541
        for (InventoryItem inventoryItem : inventoryItems) {
2542
            List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByInventoryItemId(inventoryItem.getId());
2543
            FofoLineItem fofoLineItem = fofoLineItems.get(0);
2544
            FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(fofoLineItem.getFofoOrderItemId());
2545
            FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(fofoOrderItem.getOrderId());
2546
            String reversalReason = "Scheme rolled back as activation date is invalid for imei " + inventoryItem.getSerialNumber();
34319 amit.gupta 2547
            //schemeService.reverseSchemes(Arrays.asList(inventoryItem), fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.ACTIVATION));
32145 tejbeer 2548
            schemeService.reverseSchemes(Arrays.asList(inventoryItem), fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.SPECIAL_SUPPORT));
27083 amit.gupta 2549
 
32145 tejbeer 2550
        }
24271 amit.gupta 2551
 
32145 tejbeer 2552
    }
24271 amit.gupta 2553
 
32145 tejbeer 2554
    @Override
2555
    public float getSales(int fofoId, LocalDateTime startDate, LocalDateTime endDate) {
2556
        Float sales = fofoOrderRepository.selectSaleSumGroupByFofoIds(startDate, endDate).get(fofoId);
2557
        return sales == null ? 0f : sales;
2558
    }
24271 amit.gupta 2559
 
32145 tejbeer 2560
    @Override
2561
    public LocalDateTime getMaxSalesDate(int fofoId, LocalDateTime startDate, LocalDateTime endDate) {
2562
        LocalDateTime dateTime = fofoOrderRepository.selectMaxSaleDateGroupByFofoIds(startDate, endDate).get(fofoId);
2563
        return dateTime;
2564
    }
25101 amit.gupta 2565
 
32145 tejbeer 2566
    @Override
2567
    // Only being used internally
2568
    public float getSales(int fofoId, LocalDate onDate) {
2569
        LocalDateTime startTime = LocalDateTime.of(onDate, LocalTime.MIDNIGHT);
2570
        LocalDateTime endTime = LocalDateTime.of(onDate, LocalTime.MIDNIGHT).plusDays(1);
2571
        return this.getSales(fofoId, startTime, endTime);
2572
    }
24917 tejbeer 2573
 
32145 tejbeer 2574
    @Override
2575
    public float getSales(LocalDateTime onDate) {
2576
        // TODO Auto-generated method stub
2577
        return 0;
2578
    }
28166 tejbeer 2579
 
32145 tejbeer 2580
    @Override
2581
    public float getSales(LocalDateTime startDate, LocalDateTime endDate) {
2582
        // TODO Auto-generated method stub
2583
        return 0;
2584
    }
28166 tejbeer 2585
 
32145 tejbeer 2586
    @Override
36305 amit 2587
    public boolean applyColorChange(int orderId, int itemId) throws ProfitMandiBusinessException {
32145 tejbeer 2588
        Order order = orderRepository.selectById(orderId);
2589
        saholicInventoryService.reservationCountByColor(itemId, order);
28166 tejbeer 2590
 
32145 tejbeer 2591
        order.getLineItem().setItemId(itemId);
2592
        Item item = itemRepository.selectById(itemId);
2593
        order.getLineItem().setColor(item.getColor());
2594
        return true;
2595
    }
28166 tejbeer 2596
 
32145 tejbeer 2597
    @Override
2598
    public FofoOrder getOrderByInventoryItemId(int inventoryItemId) throws Exception {
2599
        List<FofoLineItem> lineItems = fofoLineItemRepository.selectByInventoryItemId(inventoryItemId);
2600
        if (lineItems.size() > 0) {
2601
            FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(lineItems.get(0).getFofoOrderItemId());
2602
            fofoOrderItem.setFofoLineItems(new HashSet<>(lineItems));
2603
            FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(fofoOrderItem.getOrderId());
2604
            fofoOrder.setOrderItem(fofoOrderItem);
2605
            return fofoOrder;
2606
        } else {
2607
            throw new Exception(String.format("Could not find inventoryItemId - %s", inventoryItemId));
2608
        }
2609
    }
28166 tejbeer 2610
 
32145 tejbeer 2611
    @Override
2612
    public Map<Integer, Long> carryBagCreditCount(int fofoId) throws ProfitMandiBusinessException {
28166 tejbeer 2613
 
32145 tejbeer 2614
        FofoStore fs = fofoStoreRepository.selectByRetailerId(fofoId);
2615
        LocalDateTime lastCredit = fs.getBagsLastCredited();
2616
        /*
2617
         * long carryBagCount = 0; List<FofoOrder> fofoOrders =
2618
         * fofoOrderRepository.selectByFofoIdBetweenCreatedTimeStamp(fofoId,
2619
         * lastCredit.atStartOfDay(), LocalDate.now().plusDays(1).atStartOfDay()); for
2620
         * (FofoOrder fo : fofoOrders) { carryBagCount +=
2621
         * fofoOrderItemRepository.selectByOrderId(fo.getId()).stream() .filter(x ->
2622
         * x.getSellingPrice() >= 12000).count();
2623
         *
2624
         * }
2625
         */
28166 tejbeer 2626
 
32145 tejbeer 2627
        Session session = sessionFactory.getCurrentSession();
2628
        CriteriaBuilder cb = session.getCriteriaBuilder();
2629
 
2630
        CriteriaQuery<SimpleEntry> query = cb.createQuery(SimpleEntry.class);
2631
        Root<FofoOrder> fofoOrder = query.from(FofoOrder.class);
2632
        Root<FofoOrderItem> fofoOrderItem = query.from(FofoOrderItem.class);
2633
        Root<TagListing> tagListingRoot = query.from(TagListing.class);
2634
        Root<Item> itemRoot = query.from(Item.class);
2635
 
2636
        Predicate p2 = cb.between(fofoOrder.get(ProfitMandiConstants.CREATE_TIMESTAMP), lastCredit, LocalDate.now().atStartOfDay());
2637
        Predicate p3 = cb.isNull(fofoOrder.get("cancelledTimestamp"));
2638
        Predicate joinPredicate = cb.and(
2639
                cb.equal(fofoOrder.get(ProfitMandiConstants.ID), fofoOrderItem.get(ProfitMandiConstants.ORDER_ID)), cb.equal(fofoOrderItem.get("itemId"), tagListingRoot.get("itemId")), cb.equal(itemRoot.get("id"), tagListingRoot.get("itemId")), cb.equal(fofoOrder.get(ProfitMandiConstants.FOFO_ID), fofoId));
2640
        ItemCriteria itemCriteria = new ItemCriteria();
35236 amit 2641
        itemCriteria.setBrands(brandsService.getBrands(fofoId, null, 3).stream().map(x -> x.getName()).collect(Collectors.toList()));
32145 tejbeer 2642
        float startValue = 12000;
2643
        itemCriteria.setStartPrice(startValue);
2644
        itemCriteria.setEndPrice(0);
2645
        itemCriteria.setFeaturedPhone(false);
2646
        itemCriteria.setSmartPhone(true);
2647
        itemCriteria.setCatalogIds(new ArrayList<>());
2648
        itemCriteria.setExcludeCatalogIds(new ArrayList<>());
2649
        Predicate itemPredicate = itemRepository.getItemPredicate(itemCriteria, cb, itemRoot, tagListingRoot.get("itemId"), tagListingRoot.get("sellingPrice"));
2650
        Predicate finalPredicate = cb.and(itemPredicate, p2, p3, joinPredicate);
2651
        query = query.multiselect(fofoOrder.get(ProfitMandiConstants.FOFO_ID), cb.count(fofoOrder)).where(finalPredicate).groupBy(fofoOrder.get(ProfitMandiConstants.FOFO_ID));
2652
        List<SimpleEntry> simpleEntries = session.createQuery(query).getResultList();
2653
        Map<Integer, Long> returnMap = new HashMap<>();
2654
 
2655
        for (SimpleEntry simpleEntry : simpleEntries) {
2656
            returnMap.put((Integer) simpleEntry.getKey(), (Long) simpleEntry.getValue());
2657
        }
2658
        return returnMap;
2659
 
2660
    }
32607 ranu 2661
 
2662
    @Override
2663
    public void createMissingScratchOffers() {
2664
        List<FofoOrder> fofoOrders = fofoOrderRepository.selectFromSaleDate(LocalDate.of(2023, 11, 6).atStartOfDay());
2665
        for (FofoOrder fofoOrder : fofoOrders) {
2666
            if (fofoOrder.getCancelledTimestamp() == null) { // Check if cancelled_timestamp is not null
2667
                try {
2668
                    this.createScratchOffer(fofoOrder.getFofoId(), fofoOrder.getInvoiceNumber(), fofoOrder.getCustomerId());
2669
                } catch (Exception e) {
2670
                    LOGGER.error("Error while processing missing scratch offer invoice orderId", fofoOrder.getId());
2671
                }
2672
            }
2673
        }
2674
    }
32724 amit.gupta 2675
 
2676
    @Override
33665 ranu 2677
    public boolean refundOrder(int orderId, String refundedBy, String refundReason) throws
2678
            ProfitMandiBusinessException {
32724 amit.gupta 2679
        /*def refund_order(order_id, refunded_by, reason):
2680
        """
2681
        If the order is in RTO_RECEIVED_PRESTINE, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
2682
            1. Creates a refund request for batch processing.
2683
            2. Creates a return order for the warehouse executive to return the shipped material.
2684
            3. Marks the current order as RTO_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
2685
 
2686
        If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
2687
            1. Creates a refund request for batch processing.
2688
            2. Cancels the reservation of the item in the warehouse.
2689
            3. Marks the current order as the REFUNDED final state.
2690
 
2691
        For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
2692
            1. Cancels the reservation of the item in the warehouse.
2693
            2. Marks the current order as CANCELED.
2694
 
2695
        In all cases, it updates the reason for cancellation or refund and the person who performed the action.
2696
 
2697
        Returns True if it is successful, False otherwise.
2698
 
2699
        Throws an exception if the order with the given id couldn't be found.
2700
 
2701
        Parameters:
2702
         - order_id
2703
         - refunded_by
2704
         - reason
2705
        """
2706
        LOGGER.info("Refunding order id: {}", orderId);
2707
        Order order = orderRepository.selectById(orderId);
2708
 
2709
        if order.cod:
2710
        logging.info("Refunding COD order with status " + str(order.status))
2711
        status_transition = refund_status_transition
2712
        if order.status not in status_transition.keys():
2713
        raise TransactionServiceException(114, "This order can't be refunded")
2714
 
2715
        if order.status in [OrderStatus.COD_VERIFICATION_PENDING, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT, OrderStatus.ACCEPTED]:
2716
        __update_inventory_reservation(order, refund=True)
2717
        order.statusDescription = "Order Cancelled"
2718
            #Shipment Id and Airway Bill No should be none in case of Cancellation
2719
        order.logisticsTransactionId = None
2720
        order.tracking_id = None
2721
        order.airwaybill_no = None
2722
        elif order.status == OrderStatus.BILLED:
2723
        __create_return_order(order)
2724
        order.statusDescription = "Order Cancelled"
2725
        elif order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT]:
2726
        if order.status != OrderStatus.RTO_LOST_IN_TRANSIT:
2727
        __create_return_order(order)
2728
        order.statusDescription = "RTO Refunded"
2729
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
2730
            #__create_return_order(order)
2731
        order.statusDescription = "Lost in Transit Refunded"
2732
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
2733
        if order.status != OrderStatus.DOA_LOST_IN_TRANSIT:
2734
        __create_return_order(order)
2735
        __create_refund(order, 0, 'Should be unreachable for now')
2736
        order.statusDescription = "DOA Refunded"
2737
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
2738
        if order.status != OrderStatus.RET_LOST_IN_TRANSIT:
2739
        __create_return_order(order)
2740
        __create_refund(order, 0, 'Should be unreachable for now')
2741
        order.statusDescription = "Return Refunded"
2742
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
2743
        if order.previousStatus in [OrderStatus.COD_VERIFICATION_PENDING, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT, OrderStatus.ACCEPTED]:
2744
        __update_inventory_reservation(order, refund=True)
2745
        order.statusDescription = "Order Cancelled on customer request"
2746
        elif order.previousStatus == OrderStatus.BILLED:
2747
        __create_return_order(order)
2748
        order.statusDescription = "Order Cancelled on customer request"
2749
        order.received_return_timestamp = datetime.datetime.now()
2750
    else:
2751
        status_transition = {OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
2752
                OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
2753
                OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
2754
                OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
2755
                OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
2756
                OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
2757
                OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
2758
                OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
2759
                OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
2760
                OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
2761
                OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
2762
                OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
2763
                OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2764
                OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2765
                OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2766
                OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2767
                OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2768
                OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2769
                OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2770
                OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST,
2771
                OrderStatus.PAYMENT_FLAGGED : OrderStatus.PAYMENT_FLAGGED_DENIED
2772
                     }
2773
        if order.status not in status_transition.keys():
2774
        raise TransactionServiceException(114, "This order can't be refunded")
2775
 
2776
        if order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT] :
2777
        if order.status != OrderStatus.RTO_LOST_IN_TRANSIT:
2778
        __create_return_order(order)
2779
        __create_refund(order, order.wallet_amount, 'Order #{0} is RTO refunded'.format(order.id))
2780
        order.statusDescription = "RTO Refunded"
2781
            #Start:- Added By Manish Sharma for Creating a new Ticket: Category- RTO Refund on 21-Jun-2013
2782
        try:
2783
        crmServiceClient = CRMClient().get_client()
2784
        ticket =Ticket()
2785
        activity = Activity()
2786
 
2787
        description = "Creating Ticket for " + order.statusDescription + " Order"
2788
        ticket.creatorId = 1
2789
        ticket.assigneeId = 34
2790
        ticket.category = TicketCategory.RTO_REFUND
2791
        ticket.priority = TicketPriority.MEDIUM
2792
        ticket.status = TicketStatus.OPEN
2793
        ticket.description = description
2794
        ticket.orderId = order.id
2795
 
2796
        activity.creatorId = 1
2797
        activity.ticketAssigneeId = ticket.assigneeId
2798
        activity.type = ActivityType.OTHER
2799
        activity.description = description
2800
        activity.ticketCategory = ticket.category
2801
        activity.ticketDescription = ticket.description
2802
        activity.ticketPriority = ticket.priority
2803
        activity.ticketStatus = ticket.status
2804
 
2805
        ticket.customerId= order.customer_id
2806
        ticket.customerEmailId = order.customer_email
2807
        ticket.customerMobileNumber = order.customer_mobilenumber
2808
        ticket.customerName = order.customer_name
2809
        activity.customerId = ticket.customerId
2810
        activity.customerEmailId = order.customer_email
2811
        activity.customerMobileNumber = order.customer_mobilenumber
2812
        activity.customerName = order.customer_name
2813
 
2814
        crmServiceClient.insertTicket(ticket, activity)
2815
 
2816
        except:
2817
        print "Ticket for RTO Refund is not created."
2818
            #End:- Added By Manish Sharma for Creating a new Ticket: Category- RTO Refund on 21-Jun-2013
2819
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
2820
            #__create_return_order(order)
2821
        __create_refund(order, order.wallet_amount, 'Order #{0} is Lost in Transit'.format(order.id))
2822
        order.statusDescription = "Lost in Transit Refunded"
2823
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
2824
        if order.status != OrderStatus.DOA_LOST_IN_TRANSIT:
2825
        __create_return_order(order)
2826
        __create_refund(order, 0, 'This should be unreachable')
2827
        order.statusDescription = "DOA Refunded"
2828
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
2829
        if order.status != OrderStatus.RET_LOST_IN_TRANSIT:
2830
        __create_return_order(order)
2831
        __create_refund(order, 0, 'This should be unreachable')
2832
        order.statusDescription = "Return Refunded"
2833
        elif order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT, OrderStatus.ACCEPTED]:
2834
        __update_inventory_reservation(order, refund=True)
2835
        order.statusDescription = "Order Refunded"
2836
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
2837
        if order.previousStatus in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT, OrderStatus.PAYMENT_FLAGGED, OrderStatus.ACCEPTED]:
2838
        __update_inventory_reservation(order, refund=True)
2839
        order.statusDescription = "Order Cancelled on customer request"
2840
        elif order.previousStatus == OrderStatus.BILLED:
2841
        __create_refund(order, order.wallet_amount,  'Order #{0} Cancelled on customer request'.format(order.id))
2842
        order.statusDescription = "Order Cancelled on customer request"
2843
 
2844
        elif order.status == OrderStatus.PAYMENT_FLAGGED:
2845
        __update_inventory_reservation(order, refund=True)
2846
        order.statusDescription = "Order Cancelled due to payment flagged"
2847
 
2848
    # For orders that are cancelled after being billed, we need to scan in the scanned out
2849
    # inventory item and change availability accordingly
2850
        inventoryClient = InventoryClient().get_client()
2851
        warehouse = inventoryClient.getWarehouse(order.warehouse_id)
2852
        if warehouse.billingType == BillingType.OURS or warehouse.billingType == BillingType.OURS_EXTERNAL:
2853
        #Now BILLED orders can also be refunded directly with low inventory cancellations
2854
        if order.status in [OrderStatus.BILLED, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_FROM_WH]:
2855
        __create_refund(order, order.wallet_amount, reason)
2856
        if order.status in [OrderStatus.BILLED, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_FROM_WH] or (order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED and order.previousStatus in [OrderStatus.BILLED, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_FROM_WH]):
2857
        lineitem = order.lineitems[0]
2858
        catalogClient = CatalogClient().get_client()
2859
        item = catalogClient.getItem(lineitem.item_id)
2860
        warehouseClient = WarehouseClient().get_client()
2861
        if warehouse.billingType == BillingType.OURS:
2862
        if ItemType.SERIALIZED == item.type:
2863
        for serial_number in str(lineitem.serial_number).split(','):
2864
        warehouseClient.scanSerializedItemForOrder(serial_number, ScanType.SALE_RET, order.id, order.fulfilmentWarehouseId, 1, order.warehouse_id)
2865
                else:
2866
        warehouseClient.scanForOrder(None, ScanType.SALE_RET, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
2867
        if warehouse.billingType == BillingType.OURS_EXTERNAL:
2868
        warehouseClient.scanForOursExternalSaleReturn(order.id, lineitem.transfer_price)
2869
        if order.freebieItemId:
2870
        warehouseClient.scanfreebie(order.id, order.freebieItemId, 0, ScanType.SALE_RET)
2871
 
2872
        order.status = status_transition[order.status]
2873
        order.statusDescription = OrderStatus._VALUES_TO_NAMES[order.status]
2874
        order.refund_timestamp = datetime.datetime.now()
2875
        order.refunded_by = refunded_by
2876
        order.refund_reason = reason
2877
    #to re evaluate the shipping charge if any order is being cancelled.
2878
    #_revaluate_shiping(order_id)
2879
        session.commit()
2880
        return True*/
2881
        return true;
2882
    }
2883
 
2884
    @Autowired
2885
    DebitNoteRepository debitNoteRepository;
2886
 
2887
    //initiate refund only if the stock is returned
2888
 
25724 amit.gupta 2889
}