Subversion Repositories SmartDukaan

Rev

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