Subversion Repositories SmartDukaan

Rev

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

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