Subversion Repositories SmartDukaan

Rev

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

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