Subversion Repositories SmartDukaan

Rev

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