Subversion Repositories SmartDukaan

Rev

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