Subversion Repositories SmartDukaan

Rev

Rev 37102 | 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());
37398 amit 1443
        pdfModel.setInsurancePolicies(InsuranceInvoiceLine.from(insurancePolicies));
24275 amit.gupta 1444
 
32145 tejbeer 1445
        Retailer retailer = retailerRepository.selectById(fofoOrder.getFofoId());
1446
        User user = userRepository.selectById(userAccountRepository.selectUserIdByRetailerId(retailer.getId()));
35896 amit 1447
        FofoStore fofoStoreForGst = fofoStoreRepository.selectByRetailerId(retailer.getId());
32145 tejbeer 1448
        CustomRetailer customRetailer = new CustomRetailer();
1449
        customRetailer.setBusinessName(retailer.getName());
1450
        customRetailer.setMobileNumber(user.getMobileNumber());
35896 amit 1451
        customRetailer.setGstNumber(fofoStoreForGst != null ? fofoStoreForGst.getGstNumber() : null);
32145 tejbeer 1452
        Address retailerAddress = addressRepository.selectById(retailerRegisteredAddressRepository.selectAddressIdByRetailerId(retailer.getId()));
1453
        customRetailer.setAddress(this.createCustomAddress(retailerAddress));
1454
        pdfModel.setRetailer(customRetailer);
23650 amit.gupta 1455
 
33089 amit.gupta 1456
        pdfModel.setCustomer(getCustomCustomer(fofoOrder, customRetailer.getAddress()));
1457
        pdfModel.setInvoiceNumber(fofoOrder.getInvoiceNumber());
1458
        pdfModel.setTotalAmount(fofoOrder.getTotalAmount());
1459
 
1460
 
35695 amit 1461
        List<CustomOrderItem> regularFofoItems = new ArrayList<>();
1462
        List<CustomOrderItem> marginSchemeFofoItems = new ArrayList<>();
1463
        boolean hasMarginSchemeItems = false;
32145 tejbeer 1464
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1465
            float discount = fofoOrderItem.getDiscount();
1466
            CustomOrderItem customFofoOrderItem = new CustomOrderItem();
1467
            float totalTaxRate = fofoOrderItem.getIgstRate() + fofoOrderItem.getSgstRate() + fofoOrderItem.getCgstRate();
23650 amit.gupta 1468
 
32145 tejbeer 1469
            customFofoOrderItem.setDescription(fofoOrderItem.getBrand() + " " + fofoOrderItem.getModelName() + " " + fofoOrderItem.getModelNumber() + "-" + fofoOrderItem.getColor());
1470
            Set<String> serialNumbers = this.toSerialNumbers(fofoOrderItem.getFofoLineItems());
32816 ranu 1471
            List<FofoNonSerializeSerial> nonSerializeSerials = fofoNonSerializeSerialRepository.selectByItemIdAndOrderId(fofoOrderItem.getId());
1472
            List<String> customSerialNumbers = nonSerializeSerials.stream().map(FofoNonSerializeSerial::getSerialNumber).collect(Collectors.toList());
1473
            LOGGER.info("nonSerializeSerials {}", nonSerializeSerials);
32145 tejbeer 1474
            if (!serialNumbers.isEmpty()) {
1475
                customFofoOrderItem.setDescription(
1476
                        customFofoOrderItem.getDescription() + "\n IMEIS - " + String.join(", ", serialNumbers));
1477
            }
32816 ranu 1478
            if (!customSerialNumbers.isEmpty()) {
1479
                customFofoOrderItem.setDescription(
1480
                        customFofoOrderItem.getDescription() + "\n SerialNumber - " + String.join(", ", customSerialNumbers));
1481
            }
32145 tejbeer 1482
            customFofoOrderItem.setQuantity(fofoOrderItem.getQuantity());
1483
            customFofoOrderItem.setHsnCode(fofoOrderItem.getHsnCode());
35695 amit 1484
 
1485
            // Check if this is a margin scheme item
1486
            boolean isMarginItem = false;
1487
            try {
1488
                Item item = itemRepository.selectById(fofoOrderItem.getItemId());
1489
                Category category = categoryRepository.selectById(item.getCategoryId());
1490
                isMarginItem = category.isMarginOnly() && !serialNumbers.isEmpty();
1491
            } catch (Exception e) {
1492
                LOGGER.warn("Could not check margin scheme for fofo order item {}", fofoOrderItem.getId(), e);
1493
            }
1494
 
1495
            if (isMarginItem) {
1496
                // Margin Scheme: GST on margin only
1497
                // Purchase price = what FOFO paid (from fofo.inventory_item.unitPrice)
1498
                float purchasePrice = getFofoPurchasePrice(serialNumbers.iterator().next(), fofoOrder.getFofoId());
1499
                float sellingPrice = fofoOrderItem.getSellingPrice();
1500
                float margin = Math.max(0, sellingPrice - purchasePrice);
1501
                float taxableMargin = margin / (1 + totalTaxRate / 100);
1502
 
1503
                customFofoOrderItem.setMarginScheme(true);
1504
                customFofoOrderItem.setPurchasePrice(purchasePrice);
1505
                customFofoOrderItem.setSellingPrice(sellingPrice);
1506
                customFofoOrderItem.setMargin(margin);
1507
                customFofoOrderItem.setRate(sellingPrice);
1508
                customFofoOrderItem.setDiscount(0);
1509
                customFofoOrderItem.setAmount(taxableMargin * fofoOrderItem.getQuantity());
1510
                customFofoOrderItem.setNetAmount(fofoOrderItem.getSellingPrice() * fofoOrderItem.getQuantity());
1511
 
1512
                float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
1513
                float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
1514
                float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
1515
                customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
1516
                customFofoOrderItem.setIgstAmount(igstAmount);
1517
                customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
1518
                customFofoOrderItem.setCgstAmount(cgstAmount);
1519
                customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
1520
                customFofoOrderItem.setSgstAmount(sgstAmount);
1521
 
1522
                marginSchemeFofoItems.add(customFofoOrderItem);
1523
                hasMarginSchemeItems = true;
1524
            } else {
1525
                // Regular: GST on full selling price
1526
                float taxableSellingPrice = (fofoOrderItem.getSellingPrice() + discount) / (1 + totalTaxRate / 100);
1527
                float taxableDiscountPrice = discount / (1 + totalTaxRate / 100);
1528
 
1529
                customFofoOrderItem.setAmount(fofoOrderItem.getQuantity() * (taxableSellingPrice - taxableDiscountPrice));
1530
                customFofoOrderItem.setRate(taxableSellingPrice);
1531
                customFofoOrderItem.setDiscount(taxableDiscountPrice);
1532
                customFofoOrderItem.setNetAmount(fofoOrderItem.getSellingPrice() * fofoOrderItem.getQuantity());
1533
 
1534
                float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
1535
                float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
1536
                float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
1537
                customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
1538
                customFofoOrderItem.setIgstAmount(igstAmount);
1539
                customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
1540
                customFofoOrderItem.setCgstAmount(cgstAmount);
1541
                customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
1542
                customFofoOrderItem.setSgstAmount(sgstAmount);
1543
 
1544
                regularFofoItems.add(customFofoOrderItem);
1545
            }
32145 tejbeer 1546
        }
35695 amit 1547
        // Regular items first, then margin scheme items
1548
        List<CustomOrderItem> customerFofoOrderItems = new ArrayList<>(regularFofoItems);
1549
        customerFofoOrderItems.addAll(marginSchemeFofoItems);
32145 tejbeer 1550
        pdfModel.setOrderItems(customerFofoOrderItems);
35695 amit 1551
        pdfModel.setHasMarginSchemeItems(hasMarginSchemeItems);
1552
        if (hasMarginSchemeItems) {
1553
            List<String> declarations = new ArrayList<>();
1554
            declarations.add("Items marked under Margin Scheme are taxed under Rule 32(5) of CGST Rules, 2017.");
1555
            declarations.add("GST is charged on the margin (Selling Price - Purchase Price) and not on the full value of supply.");
1556
            declarations.add("Input Tax Credit is not available on margin scheme items.");
1557
            pdfModel.setMarginSchemeDeclarations(declarations);
1558
        }
32627 ranu 1559
        String customerAddressStateCode = "";
32145 tejbeer 1560
        String partnerAddressStateCode = stateRepository.selectByName(pdfModel.getRetailer().getAddress().getState()).getCode();
32627 ranu 1561
        if (pdfModel.getCustomer() != null && pdfModel.getCustomer().getAddress() != null &&
1562
                pdfModel.getCustomer().getAddress().getState() != null &&
1563
                !pdfModel.getCustomer().getAddress().getState().trim().isEmpty()) {
1564
            customerAddressStateCode = stateRepository.selectByName(pdfModel.getCustomer().getAddress().getState()).getCode();
1565
        }
1566
 
32145 tejbeer 1567
        pdfModel.setPartnerAddressStateCode(partnerAddressStateCode);
32627 ranu 1568
        if (!customerAddressStateCode.equals("")) {
1569
            pdfModel.setCustomerAddressStateCode(customerAddressStateCode);
1570
        }
32145 tejbeer 1571
        pdfModel.setCancelled(fofoOrder.getCancelledTimestamp() != null);
1572
        List<String> tncs = new ArrayList<>();
34999 amit 1573
        tncs.add("I agree that goods received are in good working condition.");
1574
        tncs.add("Goods once sold cannot be exchanged or taken back.");
32145 tejbeer 1575
        tncs.add("Warranty for the goods received by me is the responsibility of the manufacturer only.");
1576
        if (pdfModel.getInsurancePolicies() != null && pdfModel.getInsurancePolicies().size() > 0) {
35000 amit 1577
            tncs.add("Extended Warranty/ Damage Protection related issues are to be handled directly by the respective providers.");
32145 tejbeer 1578
        }
1579
        pdfModel.setTncs(tncs);
1580
        return pdfModel;
23650 amit.gupta 1581
 
32145 tejbeer 1582
    }
23650 amit.gupta 1583
 
35695 amit 1584
    private float getFofoPurchasePrice(String serialNumber, int fofoId) {
1585
        try {
1586
            InventoryItem fofoInventoryItem = inventoryItemRepository.selectBySerialNumberFofoId(serialNumber, fofoId);
1587
            if (fofoInventoryItem != null) {
1588
                return fofoInventoryItem.getUnitPrice();
1589
            }
1590
        } catch (Exception e) {
1591
            LOGGER.error("Could not fetch FOFO purchase price for serial: {}, fofoId: {}", serialNumber, fofoId, e);
1592
        }
1593
        return 0;
1594
    }
1595
 
33665 ranu 1596
    private CustomCustomer getCustomCustomer(FofoOrder fofoOrder, CustomAddress retailerAddress) throws
1597
            ProfitMandiBusinessException {
32145 tejbeer 1598
        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
1599
        CustomCustomer customCustomer = new CustomCustomer();
1600
        customCustomer.setFirstName(customer.getFirstName());
1601
        customCustomer.setLastName(customer.getLastName());
1602
        customCustomer.setEmailId(customer.getEmailId());
1603
        customCustomer.setMobileNumber(customer.getMobileNumber());
1604
        customCustomer.setGstNumber(fofoOrder.getCustomerGstNumber());
32627 ranu 1605
        if (fofoOrder.getCustomerAddressId() != 0) {
1606
            CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
1607
            customCustomer.setAddress(this.createCustomAddress(customerAddress));
1608
        } else {
33089 amit.gupta 1609
 
1610
            customCustomer.setAddress(this.createCustomAddressWithoutId(customCustomer, retailerAddress));
32627 ranu 1611
        }
32145 tejbeer 1612
        return customCustomer;
32627 ranu 1613
 
32145 tejbeer 1614
    }
23655 amit.gupta 1615
 
32145 tejbeer 1616
    @Override
1617
    public InvoicePdfModel getInvoicePdfModel(int fofoId, int orderId) throws ProfitMandiBusinessException {
1618
        FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndOrderId(fofoId, orderId);
1619
        return this.getInvoicePdfModel(fofoOrder);
1620
    }
23650 amit.gupta 1621
 
32145 tejbeer 1622
    public String getBillingAddress(CustomerAddress customerAddress) {
1623
        StringBuilder address = new StringBuilder();
1624
        if ((customerAddress.getLine1() != null) && (!customerAddress.getLine1().isEmpty())) {
1625
            address.append(customerAddress.getLine1());
1626
            address.append(", ");
1627
        }
22859 ashik.ali 1628
 
32145 tejbeer 1629
        if ((customerAddress.getLine2() != null) && (!customerAddress.getLine2().isEmpty())) {
1630
            address.append(customerAddress.getLine2());
1631
            address.append(", ");
1632
        }
22859 ashik.ali 1633
 
32145 tejbeer 1634
        if ((customerAddress.getLandmark() != null) && (!customerAddress.getLandmark().isEmpty())) {
1635
            address.append(customerAddress.getLandmark());
1636
            address.append(", ");
1637
        }
22859 ashik.ali 1638
 
32145 tejbeer 1639
        if ((customerAddress.getCity() != null) && (!customerAddress.getCity().isEmpty())) {
1640
            address.append(customerAddress.getCity());
1641
            address.append(", ");
1642
        }
22859 ashik.ali 1643
 
32145 tejbeer 1644
        if ((customerAddress.getState() != null) && (!customerAddress.getState().isEmpty())) {
1645
            address.append(customerAddress.getState());
1646
        }
22859 ashik.ali 1647
 
32145 tejbeer 1648
        if ((customerAddress.getPinCode() != null) && (!customerAddress.getPinCode().isEmpty())) {
1649
            address.append("- ");
1650
            address.append(customerAddress.getPinCode());
1651
        }
22859 ashik.ali 1652
 
32145 tejbeer 1653
        return address.toString();
1654
    }
23650 amit.gupta 1655
 
32145 tejbeer 1656
    @Override
1657
    public List<CartFofo> cartCheckout(String cartJson) throws ProfitMandiBusinessException {
1658
        try {
1659
            JSONObject cartObject = new JSONObject(cartJson);
1660
            Iterator<?> keys = cartObject.keys();
23650 amit.gupta 1661
 
32145 tejbeer 1662
            Set<Integer> itemIds = new HashSet<>();
1663
            List<CartFofo> cartItems = new ArrayList<CartFofo>();
23650 amit.gupta 1664
 
32145 tejbeer 1665
            while (keys.hasNext()) {
1666
                String key = (String) keys.next();
1667
                if (cartObject.get(key) instanceof JSONObject) {
1668
                    LOGGER.info(cartObject.get(key).toString());
1669
                }
1670
                CartFofo cf = new CartFofo();
1671
                cf.setItemId(cartObject.getJSONObject(key).getInt("itemId"));
1672
                cf.setQuantity(cartObject.getJSONObject(key).getInt("quantity"));
1673
                if (cartObject.getJSONObject(key).has("poId")) {
23650 amit.gupta 1674
 
32145 tejbeer 1675
                    cf.setPoId(cartObject.getJSONObject(key).getInt("poId"));
1676
                    cf.setPoItemId(cartObject.getJSONObject(key).getInt("poItemId"));
1677
                }
1678
                if (cf.getQuantity() <= 0) {
1679
                    continue;
1680
                }
1681
                cartItems.add(cf);
1682
                itemIds.add(cartObject.getJSONObject(key).getInt("itemId"));
1683
            }
1684
            Map<Integer, Item> itemMap = new HashMap<Integer, Item>();
1685
            if (itemIds.size() > 0) {
1686
                List<Item> items = itemRepository.selectByIds(itemIds);
1687
                for (Item i : items) {
1688
                    itemMap.put(i.getId(), i);
1689
                }
23650 amit.gupta 1690
 
32145 tejbeer 1691
            }
1692
            for (CartFofo cf : cartItems) {
1693
                Item i = itemMap.get(cf.getItemId());
1694
                if (i == null) {
1695
                    continue;
1696
                }
1697
                cf.setDisplayName(getValidName(i.getBrand()) + " " + getValidName(i.getModelName()) + " " + getValidName(i.getModelNumber()) + " " + getValidName(i.getColor()).replaceAll("\\s+", " "));
1698
                cf.setItemType(i.getType());
1699
            }
1700
            return cartItems;
1701
        } catch (Exception e) {
1702
            LOGGER.error("Unable to Prepare cart to place order...", e);
1703
            throw new ProfitMandiBusinessException("cartData", cartJson, "FFORDR_1006");
1704
        }
1705
    }
23650 amit.gupta 1706
 
32145 tejbeer 1707
    @Override
33665 ranu 1708
    public Map<String, Object> getSaleHistory(int fofoId, SearchType searchType, String searchValue, LocalDateTime
1709
            startDate, LocalDateTime endDate, int offset, int limit) throws ProfitMandiBusinessException {
32145 tejbeer 1710
        long countItems = 0;
1711
        List<FofoOrder> fofoOrders = new ArrayList<>();
23650 amit.gupta 1712
 
32145 tejbeer 1713
        if (searchType == SearchType.CUSTOMER_MOBILE_NUMBER && !searchValue.isEmpty()) {
1714
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerMobileNumber(fofoId, searchValue, null, null, offset, limit);
1715
            countItems = fofoOrderRepository.selectCountByCustomerMobileNumber(fofoId, searchValue, null, null);
1716
        } else if (searchType == SearchType.CUSTOMER_NAME && !searchValue.isEmpty()) {
1717
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerName(fofoId, searchValue, null, null, offset, limit);
1718
            countItems = fofoOrderRepository.selectCountByCustomerName(fofoId, searchValue, null, null);
1719
        } else if (searchType == SearchType.IMEI && !searchValue.isEmpty()) {
1720
            fofoOrders = fofoOrderRepository.selectByFofoIdAndSerialNumber(fofoId, searchValue, null, null, offset, limit);
1721
            countItems = fofoOrderRepository.selectCountBySerialNumber(fofoId, searchValue, null, null);
1722
        } else if (searchType == SearchType.ITEM_NAME && !searchValue.isEmpty()) {
1723
            fofoOrders = fofoOrderRepository.selectByFofoIdAndItemName(fofoId, searchValue, null, null, offset, limit);
1724
            countItems = fofoOrderRepository.selectCountByItemName(fofoId, searchValue, null, null);
1725
        } else if (searchType == SearchType.INVOICE_NUMBER && !searchValue.isEmpty()) {
1726
            fofoOrders = Arrays.asList(fofoOrderRepository.selectByFofoIdAndInvoiceNumber(fofoId, searchValue));
1727
            countItems = fofoOrders.size();
1728
        } else if (searchType == SearchType.DATE_RANGE) {
1729
            fofoOrders = fofoOrderRepository.selectByFofoId(fofoId, startDate, endDate, offset, limit);
1730
            countItems = fofoOrderRepository.selectCountByFofoId(fofoId, startDate, endDate);
1731
        }
1732
        Map<String, Object> map = new HashMap<>();
23650 amit.gupta 1733
 
32145 tejbeer 1734
        map.put("saleHistories", fofoOrders);
1735
        map.put("start", offset + 1);
1736
        map.put("size", countItems);
1737
        map.put("searchType", searchType);
1738
        map.put("searchTypes", SearchType.values());
1739
        map.put("startDate", startDate);
1740
        map.put("searchValue", searchValue);
1741
        map.put(ProfitMandiConstants.END_TIME, endDate);
1742
        if (fofoOrders.size() < limit) {
1743
            map.put("end", offset + fofoOrders.size());
1744
        } else {
1745
            map.put("end", offset + limit);
1746
        }
1747
        return map;
1748
    }
30426 tejbeer 1749
 
33665 ranu 1750
    public ResponseEntity<?> downloadReportInCsv(org.apache.commons.io.output.ByteArrayOutputStream
1751
                                                         baos, List<List<?>> rows, String fileName) {
32145 tejbeer 1752
        final HttpHeaders headers = new HttpHeaders();
1753
        headers.set("Content-Type", "text/csv");
30426 tejbeer 1754
 
32145 tejbeer 1755
        headers.set("Content-disposition", "inline; filename=" + fileName + ".csv");
1756
        headers.setContentLength(baos.toByteArray().length);
23202 ashik.ali 1757
 
32145 tejbeer 1758
        final InputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
1759
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
30426 tejbeer 1760
 
33454 amit.gupta 1761
        return new ResponseEntity<>(inputStreamResource, headers, HttpStatus.OK);
32145 tejbeer 1762
    }
30157 manish 1763
 
32145 tejbeer 1764
    @Override
33665 ranu 1765
    public Map<String, Object> getSaleHistoryPaginated(int fofoId, SearchType searchType, String
1766
            searchValue, LocalDateTime startDate, LocalDateTime endDate, int offset, int limit) throws
1767
            ProfitMandiBusinessException {
32145 tejbeer 1768
        List<FofoOrder> fofoOrders = new ArrayList<>();
23650 amit.gupta 1769
 
32145 tejbeer 1770
        if (searchType == SearchType.CUSTOMER_MOBILE_NUMBER && !searchValue.isEmpty()) {
1771
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerMobileNumber(fofoId, searchValue, startDate, endDate, offset, limit);
1772
        } else if (searchType == SearchType.CUSTOMER_NAME && !searchValue.isEmpty()) {
1773
            fofoOrders = fofoOrderRepository.selectByFofoIdAndCustomerName(fofoId, searchValue, startDate, endDate, offset, limit);
1774
        } else if (searchType == SearchType.IMEI && !searchValue.isEmpty()) {
1775
            fofoOrders = fofoOrderRepository.selectByFofoIdAndSerialNumber(fofoId, searchValue, startDate, endDate, offset, limit);
1776
        } else if (searchType == SearchType.ITEM_NAME && !searchValue.isEmpty()) {
1777
            fofoOrders = fofoOrderRepository.selectByFofoIdAndItemName(fofoId, searchValue, startDate, endDate, offset, limit);
24275 amit.gupta 1778
 
32145 tejbeer 1779
        } else if (searchType == SearchType.DATE_RANGE) {
1780
            fofoOrders = fofoOrderRepository.selectByFofoId(fofoId, startDate, endDate, offset, limit);
1781
        }
1782
        Map<String, Object> map = new HashMap<>();
1783
        map.put("saleHistories", fofoOrders);
1784
        map.put("searchType", searchType);
1785
        map.put("searchTypes", SearchType.values());
1786
        map.put("startDate", startDate);
1787
        map.put("searchValue", searchValue);
1788
        map.put(ProfitMandiConstants.END_TIME, endDate);
1789
        return map;
1790
    }
23650 amit.gupta 1791
 
32145 tejbeer 1792
    private String getFofoStoreCode(int fofoId) throws ProfitMandiBusinessException {
1793
        FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(fofoId);
1794
        return fofoStore.getCode();
1795
    }
23650 amit.gupta 1796
 
32145 tejbeer 1797
    private String getValidName(String name) {
1798
        return name != null ? name : "";
1799
    }
23650 amit.gupta 1800
 
32145 tejbeer 1801
    private Set<String> toSerialNumbers(Set<FofoLineItem> fofoLineItems) {
1802
        Set<String> serialNumbers = new HashSet<>();
1803
        for (FofoLineItem fofoLineItem : fofoLineItems) {
1804
            if (fofoLineItem.getSerialNumber() != null && !fofoLineItem.getSerialNumber().isEmpty()) {
1805
                serialNumbers.add(fofoLineItem.getSerialNumber());
1806
            }
1807
        }
1808
        return serialNumbers;
1809
    }
23650 amit.gupta 1810
 
33520 amit.gupta 1811
    static final List<String> MOP_VOILATED_BRANDS = Arrays.asList("Live Demo", "Almost New");
1812
 
35733 amit 1813
    // DP price validation disabled as of 11 sep 2025 as per tarun sir
33665 ranu 1814
    private void validateDpPrice(int fofoId, Map<
1815
            Integer, PriceModel> itemIdMopPriceMap, Map<Integer, CustomFofoOrderItem> itemIdCustomFofoLineItemMap) throws
1816
            ProfitMandiBusinessException {
32145 tejbeer 1817
    }
24275 amit.gupta 1818
 
35733 amit 1819
    // MOP price validation disabled as of 11 sep 2025 as per tarun sir
33665 ranu 1820
    private void validateMopPrice(int fofoId, Map<
1821
            Integer, PriceModel> itemIdMopPriceMap, Map<Integer, CustomFofoOrderItem> itemIdCustomFofoLineItemMap) throws
1822
            ProfitMandiBusinessException {
32145 tejbeer 1823
    }
23650 amit.gupta 1824
 
33665 ranu 1825
    private void updateInventoryItemsAndScanRecord(Set<InventoryItem> inventoryItems, int fofoId, Map<
1826
            Integer, Integer> inventoryItemQuantityUsed, int fofoOrderId) {
32145 tejbeer 1827
        for (InventoryItem inventoryItem : inventoryItems) {
1828
            inventoryItem.setLastScanType(ScanType.SALE);
33087 amit.gupta 1829
            inventoryItem.setUpdateTimestamp(LocalDateTime.now());
32145 tejbeer 1830
            ScanRecord scanRecord = new ScanRecord();
1831
            scanRecord.setInventoryItemId(inventoryItem.getId());
1832
            scanRecord.setFofoId(fofoId);
1833
            scanRecord.setOrderId(fofoOrderId);
1834
            // correct this
1835
            scanRecord.setQuantity(inventoryItemQuantityUsed.get(inventoryItem.getId()));
1836
            scanRecord.setType(ScanType.SALE);
1837
            scanRecordRepository.persist(scanRecord);
1838
            purchaseReturnItemRepository.deleteById(inventoryItem.getId());
23650 amit.gupta 1839
 
32145 tejbeer 1840
        }
1841
    }
23650 amit.gupta 1842
 
33665 ranu 1843
    private void createFofoLineItem(int fofoOrderItemId, Set<
1844
            InventoryItem> inventoryItems, Map<Integer, Integer> inventoryItemIdQuantityUsed) {
32145 tejbeer 1845
        for (InventoryItem inventoryItem : inventoryItems) {
1846
            FofoLineItem fofoLineItem = new FofoLineItem();
1847
            fofoLineItem.setFofoOrderItemId(fofoOrderItemId);
1848
            fofoLineItem.setSerialNumber(inventoryItem.getSerialNumber());
1849
            fofoLineItem.setInventoryItemId(inventoryItem.getId());
1850
            fofoLineItem.setQuantity(inventoryItemIdQuantityUsed.get(inventoryItem.getId()));
1851
            fofoLineItemRepository.persist(fofoLineItem);
1852
        }
1853
    }
23650 amit.gupta 1854
 
33665 ranu 1855
    private FofoOrderItem createAndGetFofoOrderItem(CustomFofoOrderItem customFofoOrderItem, int fofoOrderId, Map<
35493 amit 1856
            Integer, Item> itemMap, Set<InventoryItem> inventoryItems, Map<Integer, TagListing> tagListingMap,
1857
            Map<Integer, GstRate> gstRateMap) throws ProfitMandiBusinessException {
32145 tejbeer 1858
        FofoOrderItem fofoOrderItem = new FofoOrderItem();
1859
        fofoOrderItem.setItemId(customFofoOrderItem.getItemId());
1860
        fofoOrderItem.setQuantity(customFofoOrderItem.getQuantity());
1861
        fofoOrderItem.setSellingPrice(customFofoOrderItem.getSellingPrice());
34381 vikas.jang 1862
        fofoOrderItem.setPendingOrderItemId(customFofoOrderItem.getPoiId());
32145 tejbeer 1863
        fofoOrderItem.setOrderId(fofoOrderId);
35493 amit 1864
 
1865
        // N+1 fix: Use pre-fetched tagListingMap instead of querying per item
1866
        TagListing tl = tagListingMap.get(customFofoOrderItem.getItemId());
32145 tejbeer 1867
        // In case listing gets removed rebill it using the selling price
1868
        if (tl != null) {
1869
            fofoOrderItem.setDp(tl.getSellingPrice());
1870
            fofoOrderItem.setMop(tl.getMop());
1871
        } else {
1872
            fofoOrderItem.setDp(customFofoOrderItem.getSellingPrice());
1873
            fofoOrderItem.setMop(customFofoOrderItem.getSellingPrice());
1874
        }
1875
        fofoOrderItem.setDiscount(customFofoOrderItem.getDiscountAmount());
24823 amit.gupta 1876
 
32145 tejbeer 1877
        Item item = itemMap.get(customFofoOrderItem.getItemId());
35493 amit 1878
 
35736 amit 1879
        // Use first inventory item to get HSN code and GST rates
1880
        InventoryItem firstInventoryItem = inventoryItems.iterator().next();
1881
        GstRate gstRate = gstRateMap.get(firstInventoryItem.getItemId());
1882
        if (gstRate != null) {
1883
            fofoOrderItem.setIgstRate(gstRate.getIgstRate());
1884
            fofoOrderItem.setCgstRate(gstRate.getCgstRate());
1885
            fofoOrderItem.setSgstRate(gstRate.getSgstRate());
32145 tejbeer 1886
        }
35736 amit 1887
        fofoOrderItem.setHsnCode(firstInventoryItem.getHsnCode());
32145 tejbeer 1888
        fofoOrderItem.setBrand(item.getBrand());
1889
        fofoOrderItem.setModelName(item.getModelName());
1890
        fofoOrderItem.setModelNumber(item.getModelNumber());
1891
        fofoOrderItem.setColor(item.getColor());
1892
        fofoOrderItemRepository.persist(fofoOrderItem);
1893
        return fofoOrderItem;
1894
    }
27516 amit.gupta 1895
 
33665 ranu 1896
    private FofoOrderItem getDummyFofoOrderItem(int itemId, int fofoOrderId, String serialNumber, Integer stateId) throws
1897
            ProfitMandiBusinessException {
32145 tejbeer 1898
        Item item = itemRepository.selectById(itemId);
1899
        TagListing tl = tagListingRepository.selectByItemId(itemId);
1900
        FofoOrderItem fofoOrderItem = new FofoOrderItem();
1901
        fofoOrderItem.setItemId(itemId);
1902
        fofoOrderItem.setQuantity(1);
1903
        fofoOrderItem.setSellingPrice(tl.getMop());
1904
        fofoOrderItem.setOrderId(fofoOrderId);
1905
        // In case listing gets removed rebill it using the selling price
1906
        fofoOrderItem.setDp(tl.getSellingPrice());
1907
        fofoOrderItem.setMop(tl.getMop());
1908
        fofoOrderItem.setDiscount(0);
27516 amit.gupta 1909
 
32145 tejbeer 1910
        Map<Integer, GstRate> itemIdStateTaxRateMap = null;
1911
        if (stateId != null) {
1912
            itemIdStateTaxRateMap = stateGstRateRepository.getStateTaxRate(Arrays.asList(itemId), stateId);
1913
        } else {
1914
            itemIdStateTaxRateMap = stateGstRateRepository.getIgstTaxRate(Arrays.asList(itemId));
1915
        }
27516 amit.gupta 1916
 
32145 tejbeer 1917
        fofoOrderItem.setIgstRate(itemIdStateTaxRateMap.get(itemId).getIgstRate());
27516 amit.gupta 1918
 
32145 tejbeer 1919
        fofoOrderItem.setCgstRate(itemIdStateTaxRateMap.get(itemId).getCgstRate());
1920
        fofoOrderItem.setSgstRate(itemIdStateTaxRateMap.get(itemId).getSgstRate());
23650 amit.gupta 1921
 
1922
 
32145 tejbeer 1923
        fofoOrderItem.setHsnCode(item.getHsnCode());
1924
        fofoOrderItem.setBrand(item.getBrand());
1925
        fofoOrderItem.setModelName(item.getModelName());
1926
        fofoOrderItem.setModelNumber(item.getModelNumber());
1927
        fofoOrderItem.setColor(item.getColor());
23650 amit.gupta 1928
 
32145 tejbeer 1929
        Set<FofoLineItem> fofoLineItems = new HashSet<>();
1930
        FofoLineItem fli = new FofoLineItem();
1931
        fli.setQuantity(1);
1932
        fli.setSerialNumber(serialNumber);
1933
        fofoLineItems.add(fli);
1934
        fofoOrderItem.setFofoLineItems(fofoLineItems);
22859 ashik.ali 1935
 
32145 tejbeer 1936
        return fofoOrderItem;
1937
    }
22859 ashik.ali 1938
 
33665 ranu 1939
    private void updateCurrentInventorySnapshot(List<CurrentInventorySnapshot> currentInventorySnapshots,
1940
                                                int fofoId, int itemId, int quantity) throws ProfitMandiBusinessException {
32145 tejbeer 1941
        for (CurrentInventorySnapshot currentInventorySnapshot : currentInventorySnapshots) {
1942
            if (currentInventorySnapshot.getItemId() == itemId && currentInventorySnapshot.getFofoId() == fofoId) {
1943
                currentInventorySnapshotRepository.updateAvailabilityByItemIdAndFofoId(itemId, fofoId, currentInventorySnapshot.getAvailability() - quantity);
1944
            }
1945
        }
1946
    }
23650 amit.gupta 1947
 
33665 ranu 1948
    private void createPaymentOptions(FofoOrder fofoOrder, Set<CustomPaymentOption> customPaymentOptions) throws
1949
            ProfitMandiBusinessException {
32145 tejbeer 1950
        for (CustomPaymentOption customPaymentOption : customPaymentOptions) {
1951
            if (customPaymentOption.getAmount() > 0) {
1952
                PaymentOptionTransaction paymentOptionTransaction = new PaymentOptionTransaction();
1953
                paymentOptionTransaction.setReferenceId(fofoOrder.getId());
1954
                paymentOptionTransaction.setPaymentOptionId(customPaymentOption.getPaymentOptionId());
1955
                paymentOptionTransaction.setReferenceType(PaymentOptionReferenceType.ORDER);
1956
                paymentOptionTransaction.setAmount(customPaymentOption.getAmount());
1957
                paymentOptionTransaction.setFofoId(fofoOrder.getFofoId());
1958
                paymentOptionTransactionRepository.persist(paymentOptionTransaction);
1959
            }
1960
        }
1961
    }
22859 ashik.ali 1962
 
33665 ranu 1963
    private FofoOrder createAndGetFofoOrder(int customerId, String customerGstNumber, int fofoId, String
34381 vikas.jang 1964
            documentNumber, float totalAmount, int customerAddressId, int poId) {
36362 amit 1965
        // Idempotency: concurrent duplicate requests (double-click, upstream retries) used
1966
        // to deadlock on idx_invoice_number. Fast path — if the row already exists for
1967
        // this (fofo, invoice) return it instead of attempting a duplicate insert.
1968
        FofoOrder existing = findExistingFofoOrder(fofoId, documentNumber);
1969
        if (existing != null) return existing;
1970
 
32145 tejbeer 1971
        FofoOrder fofoOrder = new FofoOrder();
1972
        fofoOrder.setCustomerGstNumber(customerGstNumber);
1973
        fofoOrder.setCustomerId(customerId);
1974
        fofoOrder.setFofoId(fofoId);
34381 vikas.jang 1975
        fofoOrder.setPendingOrderId(poId);
32145 tejbeer 1976
        fofoOrder.setInvoiceNumber(documentNumber);
1977
        fofoOrder.setTotalAmount(totalAmount);
1978
        fofoOrder.setCustomerAddressId(customerAddressId);
36362 amit 1979
        try {
1980
            fofoOrderRepository.persist(fofoOrder);
1981
        } catch (org.springframework.dao.DataIntegrityViolationException dup) {
1982
            // Narrow race: another concurrent request won the insert after our select.
1983
            // Re-fetch and return the winner's row. Requires the uk_fofo_order_fofo_invoice
1984
            // unique key on fofo_order to surface the duplicate as this exception.
1985
            FofoOrder winner = findExistingFofoOrder(fofoId, documentNumber);
1986
            if (winner != null) return winner;
1987
            throw dup;
1988
        }
32145 tejbeer 1989
        return fofoOrder;
1990
    }
23650 amit.gupta 1991
 
36362 amit 1992
    private FofoOrder findExistingFofoOrder(int fofoId, String invoiceNumber) {
1993
        try {
1994
            return fofoOrderRepository.selectByFofoIdAndInvoiceNumber(fofoId, invoiceNumber);
1995
        } catch (ProfitMandiBusinessException ignored) {
1996
            return null;
1997
        }
1998
    }
1999
 
33665 ranu 2000
    private void validateItemsSerializedNonSerialized
2001
            (List<Item> items, Map<Integer, CustomFofoOrderItem> customFofoOrderItemMap) throws
2002
            ProfitMandiBusinessException {
32145 tejbeer 2003
        List<Integer> invalidItemIdSerialNumbers = new ArrayList<Integer>();
2004
        List<Integer> itemIdNonSerializedSerialNumbers = new ArrayList<Integer>();
2005
        for (Item i : items) {
2006
            CustomFofoOrderItem customFofoOrderItem = customFofoOrderItemMap.get(i.getId());
2007
            if (i.getType().equals(ItemType.SERIALIZED)) {
2008
                if (customFofoOrderItem == null || customFofoOrderItem.getSerialNumberDetails().isEmpty()) {
2009
                    invalidItemIdSerialNumbers.add(i.getId());
2010
                }
2011
            } else {
2012
                Set<String> serialNumbers = this.serialNumberDetailsToSerialNumbers(customFofoOrderItem.getSerialNumberDetails());
2013
                if (customFofoOrderItem == null || !serialNumbers.isEmpty()) {
2014
                    itemIdNonSerializedSerialNumbers.add(i.getId());
2015
                }
2016
            }
2017
        }
23650 amit.gupta 2018
 
32145 tejbeer 2019
        if (!invalidItemIdSerialNumbers.isEmpty()) {
2020
            LOGGER.error("Invalid itemId's serialNumbers for serialized{}", invalidItemIdSerialNumbers);
2021
            // itemId's are serialized you are saying these are not serialized
2022
            throw new ProfitMandiBusinessException("invalidItemIdSerialNumbers", invalidItemIdSerialNumbers, "FFORDR_1013");
2023
        }
22859 ashik.ali 2024
 
32145 tejbeer 2025
        if (!itemIdNonSerializedSerialNumbers.isEmpty()) {
2026
            LOGGER.error("Invalid itemId's serialNumbers for non serialized{}", itemIdNonSerializedSerialNumbers);
2027
            // itemId's are non serialized you are saying these are serialized
2028
            throw new ProfitMandiBusinessException("itemIdNonSerializedSerialNumbers", itemIdNonSerializedSerialNumbers, "FFORDR_1014");
2029
        }
2030
    }
22859 ashik.ali 2031
 
33665 ranu 2032
    private void validateCurrentInventorySnapshotQuantities
2033
            (List<CurrentInventorySnapshot> currentInventorySnapshots, Map<Integer, CustomFofoOrderItem> itemIdCustomFofoOrderItemMap) throws
2034
            ProfitMandiBusinessException {
32145 tejbeer 2035
        if (itemIdCustomFofoOrderItemMap.keySet().size() != currentInventorySnapshots.size()) {
2036
            throw new ProfitMandiBusinessException("quantiiesSize", currentInventorySnapshots.size(), "");
2037
        }
2038
        List<ItemIdQuantityAvailability> itemIdQuantityAvailabilities = new ArrayList<>(); // this is for error
2039
        LOGGER.info("currentInventorySnapshots " + currentInventorySnapshots);
2040
        LOGGER.info("CustomFofoLineItemMap {}", itemIdCustomFofoOrderItemMap);
2041
        for (CurrentInventorySnapshot currentInventorySnapshot : currentInventorySnapshots) {
2042
            CustomFofoOrderItem customFofoOrderItem = itemIdCustomFofoOrderItemMap.get(currentInventorySnapshot.getItemId());
2043
            LOGGER.info("customFofoOrderItem {}", customFofoOrderItem);
2044
            if (customFofoOrderItem.getQuantity() > currentInventorySnapshot.getAvailability()) {
2045
                ItemIdQuantityAvailability itemIdQuantityAvailability = new ItemIdQuantityAvailability();
2046
                itemIdQuantityAvailability.setItemId(customFofoOrderItem.getItemId());
2047
                Quantity quantity = new Quantity();
2048
                quantity.setAvailable(currentInventorySnapshot.getAvailability());
2049
                quantity.setRequested(customFofoOrderItem.getQuantity());
2050
                itemIdQuantityAvailability.setQuantity(quantity);
2051
                itemIdQuantityAvailabilities.add(itemIdQuantityAvailability);
2052
            }
2053
        }
22859 ashik.ali 2054
 
32145 tejbeer 2055
        if (!itemIdQuantityAvailabilities.isEmpty()) {
2056
            // itemIdQuantity request is not valid
2057
            LOGGER.error("Requested quantities should not be greater than currently available quantities {}", itemIdQuantityAvailabilities);
2058
            throw new ProfitMandiBusinessException("itemIdQuantityAvailabilities", itemIdQuantityAvailabilities, "FFORDR_1015");
2059
        }
2060
    }
22859 ashik.ali 2061
 
33665 ranu 2062
    private int getItemIdFromSerialNumber(Map<Integer, CustomFofoOrderItem> itemIdCustomFofoOrderItemMap, String
2063
            serialNumber) {
32145 tejbeer 2064
        int itemId = 0;
2065
        for (Map.Entry<Integer, CustomFofoOrderItem> entry : itemIdCustomFofoOrderItemMap.entrySet()) {
2066
            Set<SerialNumberDetail> serialNumberDetails = entry.getValue().getSerialNumberDetails();
2067
            for (SerialNumberDetail serialNumberDetail : serialNumberDetails) {
2068
                if (serialNumberDetail.getSerialNumber().equals(serialNumber)) {
2069
                    itemId = entry.getKey();
2070
                    break;
2071
                }
2072
            }
2073
        }
2074
        return itemId;
2075
    }
23650 amit.gupta 2076
 
32145 tejbeer 2077
    private Map<Integer, Item> toItemMap(List<Item> items) {
2078
        Function<Item, Integer> itemIdFunction = new Function<Item, Integer>() {
2079
            @Override
2080
            public Integer apply(Item item) {
2081
                return item.getId();
2082
            }
2083
        };
2084
        Function<Item, Item> itemFunction = new Function<Item, Item>() {
2085
            @Override
2086
            public Item apply(Item item) {
2087
                return item;
2088
            }
2089
        };
2090
        return items.stream().collect(Collectors.toMap(itemIdFunction, itemFunction));
2091
    }
23650 amit.gupta 2092
 
32145 tejbeer 2093
    private void setCustomerAddress(CustomerAddress customerAddress, CustomAddress customAddress) {
2094
        customerAddress.setName(customAddress.getName());
2095
        customerAddress.setLastName(customAddress.getLastName());
2096
        customerAddress.setLine1(customAddress.getLine1());
2097
        customerAddress.setLine2(customAddress.getLine2());
2098
        customerAddress.setLandmark(customAddress.getLandmark());
2099
        customerAddress.setCity(customAddress.getCity());
2100
        customerAddress.setPinCode(customAddress.getPinCode());
2101
        customerAddress.setState(customAddress.getState());
2102
        customerAddress.setCountry(customAddress.getCountry());
2103
        customerAddress.setPhoneNumber(customAddress.getPhoneNumber());
2104
    }
23650 amit.gupta 2105
 
32145 tejbeer 2106
    private CustomAddress createCustomAddress(Address address) {
2107
        CustomAddress customAddress = new CustomAddress();
2108
        customAddress.setName(address.getName());
2109
        customAddress.setLine1(address.getLine1());
2110
        customAddress.setLine2(address.getLine2());
2111
        customAddress.setLandmark(address.getLandmark());
2112
        customAddress.setCity(address.getCity());
2113
        customAddress.setPinCode(address.getPinCode());
2114
        customAddress.setState(address.getState());
2115
        customAddress.setCountry(address.getCountry());
2116
        customAddress.setPhoneNumber(address.getPhoneNumber());
2117
        return customAddress;
2118
    }
23650 amit.gupta 2119
 
32145 tejbeer 2120
    private CustomAddress createCustomAddress(CustomerAddress customerAddress) {
2121
        CustomAddress customAddress = new CustomAddress();
2122
        customAddress.setName(customerAddress.getName());
2123
        customAddress.setLastName(customerAddress.getLastName());
2124
        customAddress.setLine1(customerAddress.getLine1());
2125
        customAddress.setLine2(customerAddress.getLine2());
2126
        customAddress.setLandmark(customerAddress.getLandmark());
2127
        customAddress.setCity(customerAddress.getCity());
2128
        customAddress.setPinCode(customerAddress.getPinCode());
2129
        customAddress.setState(customerAddress.getState());
2130
        customAddress.setCountry(customerAddress.getCountry());
2131
        customAddress.setPhoneNumber(customerAddress.getPhoneNumber());
2132
        return customAddress;
2133
    }
23650 amit.gupta 2134
 
33665 ranu 2135
    private CustomAddress createCustomAddressWithoutId(CustomCustomer customerAddress, CustomAddress
2136
            retailerAddress) {
32627 ranu 2137
        CustomAddress customAddress = new CustomAddress();
2138
        customAddress.setName(customerAddress.getFirstName());
2139
        customAddress.setLastName(customerAddress.getLastName());
2140
        customAddress.setLine1("");
2141
        customAddress.setLine2("");
2142
        customAddress.setLandmark("");
33089 amit.gupta 2143
        customAddress.setCity(retailerAddress.getCity());
2144
        customAddress.setPinCode(retailerAddress.getPinCode());
2145
        customAddress.setState(retailerAddress.getState());
32627 ranu 2146
        customAddress.setCountry("");
2147
        customAddress.setPhoneNumber(customerAddress.getMobileNumber());
2148
        return customAddress;
2149
    }
2150
 
33665 ranu 2151
    private void validatePaymentOptionsAndTotalAmount(Set<CustomPaymentOption> customPaymentOptions,
2152
                                                      float totalAmount) throws ProfitMandiBusinessException {
32145 tejbeer 2153
        Set<Integer> paymentOptionIds = new HashSet<>();
23650 amit.gupta 2154
 
32145 tejbeer 2155
        float calculatedAmount = 0;
2156
        for (CustomPaymentOption customPaymentOption : customPaymentOptions) {
2157
            paymentOptionIds.add(customPaymentOption.getPaymentOptionId());
2158
            calculatedAmount = calculatedAmount + customPaymentOption.getAmount();
2159
        }
2160
        if (calculatedAmount != totalAmount) {
2161
            LOGGER.warn("Error occured while validating payment options amount - {} != TotalAmount {}", calculatedAmount, totalAmount);
2162
            throw new ProfitMandiBusinessException(ProfitMandiConstants.PAYMENT_OPTION_CALCULATED_AMOUNT, calculatedAmount, "FFORDR_1016");
2163
        }
23418 ashik.ali 2164
 
32145 tejbeer 2165
        List<Integer> foundPaymentOptionIds = paymentOptionRepository.selectIdsByIds(paymentOptionIds);
2166
        if (foundPaymentOptionIds.size() != paymentOptionIds.size()) {
2167
            paymentOptionIds.removeAll(foundPaymentOptionIds);
2168
            throw new ProfitMandiBusinessException(ProfitMandiConstants.PAYMENT_OPTION_ID, paymentOptionIds, "FFORDR_1017");
2169
        }
2170
    }
25101 amit.gupta 2171
 
32145 tejbeer 2172
    @Override
2173
    public List<FofoOrderItem> getByOrderId(int orderId) throws ProfitMandiBusinessException {
2174
        List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(orderId);
2175
        if (!fofoOrderItems.isEmpty()) {
2176
            List<FofoOrderItem> newFofoOrderItems = new ArrayList<>();
2177
            Map<Integer, Set<FofoLineItem>> fofoOrderItemIdFofoLineItemsMap = this.toFofoOrderItemIdFofoLineItems(fofoOrderItems);
2178
            Iterator<FofoOrderItem> fofoOrderItemsIterator = fofoOrderItems.iterator();
2179
            while (fofoOrderItemsIterator.hasNext()) {
2180
                FofoOrderItem fofoOrderItem = fofoOrderItemsIterator.next();
2181
                fofoOrderItem.setFofoLineItems(fofoOrderItemIdFofoLineItemsMap.get(fofoOrderItem.getId()));
2182
                newFofoOrderItems.add(fofoOrderItem);
2183
                fofoOrderItemsIterator.remove();
2184
            }
2185
            fofoOrderItems = newFofoOrderItems;
2186
        }
2187
        return fofoOrderItems;
2188
    }
25101 amit.gupta 2189
 
32145 tejbeer 2190
    private Set<Integer> toFofoOrderItemIds(List<FofoOrderItem> fofoOrderItems) {
2191
        Function<FofoOrderItem, Integer> fofoOrderItemToFofoOrderItemIdFunction = new Function<FofoOrderItem, Integer>() {
2192
            @Override
2193
            public Integer apply(FofoOrderItem fofoOrderItem) {
2194
                return fofoOrderItem.getId();
2195
            }
2196
        };
2197
        return fofoOrderItems.stream().map(fofoOrderItemToFofoOrderItemIdFunction).collect(Collectors.toSet());
2198
    }
25101 amit.gupta 2199
 
33665 ranu 2200
    private Map<Integer, Set<FofoLineItem>> toFofoOrderItemIdFofoLineItems(List<FofoOrderItem> fofoOrderItems) throws
2201
            ProfitMandiBusinessException {
32145 tejbeer 2202
        Set<Integer> fofoOrderItemIds = this.toFofoOrderItemIds(fofoOrderItems);
2203
        List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
2204
        Map<Integer, Set<FofoLineItem>> fofoOrderItemIdFofoLineItemsMap = new HashMap<>();
2205
        for (FofoLineItem fofoLineItem : fofoLineItems) {
2206
            if (!fofoOrderItemIdFofoLineItemsMap.containsKey(fofoLineItem.getFofoOrderItemId())) {
2207
                Set<FofoLineItem> fofoLineItems2 = new HashSet<>();
2208
                fofoLineItems2.add(fofoLineItem);
2209
                fofoOrderItemIdFofoLineItemsMap.put(fofoLineItem.getFofoOrderItemId(), fofoLineItems2);
2210
            } else {
2211
                fofoOrderItemIdFofoLineItemsMap.get(fofoLineItem.getFofoOrderItemId()).add(fofoLineItem);
2212
            }
2213
        }
2214
        return fofoOrderItemIdFofoLineItemsMap;
2215
    }
25101 amit.gupta 2216
 
32145 tejbeer 2217
    @Override
33665 ranu 2218
    public void updateCustomerDetails(CustomCustomer customCustomer, String invoiceNumber) throws
2219
            ProfitMandiBusinessException {
32145 tejbeer 2220
        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
34718 aman.kumar 2221
        LOGGER.info("fofoOrder{}", fofoOrder);
32145 tejbeer 2222
        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
34718 aman.kumar 2223
        LOGGER.info("customer{}", customer);
32145 tejbeer 2224
        customer.setFirstName(customCustomer.getFirstName());
2225
        customer.setLastName(customCustomer.getLastName());
2226
        customer.setMobileNumber(customCustomer.getMobileNumber());
2227
        customer.setEmailId(customCustomer.getEmailId());
2228
        customerRepository.persist(customer);
34338 ranu 2229
        if (fofoOrder.getCustomerAddressId() == 0) {
2230
            CustomAddress customAddress = customCustomer.getAddress();
2231
 
2232
            if (customAddress == null ||
2233
                    isNullOrEmpty(customAddress.getName()) ||
2234
                    isNullOrEmpty(customAddress.getLastName()) ||
2235
                    isNullOrEmpty(customAddress.getLine1()) ||
2236
                    isNullOrEmpty(customAddress.getCity()) ||
2237
                    isNullOrEmpty(customAddress.getPinCode()) ||
2238
                    isNullOrEmpty(customAddress.getState()) ||
34718 aman.kumar 2239
//                    isNullOrEmpty(customAddress.getCountry()) ||
34338 ranu 2240
                    isNullOrEmpty(customAddress.getPhoneNumber())) {
2241
                throw new IllegalArgumentException("Required customer address fields are missing.");
2242
            }
2243
 
2244
            CustomerAddress customerAddress = new CustomerAddress();
2245
            customerAddress.setCustomerId(fofoOrder.getCustomerId());
2246
            customerAddress.setName(customAddress.getName());
2247
            customerAddress.setLastName(customAddress.getLastName());
2248
            customerAddress.setLine1(customAddress.getLine1());
2249
            customerAddress.setLine2(customAddress.getLine2());
2250
            customerAddress.setLandmark(customAddress.getLandmark());
2251
            customerAddress.setCity(customAddress.getCity());
2252
            customerAddress.setPinCode(customAddress.getPinCode());
2253
            customerAddress.setState(customAddress.getState());
34718 aman.kumar 2254
//            customerAddress.setCountry(customAddress.getCountry());
34338 ranu 2255
            customerAddress.setPhoneNumber(customAddress.getPhoneNumber());
2256
            customerAddressRepository.persist(customerAddress);
2257
            fofoOrder.setCustomerAddressId(customerAddress.getId());
2258
 
2259
        }
32145 tejbeer 2260
        CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
2261
        if (!customerAddress.getState().equalsIgnoreCase(customCustomer.getAddress().getState())) {
2262
            List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
2263
            resetTaxation(fofoOrder.getFofoId(), customerAddress, fofoOrderItems);
2264
        }
2265
        this.setCustomerAddress(customerAddress, customCustomer.getAddress());
2266
        fofoOrder.setCustomerGstNumber(customCustomer.getGstNumber());
2267
    }
23638 amit.gupta 2268
 
34338 ranu 2269
    private boolean isNullOrEmpty(String str) {
2270
        return str == null || str.trim().isEmpty();
2271
    }
2272
 
33665 ranu 2273
    private void resetTaxation(int fofoId, CustomerAddress customerAddress, List<FofoOrderItem> fofoOrderItems) throws
2274
            ProfitMandiBusinessException {
32145 tejbeer 2275
        int retailerAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(fofoId);
23650 amit.gupta 2276
 
32145 tejbeer 2277
        Address retailerAddress = addressRepository.selectById(retailerAddressId);
24275 amit.gupta 2278
 
32145 tejbeer 2279
        Integer stateId = null;
2280
        if (customerAddress.getState().equalsIgnoreCase(retailerAddress.getState())) {
2281
            try {
2282
                stateId = Long.valueOf(stateRepository.selectByName(customerAddress.getState()).getId()).intValue();
2283
            } catch (Exception e) {
2284
                LOGGER.error("Unable to get state rates");
2285
            }
2286
        }
2287
        List<Integer> itemIds = fofoOrderItems.stream().map(x -> x.getItemId()).collect(Collectors.toList());
2288
        final Map<Integer, GstRate> gstRates;
2289
        if (stateId != null) {
2290
            gstRates = stateGstRateRepository.getStateTaxRate(itemIds, stateId);
2291
        } else {
2292
            gstRates = stateGstRateRepository.getIgstTaxRate(itemIds);
2293
        }
2294
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
2295
            GstRate rate = gstRates.get(fofoOrderItem.getItemId());
2296
            fofoOrderItem.setCgstRate(rate.getCgstRate());
2297
            fofoOrderItem.setSgstRate(rate.getSgstRate());
2298
            fofoOrderItem.setIgstRate(rate.getIgstRate());
2299
        }
2300
    }
2301
    @Override
33665 ranu 2302
    public CustomerCreditNote badReturn(int fofoId, FoiBadReturnRequest foiBadReturnRequest) throws
2303
            ProfitMandiBusinessException {
34141 tejus.loha 2304
        return this.badReturn(null, fofoId, foiBadReturnRequest);
2305
    }
2306
    @Override
2307
    public CustomerCreditNote badReturn(String loginMail,int fofoId, FoiBadReturnRequest foiBadReturnRequest) throws
2308
            ProfitMandiBusinessException {
32145 tejbeer 2309
        FofoOrderItem foi = fofoOrderItemRepository.selectById(foiBadReturnRequest.getFofoOrderItemId());
2310
        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(foi.getOrderId());
2311
        if (fofoOrder.getFofoId() != fofoId) {
2312
            throw new ProfitMandiBusinessException("Partner Auth", "", "Invalid Order");
2313
        }
2314
        int billedQty = foi.getQuantity() - customerReturnItemRepository.selectAllByOrderItemId(foi.getId()).size();
2315
        if (foiBadReturnRequest.getMarkedBadArr().size() > billedQty) {
2316
            throw new ProfitMandiBusinessException("Cant bad return more than what is billed", "", "Invalid Quantity");
2317
        }
2318
        List<CustomerReturnItem> customerReturnItems = new ArrayList<>();
2319
        for (BadReturnRequest badReturnRequest : foiBadReturnRequest.getMarkedBadArr()) {
2320
            CustomerReturnItem customerReturnItem = new CustomerReturnItem();
2321
            customerReturnItem.setFofoId(fofoId);
2322
            customerReturnItem.setFofoOrderItemId(foiBadReturnRequest.getFofoOrderItemId());
2323
            customerReturnItem.setFofoOrderId(fofoOrder.getId());
2324
            customerReturnItem.setRemarks(badReturnRequest.getRemarks());
2325
            customerReturnItem.setInventoryItemId(badReturnRequest.getInventoryItemId());
2326
            customerReturnItem.setQuantity(1);
2327
            customerReturnItem.setType(ReturnType.BAD);
2328
            // customerReturnItemRepository.persist(customerReturnItem);
2329
            inventoryService.saleReturnInventoryItem(customerReturnItem);
2330
            customerReturnItems.add(customerReturnItem);
2331
        }
2332
        CustomerCreditNote creditNote = generateCreditNote(fofoOrder, customerReturnItems);
2333
        for (CustomerReturnItem customerReturnItem : customerReturnItems) {
2334
            purchaseReturnService.returnInventoryItem(fofoId, false, customerReturnItem.getInventoryItemId(), ReturnType.BAD);
2335
        }
2336
        // This should cancel the order
2337
        fofoOrder.setCancelledTimestamp(LocalDateTime.now());
36305 amit 2338
        partnerInvestmentService.evictInvestmentCache(fofoOrder.getFofoId());
32145 tejbeer 2339
        this.reverseScheme(fofoOrder);
2340
        return creditNote;
2341
    }
23638 amit.gupta 2342
 
33665 ranu 2343
    private CustomerCreditNote generateCreditNote(FofoOrder
2344
                                                          fofoOrder, List<CustomerReturnItem> customerReturnItems) throws ProfitMandiBusinessException {
24275 amit.gupta 2345
 
32145 tejbeer 2346
        InvoiceNumberGenerationSequence sequence = invoiceNumberGenerationSequenceRepository.selectByFofoId(fofoOrder.getFofoId());
2347
        sequence.setCreditNoteSequence(sequence.getCreditNoteSequence() + 1);
2348
        invoiceNumberGenerationSequenceRepository.persist(sequence);
24275 amit.gupta 2349
 
32145 tejbeer 2350
        String creditNoteNumber = sequence.getPrefix() + "/" + sequence.getCreditNoteSequence();
2351
        CustomerCreditNote creditNote = new CustomerCreditNote();
2352
        creditNote.setCreditNoteNumber(creditNoteNumber);
2353
        creditNote.setFofoId(fofoOrder.getFofoId());
2354
        creditNote.setFofoOrderId(fofoOrder.getId());
2355
        creditNote.setFofoOrderItemId(customerReturnItems.get(0).getFofoOrderItemId());
2356
        creditNote.setSettlementType(SettlementType.UNSETTLED);
2357
        customerCreditNoteRepository.persist(creditNote);
24275 amit.gupta 2358
 
32145 tejbeer 2359
        for (CustomerReturnItem customerReturnItem : customerReturnItems) {
2360
            customerReturnItem.setCreditNoteId(creditNote.getId());
2361
            customerReturnItemRepository.persist(customerReturnItem);
2362
        }
2363
        // this.returnInventoryItems(inventoryItems, debitNote);
23655 amit.gupta 2364
 
32145 tejbeer 2365
        return creditNote;
2366
    }
23655 amit.gupta 2367
 
32145 tejbeer 2368
    @Override
2369
    public CreditNotePdfModel getCreditNotePdfModel(int customerCreditNoteId) throws ProfitMandiBusinessException {
2370
        CustomerCreditNote creditNote = customerCreditNoteRepository.selectById(customerCreditNoteId);
2371
        return getCreditNotePdfModel(creditNote);
2372
    }
24275 amit.gupta 2373
 
33665 ranu 2374
    private CreditNotePdfModel getCreditNotePdfModel(CustomerCreditNote creditNote) throws
2375
            ProfitMandiBusinessException {
32145 tejbeer 2376
        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(creditNote.getFofoOrderId());
2377
        List<CustomerReturnItem> customerReturnItems = customerReturnItemRepository.selectAllByCreditNoteId(creditNote.getId());
33090 amit.gupta 2378
        CustomRetailer customRetailer = retailerService.getFofoRetailer(fofoOrder.getFofoId());
2379
        CustomCustomer customCustomer = getCustomCustomer(fofoOrder, customRetailer.getAddress());
24275 amit.gupta 2380
 
33298 amit.gupta 2381
        List<CustomOrderItem> customerFofoOrderItems = new ArrayList<>();
23655 amit.gupta 2382
 
32145 tejbeer 2383
        FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(creditNote.getFofoOrderItemId());
2384
        float totalTaxRate = fofoOrderItem.getIgstRate() + fofoOrderItem.getSgstRate() + fofoOrderItem.getCgstRate();
24275 amit.gupta 2385
 
32145 tejbeer 2386
        CustomOrderItem customFofoOrderItem = new CustomOrderItem();
2387
        customFofoOrderItem.setDescription(fofoOrderItem.getBrand() + " " + fofoOrderItem.getModelName() + " " + fofoOrderItem.getModelNumber() + "-" + fofoOrderItem.getColor());
24275 amit.gupta 2388
 
35695 amit 2389
        List<String> serialNumbers = new ArrayList<>();
32145 tejbeer 2390
        if (ItemType.SERIALIZED.equals(itemRepository.selectById(fofoOrderItem.getItemId()).getType())) {
2391
            Set<Integer> inventoryItemIds = customerReturnItems.stream().map(x -> x.getInventoryItemId()).collect(Collectors.toSet());
35695 amit 2392
            serialNumbers = inventoryItemRepository.selectByIds(inventoryItemIds).stream().map(x -> x.getSerialNumber()).collect(Collectors.toList());
32145 tejbeer 2393
            customFofoOrderItem.setDescription(
2394
                    customFofoOrderItem.getDescription() + "\n IMEIS - " + String.join(", ", serialNumbers));
2395
        }
23638 amit.gupta 2396
 
35695 amit 2397
        // Check if margin scheme item
2398
        boolean isMarginItem = false;
2399
        try {
2400
            Item item = itemRepository.selectById(fofoOrderItem.getItemId());
2401
            Category category = categoryRepository.selectById(item.getCategoryId());
2402
            isMarginItem = category.isMarginOnly() && !serialNumbers.isEmpty();
2403
        } catch (Exception e) {
2404
            LOGGER.warn("Could not check margin scheme for credit note item {}", fofoOrderItem.getId(), e);
2405
        }
2406
 
2407
        if (isMarginItem) {
2408
            // Margin Scheme credit note: reverse GST on margin only
2409
            float purchasePrice = getFofoPurchasePrice(serialNumbers.get(0), fofoOrder.getFofoId());
2410
            float sellingPrice = fofoOrderItem.getSellingPrice();
2411
            float margin = Math.max(0, sellingPrice - purchasePrice);
2412
            float taxableMargin = margin / (1 + totalTaxRate / 100);
2413
 
2414
            customFofoOrderItem.setMarginScheme(true);
2415
            customFofoOrderItem.setPurchasePrice(purchasePrice);
2416
            customFofoOrderItem.setSellingPrice(sellingPrice);
2417
            customFofoOrderItem.setMargin(margin);
2418
            customFofoOrderItem.setRate(sellingPrice);
2419
            customFofoOrderItem.setDiscount(0);
2420
            customFofoOrderItem.setAmount(taxableMargin * customerReturnItems.size());
2421
        } else {
2422
            float taxableSellingPrice = fofoOrderItem.getSellingPrice() / (1 + totalTaxRate / 100);
2423
            float taxableDiscountPrice = fofoOrderItem.getDiscount() / (1 + totalTaxRate / 100);
2424
            customFofoOrderItem.setAmount(customerReturnItems.size() * (taxableSellingPrice - taxableDiscountPrice));
2425
            customFofoOrderItem.setRate(taxableSellingPrice);
2426
            customFofoOrderItem.setDiscount(taxableDiscountPrice);
2427
        }
2428
 
32145 tejbeer 2429
        customFofoOrderItem.setQuantity(customerReturnItems.size());
2430
        customFofoOrderItem.setNetAmount(
2431
                (fofoOrderItem.getSellingPrice() - fofoOrderItem.getDiscount()) * customFofoOrderItem.getQuantity());
29707 tejbeer 2432
 
32145 tejbeer 2433
        float igstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getIgstRate()) / 100;
2434
        float cgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getCgstRate()) / 100;
2435
        float sgstAmount = (customFofoOrderItem.getAmount() * fofoOrderItem.getSgstRate()) / 100;
2436
        LOGGER.info("fofoOrderItem - {}", fofoOrderItem);
2437
        customFofoOrderItem.setIgstRate(fofoOrderItem.getIgstRate());
2438
        customFofoOrderItem.setIgstAmount(igstAmount);
2439
        customFofoOrderItem.setCgstRate(fofoOrderItem.getCgstRate());
2440
        customFofoOrderItem.setCgstAmount(cgstAmount);
2441
        customFofoOrderItem.setSgstRate(fofoOrderItem.getSgstRate());
2442
        customFofoOrderItem.setSgstAmount(sgstAmount);
2443
        customFofoOrderItem.setHsnCode(fofoOrderItem.getHsnCode());
2444
        customFofoOrderItem.setOrderId(1);
2445
        customerFofoOrderItems.add(customFofoOrderItem);
29707 tejbeer 2446
 
32145 tejbeer 2447
        InvoicePdfModel pdfModel = new InvoicePdfModel();
2448
        pdfModel.setAuther("NSSPL");
2449
        pdfModel.setCustomer(customCustomer);
2450
        pdfModel.setInvoiceNumber(fofoOrder.getInvoiceNumber());
2451
        pdfModel.setInvoiceDate(FormattingUtils.formatDate(fofoOrder.getCreateTimestamp()));
2452
        pdfModel.setTitle("Credit Note");
2453
        pdfModel.setRetailer(customRetailer);
2454
        pdfModel.setTotalAmount(customFofoOrderItem.getNetAmount());
2455
        pdfModel.setOrderItems(customerFofoOrderItems);
35695 amit 2456
        pdfModel.setHasMarginSchemeItems(isMarginItem);
29707 tejbeer 2457
 
37067 amit 2458
        // State codes (were unset, so the note printed "Code: null"). Partner = supplier, customer = buyer.
2459
        pdfModel.setPartnerAddressStateCode(
2460
                stateRepository.selectByName(customRetailer.getAddress().getState()).getCode());
2461
        if (customCustomer.getAddress() != null && customCustomer.getAddress().getState() != null
2462
                && !customCustomer.getAddress().getState().trim().isEmpty()) {
2463
            pdfModel.setCustomerAddressStateCode(
2464
                    stateRepository.selectByName(customCustomer.getAddress().getState()).getCode());
2465
        }
2466
 
32145 tejbeer 2467
        CreditNotePdfModel creditNotePdfModel = new CreditNotePdfModel();
2468
        creditNotePdfModel.setCreditNoteDate(FormattingUtils.formatDate(creditNote.getCreateTimestamp()));
2469
        creditNotePdfModel.setCreditNoteNumber(creditNote.getCreditNoteNumber());
2470
        creditNotePdfModel.setPdfModel(pdfModel);
2471
        return creditNotePdfModel;
2472
    }
24264 amit.gupta 2473
 
32145 tejbeer 2474
    // This will remove the order and maintain order record and reverse inventory
2475
    // and scheme
2476
    @Override
2477
    public void cancelOrder(List<String> invoiceNumbers) throws ProfitMandiBusinessException {
2478
        for (String invoiceNumber : invoiceNumbers) {
2479
            // Cancel only when not cancelled
2480
            FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
2481
            if (fofoOrder.getCancelledTimestamp() == null) {
2482
                fofoOrder.setCancelledTimestamp(LocalDateTime.now());
36305 amit 2483
                partnerInvestmentService.evictInvestmentCache(fofoOrder.getFofoId());
32145 tejbeer 2484
                PaymentOptionTransaction paymentTransaction = new PaymentOptionTransaction();
2485
                paymentTransaction.setAmount(-fofoOrder.getTotalAmount());
2486
                paymentTransaction.setFofoId(fofoOrder.getFofoId());
2487
                paymentTransaction.setReferenceId(fofoOrder.getId());
2488
                paymentTransaction.setReferenceType(PaymentOptionReferenceType.ORDER);
2489
                paymentTransaction.setPaymentOptionId(1);
2490
                paymentOptionTransactionRepository.persist(paymentTransaction);
31030 amit.gupta 2491
 
32145 tejbeer 2492
                List<FofoOrderItem> fois = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
2493
                if (fois.size() > 0) {
2494
                    List<InventoryItem> inventoryItems = new ArrayList<>();
2495
                    fois.stream().forEach(x -> {
2496
                        x.getFofoLineItems().stream().forEach(y -> {
2497
                            inventoryService.rollbackInventory(y.getInventoryItemId(), y.getQuantity(), fofoOrder.getFofoId());
2498
                            inventoryItems.add(inventoryItemRepository.selectById(y.getInventoryItemId()));
2499
                        });
2500
                    });
2501
                    // if(invoice)
2502
                    this.reverseScheme(fofoOrder);
2503
                }
2504
                insuranceService.cancelInsurance(fofoOrder);
2505
            }
2506
        }
2507
    }
31030 amit.gupta 2508
 
32145 tejbeer 2509
    @Override
2510
    public void reverseScheme(FofoOrder fofoOrder) throws ProfitMandiBusinessException {
2511
        String reversalReason = "Order Rolledback/Cancelled/Returned for Invoice #" + fofoOrder.getInvoiceNumber();
2512
        List<FofoOrderItem> fois = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
2513
        Set<Integer> inventoryItemIds = fois.stream().flatMap(x -> x.getFofoLineItems().stream().map(y -> y.getInventoryItemId())).collect(Collectors.toSet());
2514
        List<InventoryItem> inventoryItems = inventoryItemRepository.selectByIds(inventoryItemIds);
34486 amit.gupta 2515
        schemeService.reverseSchemes(inventoryItems, fofoOrder.getId(), reversalReason, SchemeType.OUT_SCHEME_TYPES);
34504 amit.gupta 2516
        //schemeService.reverseSchemes(inventoryItems, fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.INVESTMENT));
32145 tejbeer 2517
        schemeService.reverseSchemes(inventoryItems, fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.SPECIAL_SUPPORT));
31030 amit.gupta 2518
 
32145 tejbeer 2519
    }
24271 amit.gupta 2520
 
32145 tejbeer 2521
    @Override
2522
    public void reverseActivationScheme(List<Integer> inventoryItemIds) throws ProfitMandiBusinessException {
2523
        List<InventoryItem> inventoryItems = inventoryItemRepository.selectAllByIds(inventoryItemIds);
2524
        for (InventoryItem inventoryItem : inventoryItems) {
2525
            List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByInventoryItemId(inventoryItem.getId());
2526
            FofoLineItem fofoLineItem = fofoLineItems.get(0);
2527
            FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(fofoLineItem.getFofoOrderItemId());
2528
            FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(fofoOrderItem.getOrderId());
2529
            String reversalReason = "Scheme rolled back as activation date is invalid for imei " + inventoryItem.getSerialNumber();
34319 amit.gupta 2530
            //schemeService.reverseSchemes(Arrays.asList(inventoryItem), fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.ACTIVATION));
32145 tejbeer 2531
            schemeService.reverseSchemes(Arrays.asList(inventoryItem), fofoOrder.getId(), reversalReason, Arrays.asList(SchemeType.SPECIAL_SUPPORT));
27083 amit.gupta 2532
 
32145 tejbeer 2533
        }
24271 amit.gupta 2534
 
32145 tejbeer 2535
    }
24271 amit.gupta 2536
 
32145 tejbeer 2537
    @Override
2538
    public float getSales(int fofoId, LocalDateTime startDate, LocalDateTime endDate) {
2539
        Float sales = fofoOrderRepository.selectSaleSumGroupByFofoIds(startDate, endDate).get(fofoId);
2540
        return sales == null ? 0f : sales;
2541
    }
24271 amit.gupta 2542
 
32145 tejbeer 2543
    @Override
2544
    public LocalDateTime getMaxSalesDate(int fofoId, LocalDateTime startDate, LocalDateTime endDate) {
2545
        LocalDateTime dateTime = fofoOrderRepository.selectMaxSaleDateGroupByFofoIds(startDate, endDate).get(fofoId);
2546
        return dateTime;
2547
    }
25101 amit.gupta 2548
 
32145 tejbeer 2549
    @Override
2550
    // Only being used internally
2551
    public float getSales(int fofoId, LocalDate onDate) {
2552
        LocalDateTime startTime = LocalDateTime.of(onDate, LocalTime.MIDNIGHT);
2553
        LocalDateTime endTime = LocalDateTime.of(onDate, LocalTime.MIDNIGHT).plusDays(1);
2554
        return this.getSales(fofoId, startTime, endTime);
2555
    }
24917 tejbeer 2556
 
32145 tejbeer 2557
    @Override
2558
    public float getSales(LocalDateTime onDate) {
2559
        // TODO Auto-generated method stub
2560
        return 0;
2561
    }
28166 tejbeer 2562
 
32145 tejbeer 2563
    @Override
2564
    public float getSales(LocalDateTime startDate, LocalDateTime endDate) {
2565
        // TODO Auto-generated method stub
2566
        return 0;
2567
    }
28166 tejbeer 2568
 
32145 tejbeer 2569
    @Override
36305 amit 2570
    public boolean applyColorChange(int orderId, int itemId) throws ProfitMandiBusinessException {
32145 tejbeer 2571
        Order order = orderRepository.selectById(orderId);
2572
        saholicInventoryService.reservationCountByColor(itemId, order);
28166 tejbeer 2573
 
32145 tejbeer 2574
        order.getLineItem().setItemId(itemId);
2575
        Item item = itemRepository.selectById(itemId);
2576
        order.getLineItem().setColor(item.getColor());
2577
        return true;
2578
    }
28166 tejbeer 2579
 
32145 tejbeer 2580
    @Override
2581
    public FofoOrder getOrderByInventoryItemId(int inventoryItemId) throws Exception {
2582
        List<FofoLineItem> lineItems = fofoLineItemRepository.selectByInventoryItemId(inventoryItemId);
2583
        if (lineItems.size() > 0) {
2584
            FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(lineItems.get(0).getFofoOrderItemId());
2585
            fofoOrderItem.setFofoLineItems(new HashSet<>(lineItems));
2586
            FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(fofoOrderItem.getOrderId());
2587
            fofoOrder.setOrderItem(fofoOrderItem);
2588
            return fofoOrder;
2589
        } else {
2590
            throw new Exception(String.format("Could not find inventoryItemId - %s", inventoryItemId));
2591
        }
2592
    }
28166 tejbeer 2593
 
32145 tejbeer 2594
    @Override
2595
    public Map<Integer, Long> carryBagCreditCount(int fofoId) throws ProfitMandiBusinessException {
28166 tejbeer 2596
 
32145 tejbeer 2597
        FofoStore fs = fofoStoreRepository.selectByRetailerId(fofoId);
2598
        LocalDateTime lastCredit = fs.getBagsLastCredited();
2599
        /*
2600
         * long carryBagCount = 0; List<FofoOrder> fofoOrders =
2601
         * fofoOrderRepository.selectByFofoIdBetweenCreatedTimeStamp(fofoId,
2602
         * lastCredit.atStartOfDay(), LocalDate.now().plusDays(1).atStartOfDay()); for
2603
         * (FofoOrder fo : fofoOrders) { carryBagCount +=
2604
         * fofoOrderItemRepository.selectByOrderId(fo.getId()).stream() .filter(x ->
2605
         * x.getSellingPrice() >= 12000).count();
2606
         *
2607
         * }
2608
         */
28166 tejbeer 2609
 
32145 tejbeer 2610
        Session session = sessionFactory.getCurrentSession();
2611
        CriteriaBuilder cb = session.getCriteriaBuilder();
2612
 
2613
        CriteriaQuery<SimpleEntry> query = cb.createQuery(SimpleEntry.class);
2614
        Root<FofoOrder> fofoOrder = query.from(FofoOrder.class);
2615
        Root<FofoOrderItem> fofoOrderItem = query.from(FofoOrderItem.class);
2616
        Root<TagListing> tagListingRoot = query.from(TagListing.class);
2617
        Root<Item> itemRoot = query.from(Item.class);
2618
 
2619
        Predicate p2 = cb.between(fofoOrder.get(ProfitMandiConstants.CREATE_TIMESTAMP), lastCredit, LocalDate.now().atStartOfDay());
2620
        Predicate p3 = cb.isNull(fofoOrder.get("cancelledTimestamp"));
2621
        Predicate joinPredicate = cb.and(
2622
                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));
2623
        ItemCriteria itemCriteria = new ItemCriteria();
35236 amit 2624
        itemCriteria.setBrands(brandsService.getBrands(fofoId, null, 3).stream().map(x -> x.getName()).collect(Collectors.toList()));
32145 tejbeer 2625
        float startValue = 12000;
2626
        itemCriteria.setStartPrice(startValue);
2627
        itemCriteria.setEndPrice(0);
2628
        itemCriteria.setFeaturedPhone(false);
2629
        itemCriteria.setSmartPhone(true);
2630
        itemCriteria.setCatalogIds(new ArrayList<>());
2631
        itemCriteria.setExcludeCatalogIds(new ArrayList<>());
2632
        Predicate itemPredicate = itemRepository.getItemPredicate(itemCriteria, cb, itemRoot, tagListingRoot.get("itemId"), tagListingRoot.get("sellingPrice"));
2633
        Predicate finalPredicate = cb.and(itemPredicate, p2, p3, joinPredicate);
2634
        query = query.multiselect(fofoOrder.get(ProfitMandiConstants.FOFO_ID), cb.count(fofoOrder)).where(finalPredicate).groupBy(fofoOrder.get(ProfitMandiConstants.FOFO_ID));
2635
        List<SimpleEntry> simpleEntries = session.createQuery(query).getResultList();
2636
        Map<Integer, Long> returnMap = new HashMap<>();
2637
 
2638
        for (SimpleEntry simpleEntry : simpleEntries) {
2639
            returnMap.put((Integer) simpleEntry.getKey(), (Long) simpleEntry.getValue());
2640
        }
2641
        return returnMap;
2642
 
2643
    }
32607 ranu 2644
 
2645
    @Override
2646
    public void createMissingScratchOffers() {
2647
        List<FofoOrder> fofoOrders = fofoOrderRepository.selectFromSaleDate(LocalDate.of(2023, 11, 6).atStartOfDay());
2648
        for (FofoOrder fofoOrder : fofoOrders) {
2649
            if (fofoOrder.getCancelledTimestamp() == null) { // Check if cancelled_timestamp is not null
2650
                try {
2651
                    this.createScratchOffer(fofoOrder.getFofoId(), fofoOrder.getInvoiceNumber(), fofoOrder.getCustomerId());
2652
                } catch (Exception e) {
2653
                    LOGGER.error("Error while processing missing scratch offer invoice orderId", fofoOrder.getId());
2654
                }
2655
            }
2656
        }
2657
    }
32724 amit.gupta 2658
 
2659
    @Override
33665 ranu 2660
    public boolean refundOrder(int orderId, String refundedBy, String refundReason) throws
2661
            ProfitMandiBusinessException {
32724 amit.gupta 2662
        /*def refund_order(order_id, refunded_by, reason):
2663
        """
2664
        If the order is in RTO_RECEIVED_PRESTINE, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
2665
            1. Creates a refund request for batch processing.
2666
            2. Creates a return order for the warehouse executive to return the shipped material.
2667
            3. Marks the current order as RTO_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
2668
 
2669
        If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
2670
            1. Creates a refund request for batch processing.
2671
            2. Cancels the reservation of the item in the warehouse.
2672
            3. Marks the current order as the REFUNDED final state.
2673
 
2674
        For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
2675
            1. Cancels the reservation of the item in the warehouse.
2676
            2. Marks the current order as CANCELED.
2677
 
2678
        In all cases, it updates the reason for cancellation or refund and the person who performed the action.
2679
 
2680
        Returns True if it is successful, False otherwise.
2681
 
2682
        Throws an exception if the order with the given id couldn't be found.
2683
 
2684
        Parameters:
2685
         - order_id
2686
         - refunded_by
2687
         - reason
2688
        """
2689
        LOGGER.info("Refunding order id: {}", orderId);
2690
        Order order = orderRepository.selectById(orderId);
2691
 
2692
        if order.cod:
2693
        logging.info("Refunding COD order with status " + str(order.status))
2694
        status_transition = refund_status_transition
2695
        if order.status not in status_transition.keys():
2696
        raise TransactionServiceException(114, "This order can't be refunded")
2697
 
2698
        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]:
2699
        __update_inventory_reservation(order, refund=True)
2700
        order.statusDescription = "Order Cancelled"
2701
            #Shipment Id and Airway Bill No should be none in case of Cancellation
2702
        order.logisticsTransactionId = None
2703
        order.tracking_id = None
2704
        order.airwaybill_no = None
2705
        elif order.status == OrderStatus.BILLED:
2706
        __create_return_order(order)
2707
        order.statusDescription = "Order Cancelled"
2708
        elif order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT]:
2709
        if order.status != OrderStatus.RTO_LOST_IN_TRANSIT:
2710
        __create_return_order(order)
2711
        order.statusDescription = "RTO Refunded"
2712
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
2713
            #__create_return_order(order)
2714
        order.statusDescription = "Lost in Transit Refunded"
2715
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
2716
        if order.status != OrderStatus.DOA_LOST_IN_TRANSIT:
2717
        __create_return_order(order)
2718
        __create_refund(order, 0, 'Should be unreachable for now')
2719
        order.statusDescription = "DOA Refunded"
2720
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
2721
        if order.status != OrderStatus.RET_LOST_IN_TRANSIT:
2722
        __create_return_order(order)
2723
        __create_refund(order, 0, 'Should be unreachable for now')
2724
        order.statusDescription = "Return Refunded"
2725
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
2726
        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]:
2727
        __update_inventory_reservation(order, refund=True)
2728
        order.statusDescription = "Order Cancelled on customer request"
2729
        elif order.previousStatus == OrderStatus.BILLED:
2730
        __create_return_order(order)
2731
        order.statusDescription = "Order Cancelled on customer request"
2732
        order.received_return_timestamp = datetime.datetime.now()
2733
    else:
2734
        status_transition = {OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
2735
                OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
2736
                OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
2737
                OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
2738
                OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
2739
                OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
2740
                OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
2741
                OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
2742
                OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
2743
                OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
2744
                OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
2745
                OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
2746
                OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2747
                OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2748
                OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2749
                OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2750
                OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2751
                OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2752
                OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
2753
                OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST,
2754
                OrderStatus.PAYMENT_FLAGGED : OrderStatus.PAYMENT_FLAGGED_DENIED
2755
                     }
2756
        if order.status not in status_transition.keys():
2757
        raise TransactionServiceException(114, "This order can't be refunded")
2758
 
2759
        if order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT] :
2760
        if order.status != OrderStatus.RTO_LOST_IN_TRANSIT:
2761
        __create_return_order(order)
2762
        __create_refund(order, order.wallet_amount, 'Order #{0} is RTO refunded'.format(order.id))
2763
        order.statusDescription = "RTO Refunded"
2764
            #Start:- Added By Manish Sharma for Creating a new Ticket: Category- RTO Refund on 21-Jun-2013
2765
        try:
2766
        crmServiceClient = CRMClient().get_client()
2767
        ticket =Ticket()
2768
        activity = Activity()
2769
 
2770
        description = "Creating Ticket for " + order.statusDescription + " Order"
2771
        ticket.creatorId = 1
2772
        ticket.assigneeId = 34
2773
        ticket.category = TicketCategory.RTO_REFUND
2774
        ticket.priority = TicketPriority.MEDIUM
2775
        ticket.status = TicketStatus.OPEN
2776
        ticket.description = description
2777
        ticket.orderId = order.id
2778
 
2779
        activity.creatorId = 1
2780
        activity.ticketAssigneeId = ticket.assigneeId
2781
        activity.type = ActivityType.OTHER
2782
        activity.description = description
2783
        activity.ticketCategory = ticket.category
2784
        activity.ticketDescription = ticket.description
2785
        activity.ticketPriority = ticket.priority
2786
        activity.ticketStatus = ticket.status
2787
 
2788
        ticket.customerId= order.customer_id
2789
        ticket.customerEmailId = order.customer_email
2790
        ticket.customerMobileNumber = order.customer_mobilenumber
2791
        ticket.customerName = order.customer_name
2792
        activity.customerId = ticket.customerId
2793
        activity.customerEmailId = order.customer_email
2794
        activity.customerMobileNumber = order.customer_mobilenumber
2795
        activity.customerName = order.customer_name
2796
 
2797
        crmServiceClient.insertTicket(ticket, activity)
2798
 
2799
        except:
2800
        print "Ticket for RTO Refund is not created."
2801
            #End:- Added By Manish Sharma for Creating a new Ticket: Category- RTO Refund on 21-Jun-2013
2802
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
2803
            #__create_return_order(order)
2804
        __create_refund(order, order.wallet_amount, 'Order #{0} is Lost in Transit'.format(order.id))
2805
        order.statusDescription = "Lost in Transit Refunded"
2806
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
2807
        if order.status != OrderStatus.DOA_LOST_IN_TRANSIT:
2808
        __create_return_order(order)
2809
        __create_refund(order, 0, 'This should be unreachable')
2810
        order.statusDescription = "DOA Refunded"
2811
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
2812
        if order.status != OrderStatus.RET_LOST_IN_TRANSIT:
2813
        __create_return_order(order)
2814
        __create_refund(order, 0, 'This should be unreachable')
2815
        order.statusDescription = "Return Refunded"
2816
        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]:
2817
        __update_inventory_reservation(order, refund=True)
2818
        order.statusDescription = "Order Refunded"
2819
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
2820
        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]:
2821
        __update_inventory_reservation(order, refund=True)
2822
        order.statusDescription = "Order Cancelled on customer request"
2823
        elif order.previousStatus == OrderStatus.BILLED:
2824
        __create_refund(order, order.wallet_amount,  'Order #{0} Cancelled on customer request'.format(order.id))
2825
        order.statusDescription = "Order Cancelled on customer request"
2826
 
2827
        elif order.status == OrderStatus.PAYMENT_FLAGGED:
2828
        __update_inventory_reservation(order, refund=True)
2829
        order.statusDescription = "Order Cancelled due to payment flagged"
2830
 
2831
    # For orders that are cancelled after being billed, we need to scan in the scanned out
2832
    # inventory item and change availability accordingly
2833
        inventoryClient = InventoryClient().get_client()
2834
        warehouse = inventoryClient.getWarehouse(order.warehouse_id)
2835
        if warehouse.billingType == BillingType.OURS or warehouse.billingType == BillingType.OURS_EXTERNAL:
2836
        #Now BILLED orders can also be refunded directly with low inventory cancellations
2837
        if order.status in [OrderStatus.BILLED, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_FROM_WH]:
2838
        __create_refund(order, order.wallet_amount, reason)
2839
        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]):
2840
        lineitem = order.lineitems[0]
2841
        catalogClient = CatalogClient().get_client()
2842
        item = catalogClient.getItem(lineitem.item_id)
2843
        warehouseClient = WarehouseClient().get_client()
2844
        if warehouse.billingType == BillingType.OURS:
2845
        if ItemType.SERIALIZED == item.type:
2846
        for serial_number in str(lineitem.serial_number).split(','):
2847
        warehouseClient.scanSerializedItemForOrder(serial_number, ScanType.SALE_RET, order.id, order.fulfilmentWarehouseId, 1, order.warehouse_id)
2848
                else:
2849
        warehouseClient.scanForOrder(None, ScanType.SALE_RET, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
2850
        if warehouse.billingType == BillingType.OURS_EXTERNAL:
2851
        warehouseClient.scanForOursExternalSaleReturn(order.id, lineitem.transfer_price)
2852
        if order.freebieItemId:
2853
        warehouseClient.scanfreebie(order.id, order.freebieItemId, 0, ScanType.SALE_RET)
2854
 
2855
        order.status = status_transition[order.status]
2856
        order.statusDescription = OrderStatus._VALUES_TO_NAMES[order.status]
2857
        order.refund_timestamp = datetime.datetime.now()
2858
        order.refunded_by = refunded_by
2859
        order.refund_reason = reason
2860
    #to re evaluate the shipping charge if any order is being cancelled.
2861
    #_revaluate_shiping(order_id)
2862
        session.commit()
2863
        return True*/
2864
        return true;
2865
    }
2866
 
2867
    @Autowired
2868
    DebitNoteRepository debitNoteRepository;
2869
 
2870
    //initiate refund only if the stock is returned
2871
 
25724 amit.gupta 2872
}