Subversion Repositories SmartDukaan

Rev

Rev 36362 | Rev 36562 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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