Subversion Repositories SmartDukaan

Rev

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