Subversion Repositories SmartDukaan

Rev

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