Subversion Repositories SmartDukaan

Rev

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