Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
27877 amit.gupta 1
package com.spice.profitmandi.service.offers;
2
 
29783 amit.gupta 3
import com.google.common.collect.Lists;
27877 amit.gupta 4
import com.google.gson.Gson;
5
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
33030 amit.gupta 6
import com.spice.profitmandi.common.model.CustomRetailer;
29683 amit.gupta 7
import com.spice.profitmandi.common.model.PartnerTargetModel;
8
import com.spice.profitmandi.common.model.ProfitMandiConstants;
33999 tejus.loha 9
import com.spice.profitmandi.common.util.FileUtil;
35205 amit 10
import com.spice.profitmandi.common.util.FormattingUtils;
31920 amit.gupta 11
import com.spice.profitmandi.common.util.Utils;
27877 amit.gupta 12
import com.spice.profitmandi.dao.entity.catalog.ItemCriteria;
13
import com.spice.profitmandi.dao.entity.catalog.Offer;
29783 amit.gupta 14
import com.spice.profitmandi.dao.entity.catalog.TagListing;
31903 amit.gupta 15
import com.spice.profitmandi.dao.entity.catalog.TargetSlabEntity;
31920 amit.gupta 16
import com.spice.profitmandi.dao.entity.fofo.FofoLineItem;
17
import com.spice.profitmandi.dao.entity.fofo.FofoOrderItem;
31205 amit.gupta 18
import com.spice.profitmandi.dao.entity.fofo.InventoryItem;
19
import com.spice.profitmandi.dao.entity.fofo.OfferPayout;
31920 amit.gupta 20
import com.spice.profitmandi.dao.entity.transaction.LineItem;
21
import com.spice.profitmandi.dao.entity.transaction.Order;
31747 amit.gupta 22
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
31920 amit.gupta 23
import com.spice.profitmandi.dao.entity.warehouse.WarehouseInventoryItem;
24
import com.spice.profitmandi.dao.entity.warehouse.WarehouseScan;
25
import com.spice.profitmandi.dao.enumuration.catalog.AchievementType;
29783 amit.gupta 26
import com.spice.profitmandi.dao.enumuration.catalog.AmountType;
29499 amit.gupta 27
import com.spice.profitmandi.dao.enumuration.catalog.OfferSchemeType;
31205 amit.gupta 28
import com.spice.profitmandi.dao.enumuration.transaction.SchemePayoutStatus;
35394 amit 29
import com.spice.profitmandi.dao.model.*;
35856 amit 30
import com.spice.profitmandi.dao.repository.GenericRepository;
30066 amit.gupta 31
import com.spice.profitmandi.dao.repository.catalog.*;
35205 amit 32
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
31920 amit.gupta 33
import com.spice.profitmandi.dao.repository.fofo.ActivatedImeiRepository;
34
import com.spice.profitmandi.dao.repository.fofo.InventoryItemRepository;
31205 amit.gupta 35
import com.spice.profitmandi.dao.repository.fofo.OfferPayoutRepository;
31920 amit.gupta 36
import com.spice.profitmandi.dao.repository.transaction.LineItemImeisRepository;
33087 amit.gupta 37
import com.spice.profitmandi.dao.repository.warehouse.AgeingSummaryModel;
31920 amit.gupta 38
import com.spice.profitmandi.dao.repository.warehouse.WarehouseInventoryItemRepository;
39
import com.spice.profitmandi.dao.repository.warehouse.WarehouseScanRepository;
35205 amit 40
import com.spice.profitmandi.service.NotificationService;
31920 amit.gupta 41
import com.spice.profitmandi.service.pricecircular.PriceCircularService;
42
import com.spice.profitmandi.service.scheme.InventoryPayoutModel;
27877 amit.gupta 43
import com.spice.profitmandi.service.user.RetailerService;
31205 amit.gupta 44
import com.spice.profitmandi.service.wallet.WalletService;
35205 amit 45
import com.spice.profitmandi.service.whatsapp.WhatsappMessageType;
31205 amit.gupta 46
import in.shop2020.model.v1.order.WalletReferenceType;
33999 tejus.loha 47
import org.apache.commons.io.output.ByteArrayOutputStream;
30066 amit.gupta 48
import org.apache.logging.log4j.LogManager;
49
import org.apache.logging.log4j.Logger;
50
import org.apache.poi.ss.usermodel.Cell;
51
import org.apache.poi.ss.usermodel.CellType;
52
import org.apache.poi.ss.usermodel.Row;
53
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
54
import org.apache.poi.xssf.usermodel.XSSFRow;
55
import org.apache.poi.xssf.usermodel.XSSFSheet;
56
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
57
import org.springframework.beans.factory.annotation.Autowired;
58
import org.springframework.cache.CacheManager;
59
import org.springframework.cache.annotation.Cacheable;
60
import org.springframework.stereotype.Component;
27877 amit.gupta 61
 
30066 amit.gupta 62
import java.io.IOException;
63
import java.io.InputStream;
64
import java.time.LocalDate;
31205 amit.gupta 65
import java.time.LocalDateTime;
30066 amit.gupta 66
import java.time.YearMonth;
67
import java.util.*;
68
import java.util.stream.Collectors;
69
 
27877 amit.gupta 70
@Component
71
public class OfferServiceImpl implements OfferService {
72
 
35394 amit 73
    private static final Logger LOGGER = LogManager.getLogger(OfferServiceImpl.class);
29499 amit.gupta 74
 
35394 amit 75
    // Constants
76
    private static final List<String> TARGETS = Arrays.asList("Target 1", "Target 2", "Target 3", "Target 4", "Target 5");
77
    private static final int STOCK_AGEING_THRESHOLD_DAYS = 300;
78
 
79
    // Dependencies - Core
31747 amit.gupta 80
    @Autowired
81
    private Gson gson;
27877 amit.gupta 82
 
31747 amit.gupta 83
    @Autowired
36049 amit 84
    private OfferService offerServiceProxy; // self-injection for Spring cache proxy
35205 amit 85
 
36049 amit 86
    @Autowired
87
    private CacheManager redisCacheManager;
88
 
89
    @Autowired
90
    private CacheManager redisShortCacheManager;
91
 
35394 amit 92
    // Dependencies - Repositories
35205 amit 93
    @Autowired
35856 amit 94
    private GenericRepository genericRepository;
95
 
96
    @Autowired
31747 amit.gupta 97
    private OfferRepository offerRepository;
27877 amit.gupta 98
 
31747 amit.gupta 99
    @Autowired
35394 amit 100
    private OfferPayoutRepository offerPayoutRepository;
27877 amit.gupta 101
 
31747 amit.gupta 102
    @Autowired
35394 amit 103
    private OfferTargetSlabRepository offerTargetSlabRepository;
31205 amit.gupta 104
 
31747 amit.gupta 105
    @Autowired
106
    private ItemCriteriaRepository itemCriteriaRepository;
27877 amit.gupta 107
 
31747 amit.gupta 108
    @Autowired
109
    private ItemRepository itemRepository;
27877 amit.gupta 110
 
31747 amit.gupta 111
    @Autowired
112
    private TagListingRepository tagListingRepository;
29783 amit.gupta 113
 
31747 amit.gupta 114
    @Autowired
35205 amit 115
    private FofoStoreRepository fofoStoreRepository;
30684 amit.gupta 116
 
31747 amit.gupta 117
    @Autowired
35394 amit 118
    private ActivatedImeiRepository activatedImeiRepository;
27877 amit.gupta 119
 
31920 amit.gupta 120
    @Autowired
121
    private WarehouseScanRepository warehouseScanRepository;
122
 
123
    @Autowired
124
    private WarehouseInventoryItemRepository warehouseInventoryItemRepository;
125
 
126
    @Autowired
127
    private LineItemImeisRepository lineItemImeisRepository;
35394 amit 128
 
31920 amit.gupta 129
    @Autowired
130
    private InventoryItemRepository inventoryItemRepository;
131
 
35394 amit 132
    @Autowired
133
    private OfferEligibleImeiRepository offerEligibleImeiRepository;
134
 
135
    // Dependencies - Services
136
    @Autowired
137
    private NotificationService notificationService;
138
 
139
    @Autowired
140
    private RetailerService retailerService;
141
 
142
    @Autowired
143
    private PriceCircularService priceCircularService;
144
 
145
    @Autowired
146
    private WalletService walletService;
147
 
31747 amit.gupta 148
    @Override
36049 amit 149
    public void evictOfferCaches(int offerId) {
150
        Offer offer = offerRepository.selectById(offerId);
151
        YearMonth ym = YearMonth.from(offer.getStartDate());
152
        redisCacheManager.getCache("offer.definition").evict(offerId);
153
        redisCacheManager.getCache("allOffers").evict(ym);
154
        redisCacheManager.getCache("catalog.published_yearmonth").evict(ym);
155
        redisCacheManager.getCache("offer.slabpayout").evict(offerId);
156
        redisCacheManager.getCache("offer.achievement").clear();
157
        redisShortCacheManager.getCache("todayOffers").clear();
158
    }
159
 
160
    @Override
31747 amit.gupta 161
    public void addOfferService(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
162
        LOGGER.info("createOfferRequest  -- {}", createOfferRequest);
163
        this.createOffer(createOfferRequest);
164
        this.createTargetSlabs(createOfferRequest);
165
    }
27877 amit.gupta 166
 
31747 amit.gupta 167
    private void createOffer(CreateOfferRequest createOfferRequest) {
168
        Offer offer = new Offer();
169
        offer.setName(createOfferRequest.getName());
170
        offer.setTargetType(createOfferRequest.getTargetType());
171
        offer.setBooster(createOfferRequest.isBooster());
172
        offer.setPayoutType(createOfferRequest.getPayoutType());
173
        offer.setSchemeType(createOfferRequest.getSchemeType());
174
        offer.setBaseCriteia(createOfferRequest.isBaseCriteria());
175
        offer.setEndDate(createOfferRequest.getEndDate());
176
        offer.setStartDate(createOfferRequest.getStartDate());
177
        offer.setBrandSharePercentage(createOfferRequest.getBrandShareTerms());
178
        offer.setSellinPercentage(createOfferRequest.getSellinPercentage());
179
        offer.setOfferNotes(createOfferRequest.getOfferNotes());
180
        offer.setActivationBrands(createOfferRequest.getActivationBrands());
181
        offer.setTerms(createOfferRequest.getTerms());
182
        offer.setItemCriteria(gson.toJson(createOfferRequest.getItemCriteria()));
183
        offer.setPartnerCriteria(gson.toJson(createOfferRequest.getPartnerCriteria()));
32070 amit.gupta 184
        offer.setDiscount(createOfferRequest.isDiscount());
31747 amit.gupta 185
        offerRepository.persist(offer);
186
        createOfferRequest.setId(offer.getId());
187
    }
27877 amit.gupta 188
 
31747 amit.gupta 189
    @Override
33247 ranu 190
    public List<CreateOfferRequest> getPublishedOffers(int fofoId, YearMonth yearMonth) throws ProfitMandiBusinessException {
36049 amit 191
        // Past months (>1 month ago): achievement is frozen, cache the full result
192
        if (yearMonth.isBefore(YearMonth.now().minusMonths(1))) {
193
            return offerServiceProxy.getPublishedOffersCached(fofoId, yearMonth);
194
        }
195
        // Current/recent month: assemble live from cached building blocks
196
        return assemblePublishedOffers(fofoId, yearMonth);
197
    }
198
 
199
    @Cacheable(value = "publishedOffersWithAchievement.past", cacheManager = "redisCacheManager")
200
    public List<CreateOfferRequest> getPublishedOffersCached(int fofoId, YearMonth yearMonth) throws ProfitMandiBusinessException {
201
        return assemblePublishedOffers(fofoId, yearMonth);
202
    }
203
 
204
    private List<CreateOfferRequest> assemblePublishedOffers(int fofoId, YearMonth yearMonth) throws ProfitMandiBusinessException {
35394 amit 205
        Map<Integer, List<Offer>> publishedMapByPartner = offerRepository.selectAllPublishedMapByPartner(yearMonth);
206
        List<Offer> publishedOffers = publishedMapByPartner != null ? publishedMapByPartner.get(fofoId) : null;
31747 amit.gupta 207
        List<CreateOfferRequest> createOfferRequests = new ArrayList<>();
208
        if (publishedOffers != null) {
209
            for (Offer offer : publishedOffers) {
36049 amit 210
                CreateOfferRequest copy = deepCopy(this.getCreateOfferRequest(offer));
211
                setCriteriaPayoutAchieved(fofoId, copy);
212
                createOfferRequests.add(copy);
31747 amit.gupta 213
            }
214
        }
215
        return createOfferRequests;
216
    }
27877 amit.gupta 217
 
31747 amit.gupta 218
    private void setCriteriaPayoutAchieved(int fofoId, CreateOfferRequest createOfferRequest) {
36049 amit 219
        Map<Integer, Long> criteriaTransactionMap;
31747 amit.gupta 220
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
36049 amit 221
            criteriaTransactionMap = offerRepository.getPurchaseSumForPartner(
222
                    createOfferRequest.getId(), fofoId, createOfferRequest);
31747 amit.gupta 223
        } else {
36049 amit 224
            criteriaTransactionMap = offerRepository.getSalesSumForPartner(
225
                    createOfferRequest.getId(), fofoId, createOfferRequest);
31747 amit.gupta 226
        }
227
        List<com.spice.profitmandi.dao.model.ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest
228
                .getTargetSlabs().get(0).getItemCriteriaPayouts();
27877 amit.gupta 229
 
31747 amit.gupta 230
        for (com.spice.profitmandi.dao.model.ItemCriteriaPayout itemCriteriaPayout : itemCriteriaPayouts) {
231
            itemCriteriaPayout.setNextSlab(null);
232
            long saleAmount = 0;
233
            if (criteriaTransactionMap != null
234
                    && criteriaTransactionMap.containsKey(itemCriteriaPayout.getItemCriteria().getId())) {
31853 amit.gupta 235
                saleAmount = criteriaTransactionMap.containsKey(0) ? criteriaTransactionMap.get(0) : criteriaTransactionMap.get(itemCriteriaPayout.getItemCriteria().getId());
31747 amit.gupta 236
            }
237
            itemCriteriaPayout.setAchievedValue(saleAmount);
238
            List<com.spice.profitmandi.service.offers.PayoutSlab> payoutSlabs = itemCriteriaPayout.getPayoutSlabs();
239
            for (int i = 0; i < payoutSlabs.size(); i++) {
240
                com.spice.profitmandi.service.offers.PayoutSlab beginSlab = payoutSlabs.get(i);
241
                com.spice.profitmandi.service.offers.PayoutSlab endSlab = null;
242
                if (payoutSlabs.size() - 1 > i) {
243
                    endSlab = payoutSlabs.get(i + 1);
244
                }
245
                if (beginSlab.getOnwardsAmount() > saleAmount) {
246
                    itemCriteriaPayout.setShortValue(beginSlab.getOnwardsAmount() - saleAmount);
247
                    itemCriteriaPayout.setNextSlab(beginSlab);
248
                    break;
249
                }
250
                if (endSlab != null) {
251
                    if (beginSlab.getOnwardsAmount() <= saleAmount && endSlab.getOnwardsAmount() > saleAmount) {
252
                        itemCriteriaPayout.setCurrentSlab(beginSlab);
253
                        beginSlab.setSelected(true);
254
                        itemCriteriaPayout.setNextSlab(endSlab);
255
                        itemCriteriaPayout.setShortValue(endSlab.getOnwardsAmount() - saleAmount);
256
                        break;
257
                    }
258
                } else {
259
                    beginSlab.setSelected(true);
260
                    itemCriteriaPayout.setCurrentSlab(beginSlab);
261
                }
262
            }
263
        }
264
    }
27877 amit.gupta 265
 
31747 amit.gupta 266
    @Override
36049 amit 267
    @Cacheable(value = "allOffers", cacheManager = "redisCacheManager")
33247 ranu 268
    public Map<Integer, CreateOfferRequest> getAllOffers(YearMonth yearMonth) throws ProfitMandiBusinessException {
31747 amit.gupta 269
        List<Offer> allOffers = offerRepository.selectAll(yearMonth, false);
270
        List<CreateOfferRequest> createOfferRequests = new ArrayList<>();
271
        for (Offer offer : allOffers) {
272
            CreateOfferRequest createOfferRequest = this.getCreateOfferRequest(offer);
273
            createOfferRequests.add(createOfferRequest);
274
        }
275
        return createOfferRequests.stream().collect(Collectors.toMap(CreateOfferRequest::getId, x -> x));
276
    }
27877 amit.gupta 277
 
36049 amit 278
    private CreateOfferRequest deepCopy(CreateOfferRequest source) {
279
        return gson.fromJson(gson.toJson(source), CreateOfferRequest.class);
280
    }
281
 
31747 amit.gupta 282
    @Override
36049 amit 283
    @Cacheable(value = "offer.definition", cacheManager = "redisCacheManager", key = "#offerId")
284
    public CreateOfferRequest getOfferDefinition(int offerId) throws ProfitMandiBusinessException {
285
        Offer offer = offerRepository.selectById(offerId);
286
        return this.getCreateOfferRequest(offer);
287
    }
288
 
289
    @Override
33247 ranu 290
    public CreateOfferRequest getOffer(int fofoId, int offerId) throws ProfitMandiBusinessException {
36049 amit 291
        CreateOfferRequest definition = offerServiceProxy.getOfferDefinition(offerId);
31747 amit.gupta 292
        if (fofoId > 0) {
36049 amit 293
            CreateOfferRequest copy = deepCopy(definition);
294
            copy.setCriteriaQtyAmountModel(this.getCriteriaQtyAmounModelMap(copy, fofoId));
295
            return copy;
31747 amit.gupta 296
        }
36049 amit 297
        return definition;
31747 amit.gupta 298
    }
27877 amit.gupta 299
 
31747 amit.gupta 300
    @Override
33247 ranu 301
    public CreateOfferRequest getCreateOfferRequest(Offer fromOffer) throws ProfitMandiBusinessException {
31747 amit.gupta 302
        CreateOfferRequest createOfferRequest = new CreateOfferRequest();
303
        createOfferRequest.setName(fromOffer.getName());
32023 amit.gupta 304
        createOfferRequest.setDiscount(fromOffer.isDiscount());
31747 amit.gupta 305
        createOfferRequest.setTargetType(fromOffer.getTargetType());
306
        createOfferRequest.setPayoutType(fromOffer.getPayoutType());
307
        createOfferRequest.setSchemeType(fromOffer.getSchemeType());
308
        createOfferRequest.setActivationBrands(fromOffer.getActivationBrands());
309
        createOfferRequest.setEndDate(fromOffer.getEndDate());
310
        createOfferRequest.setProcessTimestamp(fromOffer.getProcessedTimestamp());
311
        createOfferRequest.setStartDate(fromOffer.getStartDate());
312
        createOfferRequest.setBooster(fromOffer.isBooster());
313
        createOfferRequest.setActive(fromOffer.isActive());
314
        createOfferRequest.setSellinPercentage(fromOffer.getSellinPercentage());
315
        createOfferRequest.setBrandShareTerms(fromOffer.getBrandSharePercentage());
316
        createOfferRequest.setOfferNotes(fromOffer.getOfferNotes());
317
        createOfferRequest.setTerms(fromOffer.getTerms());
318
        createOfferRequest.setBaseCriteria(fromOffer.isBaseCriteia());
319
        createOfferRequest.setItemCriteria(
320
                gson.fromJson(fromOffer.getItemCriteria(), com.spice.profitmandi.service.offers.ItemCriteria.class));
321
        createOfferRequest.setPartnerCriteria(gson.fromJson(fromOffer.getPartnerCriteria(), PartnerCriteria.class));
322
        createOfferRequest.setId(fromOffer.getId());
323
        createOfferRequest.setCreatedOn(fromOffer.getCreatedTimestamp());
324
        createOfferRequest.setItemCriteriaString(
325
                itemCriteriaRepository.getItemCriteriaDescription(createOfferRequest.getItemCriteria()));
326
        List<com.spice.profitmandi.dao.model.TargetSlab> targetSlabs = offerTargetSlabRepository
327
                .getByOfferId(fromOffer.getId());
328
        createOfferRequest.setPartnerCriteriaString(
33030 amit.gupta 329
                this.getPartnerCriteriaString(createOfferRequest.getPartnerCriteria()));
31747 amit.gupta 330
        createOfferRequest.setTargetSlabs(targetSlabs);
35885 amit 331
        if (!targetSlabs.isEmpty() && !targetSlabs.get(0).getItemCriteriaPayouts().isEmpty()) {
332
            for (com.spice.profitmandi.dao.model.ItemCriteriaPayout itemCriteriaPayout : targetSlabs.get(0).getItemCriteriaPayouts()) {
333
                if (!itemCriteriaPayout.getPayoutSlabs().isEmpty()) {
334
                    itemCriteriaPayout.setNextSlab(itemCriteriaPayout.getPayoutSlabs().get(0));
335
                }
336
            }
31747 amit.gupta 337
        }
338
        return createOfferRequest;
339
    }
27877 amit.gupta 340
 
31747 amit.gupta 341
    @Override
33613 amit.gupta 342
    public void reverseAdditionalSelloutSchemes(List<InventoryItem> inventoryItems, String reversalReason) throws ProfitMandiBusinessException {
343
        Map<Integer, List<InventoryItem>> fofoInventoryItemsMap = inventoryItems.stream().collect(Collectors.groupingBy(x -> x.getFofoId()));
344
        for (Map.Entry<Integer, List<InventoryItem>> fofoInventoryItemsEntry : fofoInventoryItemsMap.entrySet()) {
345
            int fofoId = fofoInventoryItemsEntry.getKey();
346
            List<InventoryItem> partnerInventoryItems = fofoInventoryItemsEntry.getValue();
347
            List<OfferPayout> offerPayouts = new ArrayList<>();
348
            LOGGER.info("Reversing schemes for fofoId {}, InventoryItems {}", fofoId, inventoryItems);
349
            //As of now we are not handling non-serialised items
35394 amit 350
            List<InventoryItem> serializedItems = partnerInventoryItems.stream().filter(x -> x.getSerialNumber() != null).collect(Collectors.toList());
351
            if (serializedItems.size() > 0) {
352
                // Batch fetch: collect all serial numbers and fetch in one call per fofoId
353
                Set<String> serialNumbers = serializedItems.stream().map(InventoryItem::getSerialNumber).collect(Collectors.toSet());
354
                offerPayouts = offerPayoutRepository.selectAllBySerialNumbers(fofoId, serialNumbers)
355
                        .stream()
356
                        .filter(x -> x.getRejectTimestamp() == null)
357
                        .collect(Collectors.toList());
33613 amit.gupta 358
                for (OfferPayout offerPayout : offerPayouts) {
359
                    offerPayout.setStatus(SchemePayoutStatus.REJECTED);
360
                    offerPayout.setRejectTimestamp(LocalDateTime.now());
361
                }
362
                Map<Long, Double> offerPayoutAmountMap = offerPayouts.stream().collect(Collectors.groupingBy(x -> x.getOfferId(), Collectors.summingDouble(x -> x.getAmount())));
363
                for (Map.Entry<Long, Double> offerPayoutEntry : offerPayoutAmountMap.entrySet()) {
364
                    List<UserWalletHistory> histories = walletService.getAllByReference(fofoId, offerPayoutEntry.getKey().intValue(), WalletReferenceType.ADDITIONAL_SCHEME);
365
                    if (histories.size() > 0) {
31750 amit.gupta 366
 
33613 amit.gupta 367
                        walletService.rollbackAmountFromWallet(fofoId, offerPayoutEntry.getValue().floatValue(), offerPayoutEntry.getKey().intValue(),
368
                                WalletReferenceType.ADDITIONAL_SCHEME, reversalReason, LocalDateTime.now());
369
                    }
31750 amit.gupta 370
                }
371
            }
31747 amit.gupta 372
        }
373
    }
30684 amit.gupta 374
 
36103 amit 375
    @Override
376
    public void restoreAdditionalSelloutSchemes(List<InventoryItem> inventoryItems, String restoreReason)
377
            throws ProfitMandiBusinessException {
378
        Map<Integer, List<InventoryItem>> fofoInventoryItemsMap = inventoryItems.stream()
379
                .collect(Collectors.groupingBy(InventoryItem::getFofoId));
380
        for (Map.Entry<Integer, List<InventoryItem>> entry : fofoInventoryItemsMap.entrySet()) {
381
            int fofoId = entry.getKey();
382
            List<InventoryItem> partnerItems = entry.getValue();
383
 
384
            List<InventoryItem> serializedItems = partnerItems.stream()
385
                    .filter(x -> x.getSerialNumber() != null)
386
                    .collect(Collectors.toList());
387
            if (!serializedItems.isEmpty()) {
388
                Set<String> serialNumbers = serializedItems.stream()
389
                        .map(InventoryItem::getSerialNumber).collect(Collectors.toSet());
390
                List<OfferPayout> offerPayouts = offerPayoutRepository
391
                        .selectAllBySerialNumbers(fofoId, serialNumbers).stream()
392
                        .filter(x -> x.getRejectTimestamp() != null
393
                                && SchemePayoutStatus.REJECTED.equals(x.getStatus()))
394
                        .collect(Collectors.toList());
395
 
396
                for (OfferPayout offerPayout : offerPayouts) {
397
                    offerPayout.setStatus(SchemePayoutStatus.CREDITED);
398
                    offerPayout.setRejectTimestamp(null);
399
                }
400
 
401
                Map<Long, Double> offerPayoutAmountMap = offerPayouts.stream()
402
                        .collect(Collectors.groupingBy(OfferPayout::getOfferId,
403
                                Collectors.summingDouble(OfferPayout::getAmount)));
404
                for (Map.Entry<Long, Double> offerEntry : offerPayoutAmountMap.entrySet()) {
405
                    if (offerEntry.getValue() > 0) {
406
                        walletService.addAmountToWallet(fofoId, offerEntry.getKey().intValue(),
407
                                WalletReferenceType.ADDITIONAL_SCHEME, restoreReason,
408
                                offerEntry.getValue().floatValue(), LocalDateTime.now());
409
                    }
410
                }
411
            }
412
        }
413
    }
414
 
31747 amit.gupta 415
    private void createTargetSlabs(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
416
        List<com.spice.profitmandi.dao.model.TargetSlab> targetSlabs = createOfferRequest.getTargetSlabs().stream()
417
                .filter(x -> x.validate()).collect(Collectors.toList());
35394 amit 418
        if (!targetSlabs.isEmpty()) {
31747 amit.gupta 419
            Collections.sort(targetSlabs);
420
            for (com.spice.profitmandi.dao.model.TargetSlab targetSlab : targetSlabs) {
421
                if (targetSlab.validate()) {
422
                    List<ItemCriteriaPayout> itemCriteriaPayouts = targetSlab.getItemCriteriaPayouts();
423
                    for (ItemCriteriaPayout itemCriteriaPayout : itemCriteriaPayouts) {
424
                        ItemCriteria itemCriteria = itemCriteriaRepository.selectById(itemCriteriaPayout.getItemCriteria().getId());
425
                        if (itemCriteriaPayout.getItemCriteria().getId() > 0) {
426
                            itemCriteriaPayout.getItemCriteria().setId(0);
427
                        } else {
428
                            String itemCriteriaJson = gson.toJson(itemCriteriaPayout.getItemCriteria());
429
                            itemCriteria = itemCriteriaRepository.selectByCriteria(itemCriteriaJson);
430
                            // ItemCriteria Only once
431
                            if (itemCriteria == null) {
432
                                itemCriteria = new ItemCriteria();
433
                                itemCriteria.setCriteria(gson.toJson(itemCriteriaPayout.getItemCriteria()));
434
                                itemCriteriaRepository.persist(itemCriteria);
435
                            }
436
                        }
437
                        for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
31903 amit.gupta 438
                            TargetSlabEntity targetSlabEntity = new TargetSlabEntity();
439
                            targetSlabEntity.setOfferId(createOfferRequest.getId());
440
                            targetSlabEntity.setOnwardsTarget(targetSlab.getOnwardsAmount());
441
                            targetSlabEntity.setTargetDescription(targetSlab.getTargetDescription());
442
                            targetSlabEntity.setPayoutTarget(payoutSlab.getOnwardsAmount());
443
                            targetSlabEntity.setPayoutValue(payoutSlab.getPayoutAmount());
444
                            targetSlabEntity.setItemCriteriaId(itemCriteria.getId());
445
                            targetSlabEntity.setAmountType(itemCriteriaPayout.getAmountType());
32979 amit.gupta 446
                            targetSlabEntity.setStartDate(itemCriteriaPayout.getStartDate());
447
                            targetSlabEntity.setEndDate(itemCriteriaPayout.getEndDate());
31903 amit.gupta 448
                            offerTargetSlabRepository.persist(targetSlabEntity);
31747 amit.gupta 449
                        }
450
                    }
451
                }
452
            }
27877 amit.gupta 453
 
31747 amit.gupta 454
        } else {
455
            throw new ProfitMandiBusinessException("Invalid Target Slabs", "Invalid Target", "");
456
        }
27877 amit.gupta 457
 
31747 amit.gupta 458
    }
27877 amit.gupta 459
 
31747 amit.gupta 460
    @Override
33247 ranu 461
    public List<CreateOfferRequest> getPublishedOffers(LocalDate date, int fofoId, int catalogId) throws ProfitMandiBusinessException {
35394 amit 462
        Map<Integer, List<Offer>> publishedMapByPartner = offerRepository.selectAllPublishedMapByPartner(YearMonth.from(date));
463
        List<Offer> publishedOffers = publishedMapByPartner != null ? publishedMapByPartner.get(fofoId) : null;
31747 amit.gupta 464
        List<CreateOfferRequest> createOfferRequests = new ArrayList<>();
465
        if (publishedOffers != null) {
466
            for (Offer offer : publishedOffers) {
467
                boolean found = false;
468
                List<com.spice.profitmandi.dao.model.TargetSlab> targetSlabs = offerTargetSlabRepository
469
                        .getByOfferId(offer.getId());
470
                CreateOfferRequest createOfferRequest = this.getCreateOfferRequest(offer);
471
                createOfferRequest.setTargetSlabs(targetSlabs);
472
                this.setCriteriaPayoutAchieved(fofoId, createOfferRequest);
473
                Set<com.spice.profitmandi.service.offers.ItemCriteria> itemCriteriaSet = targetSlabs.stream()
474
                        .flatMap(x -> x.getItemCriteriaPayouts().stream()).map(x -> x.getItemCriteria()).distinct()
475
                        .filter(x -> itemRepository.containsModel(x, catalogId)).collect(Collectors.toSet());
29499 amit.gupta 476
 
31747 amit.gupta 477
                for (com.spice.profitmandi.dao.model.TargetSlab targetSlab : targetSlabs) {
478
                    targetSlab.setItemCriteriaPayouts(targetSlab.getItemCriteriaPayouts().stream()
479
                            .filter(x -> itemCriteriaSet.contains(x.getItemCriteria())).collect(Collectors.toList()));
480
                    if (targetSlab.getItemCriteriaPayouts().size() > 0) {
481
                        found = true;
482
                    }
483
                }
484
                if (found) {
485
                    createOfferRequests.add(createOfferRequest);
486
                }
487
            }
488
        }
29783 amit.gupta 489
 
31747 amit.gupta 490
        return createOfferRequests;
491
    }
29783 amit.gupta 492
 
31747 amit.gupta 493
    @Override
494
    public void createOffers(InputStream fileInputStream) throws Exception {
495
        Map<CreateOfferRequest, List<PartnerTargetModel>> offerPartnerTargetMap = this.parseFromExcel(fileInputStream);
32868 amit.gupta 496
        Set<YearMonth> ymListToEvict = new HashSet<>();
31747 amit.gupta 497
        for (Map.Entry<CreateOfferRequest, List<PartnerTargetModel>> partnerTargetEntry : offerPartnerTargetMap
498
                .entrySet()) {
499
            CreateOfferRequest createOfferRequest = partnerTargetEntry.getKey();
500
            Map<List<Integer>, List<Integer>> targetPartnerMap = partnerTargetEntry.getValue().stream()
501
                    .collect(Collectors.groupingBy(PartnerTargetModel::getTargets,
502
                            Collectors.mapping(PartnerTargetModel::getFofoId, Collectors.toList())));
503
            for (Map.Entry<List<Integer>, List<Integer>> targetPartnersEntry : targetPartnerMap.entrySet()) {
504
                List<Integer> fofoIds = createOfferRequest.getPartnerCriteria().getFofoIds();
505
                List<Integer> filterFofoIds = targetPartnersEntry.getValue().stream().filter(x -> !fofoIds.contains(x))
506
                        .collect(Collectors.toList());
507
                LOGGER.info("FofoIds {}", filterFofoIds);
508
                List<Integer> targets = targetPartnersEntry.getKey();
509
                LOGGER.info("Targets  {}", targets);
29806 amit.gupta 510
 
31747 amit.gupta 511
                createOfferRequest.getPartnerCriteria().setFofoIds(filterFofoIds);
512
                int counter = 0;
513
                List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0)
514
                        .getItemCriteriaPayouts();
515
                List<PayoutSlab> payoutSlabs = itemCriteriaPayouts.stream().flatMap(x -> x.getPayoutSlabs().stream()).collect(Collectors.toList());
516
                for (PayoutSlab payoutSlab : payoutSlabs) {
517
                    payoutSlab.setOnwardsAmount(targets.get(counter));
518
                    counter++;
519
                }
520
                this.addOfferService(createOfferRequest);
521
            }
32868 amit.gupta 522
            ymListToEvict.add(YearMonth.from(createOfferRequest.getStartDate()));
31747 amit.gupta 523
        }
32868 amit.gupta 524
        for (YearMonth ymToEvict : ymListToEvict) {
36049 amit 525
            redisCacheManager.getCache("allOffers").evict(ymToEvict);
32868 amit.gupta 526
        }
31747 amit.gupta 527
    }
29783 amit.gupta 528
 
31747 amit.gupta 529
    private Map<CreateOfferRequest, List<PartnerTargetModel>> parseFromExcel(InputStream inputStream)
530
            throws ProfitMandiBusinessException {
29783 amit.gupta 531
 
31747 amit.gupta 532
        Map<CreateOfferRequest, List<PartnerTargetModel>> offerPartnerTargetMap = new HashMap<>();
533
        XSSFWorkbook myWorkBook = null;
534
        try {
535
            myWorkBook = new XSSFWorkbook(inputStream);
536
            myWorkBook.setMissingCellPolicy(MissingCellPolicy.RETURN_BLANK_AS_NULL);
537
            for (int i = 0; i < myWorkBook.getNumberOfSheets(); i++) {
29683 amit.gupta 538
 
31747 amit.gupta 539
                XSSFSheet mySheet = myWorkBook.getSheetAt(i);
540
                int offerId = Integer.parseInt(mySheet.getSheetName());
541
                CreateOfferRequest existingOffer = this.getOffer(0, offerId);
542
                List<PartnerTargetModel> partnerTargetModels = new ArrayList<>();
543
                offerPartnerTargetMap.put(existingOffer, partnerTargetModels);
544
                this.printIterator(mySheet);
545
                LOGGER.info("rowCellNum {}", mySheet.getLastRowNum());
546
                for (int rowNumber = 1; rowNumber <= mySheet.getLastRowNum(); rowNumber++) {
547
                    XSSFRow row = mySheet.getRow(rowNumber);
548
                    LOGGER.info("row {}", row);
549
                    PartnerTargetModel partnerTargetModel = new PartnerTargetModel();
29783 amit.gupta 550
 
31747 amit.gupta 551
                    if (row.getCell(0) != null && row.getCell(0).getCellTypeEnum() == CellType.NUMERIC) {
552
                        partnerTargetModel.setFofoId((int) row.getCell(0).getNumericCellValue());
553
                    } else {
554
                        ProfitMandiBusinessException profitMandiBusinessException = new ProfitMandiBusinessException(
555
                                "FOFO ID", row.getCell(0).toString(), "TGLSTNG_VE_1010");
556
                        LOGGER.error("Excel file parse error : ", profitMandiBusinessException);
557
                        throw profitMandiBusinessException;
558
                    }
559
                    List<Integer> targets = new ArrayList<>();
560
                    long targetsSize = existingOffer.getTargetSlabs().get(0).getItemCriteriaPayouts().stream().flatMap(x -> x.getPayoutSlabs().stream()).collect(Collectors.counting());
561
                    for (int cellNumber = 1; cellNumber <= targetsSize; cellNumber++) {
562
                        if (row.getCell(cellNumber) != null
563
                                && row.getCell(cellNumber).getCellTypeEnum() == CellType.NUMERIC) {
564
                            targets.add((int) row.getCell(cellNumber).getNumericCellValue());
565
                        } else {
566
                            ProfitMandiBusinessException profitMandiBusinessException = new ProfitMandiBusinessException(
567
                                    "Target Column issue at " + rowNumber + ", " + cellNumber, row.getCell(cellNumber),
568
                                    "Invalid target");
569
                            LOGGER.error("Excel file parse error : ", profitMandiBusinessException);
570
                            throw profitMandiBusinessException;
571
                        }
572
                    }
573
                    partnerTargetModel.setTargets(targets);
574
                    partnerTargetModels.add(partnerTargetModel);
575
                }
576
            }
577
            myWorkBook.close();
578
        } catch (ProfitMandiBusinessException pbse) {
579
            throw pbse;
580
        } catch (IOException ioException) {
581
            ioException.printStackTrace();
582
            throw new ProfitMandiBusinessException(ProfitMandiConstants.EXCEL_FILE, ioException.getMessage(),
583
                    "EXL_VE_1000");
584
        } finally {
585
            if (myWorkBook != null) {
586
                try {
587
                    myWorkBook.close();
588
                } catch (IOException e) {
589
                    // TODO Auto-generated catch block
590
                    e.printStackTrace();
591
                }
592
            }
593
        }
594
        LOGGER.info("offerPartnerTargetMap {}", offerPartnerTargetMap);
595
        return offerPartnerTargetMap;
596
    }
29783 amit.gupta 597
 
31747 amit.gupta 598
    private void printIterator(XSSFSheet sheet) {
599
        Iterator<Row> rowIterator = sheet.iterator();
600
        while (rowIterator.hasNext()) {
601
            Row row = rowIterator.next();
35394 amit 602
            StringBuilder rowContent = new StringBuilder();
31747 amit.gupta 603
            Iterator<Cell> cellIterator = row.cellIterator();
29683 amit.gupta 604
 
31747 amit.gupta 605
            while (cellIterator.hasNext()) {
606
                Cell cell = cellIterator.next();
607
                switch (cell.getCellType()) {
608
                    case Cell.CELL_TYPE_NUMERIC:
35394 amit 609
                        rowContent.append(cell.getNumericCellValue()).append("\t");
31747 amit.gupta 610
                        break;
611
                    case Cell.CELL_TYPE_STRING:
35394 amit 612
                        rowContent.append(cell.getStringCellValue()).append("\t");
31747 amit.gupta 613
                        break;
614
                }
615
            }
35394 amit 616
            LOGGER.debug("Row content: {}", rowContent);
31747 amit.gupta 617
        }
618
    }
29683 amit.gupta 619
 
31747 amit.gupta 620
    @Override
621
    public Map<Integer, CreateOfferRequest> getPublishedOffers(LocalDate date, int fofoId, String brand) {
622
        // TODO Auto-generated method stub
623
        return null;
624
    }
30684 amit.gupta 625
 
31747 amit.gupta 626
    @Override
32043 amit.gupta 627
    @Cacheable(value = "slabPayoutMap1", cacheManager = "oneDayCacheManager")
33247 ranu 628
    public Map<Integer, Map<Integer, Long>> getSlabPayoutMap(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
31747 amit.gupta 629
        Map<Integer, Map<Integer, Long>> catalogSlabPayoutMap = new HashMap<>();
630
        com.spice.profitmandi.dao.model.TargetSlab targetSlab = createOfferRequest.getTargetSlabs().get(0);
631
        List<ItemCriteriaPayout> payouts = targetSlab.getItemCriteriaPayouts();
29783 amit.gupta 632
 
31747 amit.gupta 633
        for (ItemCriteriaPayout itemCriteriaPayout : payouts) {
634
            com.spice.profitmandi.service.offers.ItemCriteria itemCriteria = itemCriteriaPayout.getItemCriteria();
635
            List<Integer> catalogIds = itemRepository.getCatalogIds(itemCriteria);
636
            for (PayoutSlab payoutSlab : Lists.reverse(itemCriteriaPayout.getPayoutSlabs())) {
637
                if (itemCriteriaPayout.getAmountType().equals(AmountType.FIXED)) {
638
                    for (Integer catalogId : catalogIds) {
639
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
640
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
641
                        }
642
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
643
                                (long) payoutSlab.getPayoutAmount());
644
                    }
645
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.SLAB_FIXED)) {
646
                    for (Integer catalogId : catalogIds) {
647
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
648
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
649
                        }
650
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
651
                                (long) (payoutSlab.getPayoutAmount() / payoutSlab.getOnwardsAmount()));
652
                    }
653
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.PERCENTAGE)) {
654
                    Map<Integer, TagListing> tagListingsMap = tagListingRepository.selectAllByCatalogIds(catalogIds);
655
                    for (Map.Entry<Integer, TagListing> tagListingEntry : tagListingsMap.entrySet()) {
656
                        TagListing tagListing = tagListingEntry.getValue();
657
                        if (!catalogSlabPayoutMap.containsKey(tagListingEntry.getKey())) {
658
                            catalogSlabPayoutMap.put(tagListingEntry.getKey(), new LinkedHashMap<>());
659
                        }
660
                        catalogSlabPayoutMap.get(tagListingEntry.getKey()).put(payoutSlab.getOnwardsAmount(),
661
                                (long) (tagListing.getSellingPrice() * payoutSlab.getPayoutAmount() / 100));
662
                    }
663
                }
664
            }
665
        }
666
        return catalogSlabPayoutMap;
667
    }
668
 
31903 amit.gupta 669
    @Override
36049 amit 670
    @Cacheable(value = "offer.slabpayout", cacheManager = "redisCacheManager", key = "#createOfferRequest.id")
31903 amit.gupta 671
    public Map<Integer, Map<Integer, AmountModel>> getSlabPayoutMapNew(CreateOfferRequest createOfferRequest) {
672
        Map<Integer, Map<Integer, AmountModel>> catalogSlabPayoutMap = new HashMap<>();
673
        com.spice.profitmandi.dao.model.TargetSlab targetSlab = createOfferRequest.getTargetSlabs().get(0);
674
        List<ItemCriteriaPayout> payouts = targetSlab.getItemCriteriaPayouts();
675
 
676
        for (ItemCriteriaPayout itemCriteriaPayout : payouts) {
677
            com.spice.profitmandi.service.offers.ItemCriteria itemCriteria = itemCriteriaPayout.getItemCriteria();
678
            List<Integer> catalogIds = itemRepository.getCatalogIds(itemCriteria);
679
            for (PayoutSlab payoutSlab : Lists.reverse(itemCriteriaPayout.getPayoutSlabs())) {
680
                if (itemCriteriaPayout.getAmountType().equals(AmountType.FIXED)) {
681
                    for (Integer catalogId : catalogIds) {
682
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
683
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
684
                        }
685
                        AmountModel amountModel = new AmountModel();
686
                        amountModel.setAmountType(AmountType.FIXED);
687
                        amountModel.setAmount(payoutSlab.getPayoutAmount());
32021 amit.gupta 688
                        amountModel.setDiscount(createOfferRequest.isDiscount());
31903 amit.gupta 689
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
690
                                amountModel);
691
                    }
692
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.SLAB_FIXED)) {
693
                    for (Integer catalogId : catalogIds) {
694
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
695
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
696
                        }
697
 
698
                        AmountModel amountModel = new AmountModel();
699
                        amountModel.setAmountType(AmountType.FIXED);
32021 amit.gupta 700
                        amountModel.setDiscount(createOfferRequest.isDiscount());
31903 amit.gupta 701
                        amountModel.setAmount(payoutSlab.getPayoutAmount() / payoutSlab.getOnwardsAmount());
702
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
703
                                amountModel);
704
                    }
705
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.PERCENTAGE)) {
706
                    for (Integer catalogId : catalogIds) {
707
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
708
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
709
                        }
710
                        AmountModel amountModel = new AmountModel();
711
                        amountModel.setAmountType(AmountType.PERCENTAGE);
712
                        amountModel.setAmount(payoutSlab.getPayoutAmount());
32021 amit.gupta 713
                        amountModel.setDiscount(createOfferRequest.isDiscount());
31903 amit.gupta 714
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
715
                                amountModel);
716
                    }
717
                }
718
            }
719
        }
720
        return catalogSlabPayoutMap;
721
    }
722
 
31920 amit.gupta 723
 
724
    private double getAmount(InventoryPayoutModel inventoryPayoutModel, AmountModel amountModel) {
725
        double rollout = 0;
726
        if (amountModel.getAmountType().equals(AmountType.PERCENTAGE)) {
727
            double effectiveDp = inventoryPayoutModel.getDp() - inventoryPayoutModel.getFixedAmount();
728
            double totalPercentage = inventoryPayoutModel.getPercentageAmount() + amountModel.getAmount();
729
            rollout = effectiveDp * (totalPercentage / (100 + totalPercentage) - (inventoryPayoutModel.getPercentageAmount() / (100 + inventoryPayoutModel.getPercentageAmount())));
730
        } else {
731
            rollout = amountModel.getAmount() * (100 / (100 + inventoryPayoutModel.getPercentageAmount()));
732
        }
733
        return rollout;
734
    }
735
 
35394 amit 736
    @Override
737
    public Map<Integer, QtyAmountModel> getCriteriaQtyAmounModelMap(CreateOfferRequest createOfferRequest, int fofoId) throws ProfitMandiBusinessException {
738
        Map<Integer, QtyAmountModel> qtyAmountMap;
739
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
740
            qtyAmountMap = getCriteriaQtyAmountModelMapForSellin(createOfferRequest, fofoId);
741
        } else {
742
            qtyAmountMap = getCriteriaQtyAmountModelMapForSelloutAndActivation(createOfferRequest, fofoId);
743
        }
744
        LOGGER.info("Qty Amount Map {}", qtyAmountMap);
745
        return qtyAmountMap;
746
    }
34217 amit.gupta 747
 
35667 amit 748
    private PayoutSlab findEligibleSlab(List<PayoutSlab> slabs, int achievedValue) {
749
        PayoutSlab eligibleSlab = null;
750
        for (PayoutSlab slab : slabs) {
751
            if (slab.getOnwardsAmount() <= achievedValue) {
752
                eligibleSlab = slab;
753
            } else {
754
                break;
755
            }
756
        }
757
        return eligibleSlab;
758
    }
759
 
35675 amit 760
    private void setSlabProgress(ItemCriteriaPayout itemCriteriaPayout, PayoutSlab eligibleSlab, int achievedValue) {
761
        List<PayoutSlab> slabs = itemCriteriaPayout.getPayoutSlabs();
762
        itemCriteriaPayout.setCurrentSlab(eligibleSlab);
763
        if (eligibleSlab == null) {
764
            if (!slabs.isEmpty()) {
765
                itemCriteriaPayout.setNextSlab(slabs.get(0));
766
                itemCriteriaPayout.setShortValue(slabs.get(0).getOnwardsAmount() - achievedValue);
767
            }
768
        } else {
769
            int idx = slabs.indexOf(eligibleSlab);
770
            if (idx < slabs.size() - 1) {
771
                PayoutSlab next = slabs.get(idx + 1);
772
                itemCriteriaPayout.setNextSlab(next);
773
                itemCriteriaPayout.setShortValue(next.getOnwardsAmount() - achievedValue);
774
            } else {
775
                itemCriteriaPayout.setNextSlab(null);
776
                itemCriteriaPayout.setShortValue(0);
777
            }
778
        }
779
    }
780
 
35667 amit 781
    private double calculateFinalPayout(PayoutSlab eligibleSlab, AmountType amountType,
782
                                        int valueForPercentage, int valueForFixed) {
783
        if (eligibleSlab == null) return 0;
784
        eligibleSlab.setSelected(true);
785
        float payoutRate = eligibleSlab.getPayoutAmount();
786
        if (AmountType.PERCENTAGE.equals(amountType)) {
787
            return (payoutRate * valueForPercentage) / 100;
788
        } else if (AmountType.FIXED.equals(amountType)) {
789
            return payoutRate * valueForFixed;
790
        } else {
791
            return payoutRate;
792
        }
793
    }
794
 
795
    private QtyAmountModel calculateSellinQtyAndValue(List<Order> orders) {
796
        int qty = orders.stream().collect(Collectors.summingInt(x ->
797
                x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()));
798
        int value = orders.stream().collect(Collectors.summingInt(x ->
799
                Math.round(x.getLineItem().getUnitPrice() *
800
                        (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))));
801
        return new QtyAmountModel(qty, value);
802
    }
803
 
35394 amit 804
    private Map<Integer, QtyAmountModel> getCriteriaQtyAmountModelMapForSellin(CreateOfferRequest createOfferRequest, int fofoId) throws ProfitMandiBusinessException {
805
        Map<Integer, QtyAmountModel> criteriaQtyAmountMap = new HashMap<>();
806
 
807
        Map<Integer, List<Order>> criteriaOrdersMap = offerRepository.getPartnerWiseSellin(fofoId, createOfferRequest, true);
808
 
35667 amit 809
        List<Order> baseCriteriaOrders = criteriaOrdersMap.get(0);
35394 amit 810
        Integer userBaseQty = null;
811
        Integer userBaseValue = null;
35667 amit 812
        if (baseCriteriaOrders != null && baseCriteriaOrders.size() > 0) {
813
            QtyAmountModel baseModel = calculateSellinQtyAndValue(baseCriteriaOrders);
814
            userBaseQty = baseModel.getQty();
815
            userBaseValue = (int) baseModel.getAmount();
816
            criteriaQtyAmountMap.put(0, baseModel);
817
        } else {
818
            criteriaQtyAmountMap.put(0, new QtyAmountModel(0, 0));
35394 amit 819
        }
820
 
821
        LOGGER.info("Processing sellin");
822
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
823
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
824
 
825
            QtyAmountModel qtyAmountModel = new QtyAmountModel(0, 0);
35667 amit 826
            criteriaQtyAmountMap.put(criteriaId, qtyAmountModel);
35394 amit 827
 
828
            List<Order> orders = criteriaOrdersMap.get(criteriaId);
35667 amit 829
            if (orders == null || orders.isEmpty()) continue;
830
 
831
            QtyAmountModel criteriaModel = calculateSellinQtyAndValue(orders);
36051 amit 832
            int criteriaQty = criteriaModel.getQty();
833
            int totalBaseQty = criteriaQty;
35667 amit 834
            int totalBaseValue = (int) criteriaModel.getAmount();
35394 amit 835
            if (userBaseQty != null) {
836
                totalBaseQty = userBaseQty;
837
                totalBaseValue = userBaseValue;
838
            }
839
 
840
            int purchasedValue;
841
            if (createOfferRequest.getTargetType().equals(AchievementType.VALUE)) {
842
                purchasedValue = totalBaseValue;
843
            } else {
844
                purchasedValue = totalBaseQty;
845
            }
846
            qtyAmountModel.setQty(totalBaseQty);
847
            qtyAmountModel.setAmount(totalBaseValue);
848
 
35667 amit 849
            PayoutSlab eligibleSlab = findEligibleSlab(itemCriteriaPayout.getPayoutSlabs(), purchasedValue);
35675 amit 850
            setSlabProgress(itemCriteriaPayout, eligibleSlab, purchasedValue);
36051 amit 851
            // For FIXED (per pc) payout, use per-criteria qty not base value
852
            int sellinValueForFixed = itemCriteriaPayout.getAmountType().equals(AmountType.FIXED) ? criteriaQty : purchasedValue;
35667 amit 853
            double finalPayout = calculateFinalPayout(eligibleSlab, itemCriteriaPayout.getAmountType(),
36051 amit 854
                    purchasedValue, sellinValueForFixed);
35394 amit 855
            qtyAmountModel.setFinalPayout(finalPayout);
856
        }
857
        return criteriaQtyAmountMap;
858
    }
859
 
860
    private Map<Integer, QtyAmountModel> getCriteriaQtyAmountModelMapForSelloutAndActivation(CreateOfferRequest createOfferRequest, int fofoId) {
861
        Map<Integer, Map<Integer, List<FofoOrderItem>>> criteriaPartnerwiseTertiary = offerRepository.getCriteriaWisePartnerTertiary(createOfferRequest, fofoId);
862
        Map<Integer, QtyAmountModel> qtyAmountMap;
863
        final Map<String, LocalDateTime> activatedImeisActivationDateMap;
864
        qtyAmountMap = new HashMap<>();
865
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
866
            //All Serialnumbers for all eligible retailers
867
            List<String> serialNumbers = criteriaPartnerwiseTertiary.entrySet().stream().flatMap(x -> x.getValue().entrySet().stream().flatMap(foiList -> foiList.getValue().stream()))
868
                    .flatMap(y -> y.getFofoLineItems().stream()).filter(fli -> fli.getSerialNumber() != null)
869
                    .map(x -> x.getSerialNumber()).collect(Collectors.toList());
870
            if (serialNumbers.size() > 0) {
871
            /*if (imeisAllowedManually != null) {
872
                serialNumbers = serialNumbers.stream().filter(x -> imeisAllowedManually.contains(x)).collect(Collectors.toList());
873
            }*/
874
                activatedImeisActivationDateMap = activatedImeiRepository.selectBySerialNumbers(serialNumbers).stream()
875
                        .filter(x -> createOfferRequest.isWithinRange(x.getActivationTimestamp()))
876
                        .collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x.getActivationTimestamp()));
877
            } else {
878
                activatedImeisActivationDateMap = null;
879
            }
880
        } else {
881
            activatedImeisActivationDateMap = null;
882
        }
883
 
884
        QtyAmountModel qtyAmountModel = null;
885
        if (createOfferRequest.isBaseCriteria()) {
35667 amit 886
            Map<Integer, List<FofoOrderItem>> baseCriteriaMap = criteriaPartnerwiseTertiary.get(0);
887
            List<FofoOrderItem> fofoOrderItems = baseCriteriaMap == null ? null : baseCriteriaMap.get(fofoId);
35394 amit 888
            int totalBaseQty = fofoOrderItems == null ? 0 : fofoOrderItems.stream().filter(x->createOfferRequest.isWithinRange(x.getCreateTimestamp())).collect(Collectors.summingInt(x -> (x.getQuantity())));
889
            int totalBaseValue = fofoOrderItems == null ? 0 : fofoOrderItems.stream().filter(x->createOfferRequest.isWithinRange(x.getCreateTimestamp())).mapToInt(x -> (Math.round(x.getDp())) * x.getQuantity()).sum();
890
            qtyAmountModel = new QtyAmountModel(totalBaseQty, totalBaseValue);
891
            if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
892
                Map<Integer, Integer> inventoryItemValueMap = new HashMap<>();
35667 amit 893
                if (fofoOrderItems != null) {
894
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
895
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
896
                                lineItem -> {
897
                                    if (activatedImeisActivationDateMap == null || activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
898
                                        inventoryItemValueMap.put(lineItem.getInventoryItemId(), (int) fofoOrderItem.getDp());
899
                                    }
35394 amit 900
                                }
35667 amit 901
                        );
902
                    }
35394 amit 903
                }
904
                qtyAmountModel.setActivationQty(inventoryItemValueMap.size());
905
                qtyAmountModel.setActivationAmount(inventoryItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue())));
906
                qtyAmountMap.put(0, qtyAmountModel);
907
            }
908
        }
909
 
910
        //CriteriaPayoutWise
911
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
912
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
913
            Map<Integer, List<FofoOrderItem>> ordersMap = criteriaPartnerwiseTertiary.get(criteriaId);
914
 
35667 amit 915
            QtyAmountModel criteriaQtyAmountModel = new QtyAmountModel(0, 0);
916
            qtyAmountMap.put(criteriaId, criteriaQtyAmountModel);
35394 amit 917
 
35667 amit 918
            if (ordersMap == null) continue;
35394 amit 919
 
35667 amit 920
            List<FofoOrderItem> fofoOrderItems = ordersMap.get(fofoId);
921
            if (fofoOrderItems == null || fofoOrderItems.isEmpty()) continue;
35394 amit 922
 
35673 amit 923
            int totalQty = fofoOrderItems.stream().filter(x -> createOfferRequest.isWithinRange(x.getCreateTimestamp())).collect(Collectors.summingInt(x -> (x.getQuantity())));
924
            int totalValue = fofoOrderItems.stream().filter(x -> createOfferRequest.isWithinRange(x.getCreateTimestamp())).collect(Collectors.summingInt(x -> Math.round(x.getDp()) * (x.getQuantity())));
35667 amit 925
            int eligibleQty = totalQty;
926
            int eligibleValue = totalValue;
927
            criteriaQtyAmountModel.setQty(totalQty);
928
            criteriaQtyAmountModel.setAmount(totalValue);
35394 amit 929
 
35667 amit 930
            Map<FofoLineItem, Integer> lineItemValueMap = new HashMap<>();
931
            if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
932
                for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
933
                    fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
934
                            lineItem -> {
935
                                if (activatedImeisActivationDateMap == null) {
936
                                    lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
937
                                } else if (activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
938
                                    if (itemCriteriaPayout.isWithinRange(activatedImeisActivationDateMap.get(lineItem.getSerialNumber()))) {
939
                                        lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
940
                                    }
941
                                }
942
                            }
943
                    );
35394 amit 944
                }
35667 amit 945
                eligibleQty = lineItemValueMap.size();
946
                eligibleValue = lineItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue()));
947
                criteriaQtyAmountModel.setActivationQty(eligibleQty);
948
                criteriaQtyAmountModel.setActivationAmount(eligibleValue);
949
            }
35394 amit 950
 
35667 amit 951
            int eligibleBaseQty = eligibleQty;
952
            int eligibleBaseValue = eligibleValue;
953
            if (createOfferRequest.isBaseCriteria()) {
954
                eligibleBaseQty = qtyAmountModel.getActivationQty();
955
                eligibleBaseValue = (int) qtyAmountModel.getActivationAmount();
956
            }
35394 amit 957
 
35667 amit 958
            int eligibleSale = eligibleBaseValue;
959
            int eligibleCriteriaSale = eligibleValue;
960
            int eligibleCriteriaSaleDp = eligibleValue;
35394 amit 961
 
35667 amit 962
            if (createOfferRequest.getTargetType().equals(AchievementType.QUANTITY)) {
963
                eligibleSale = eligibleBaseQty;
964
                eligibleCriteriaSale = eligibleQty;
35394 amit 965
            }
966
 
36051 amit 967
            // For FIXED (per pc) payout, always use qty regardless of target type
968
            int valueForFixed = itemCriteriaPayout.getAmountType().equals(AmountType.FIXED) ? eligibleQty : eligibleCriteriaSale;
969
 
35667 amit 970
            PayoutSlab eligibleSlab = findEligibleSlab(itemCriteriaPayout.getPayoutSlabs(), eligibleSale);
35675 amit 971
            setSlabProgress(itemCriteriaPayout, eligibleSlab, eligibleSale);
35667 amit 972
            double finalPayout = calculateFinalPayout(eligibleSlab, itemCriteriaPayout.getAmountType(),
36051 amit 973
                    eligibleCriteriaSaleDp, valueForFixed);
35667 amit 974
            if (eligibleSlab != null) {
975
                LOGGER.info("Eligible Slab {}", eligibleSlab);
976
            }
977
            criteriaQtyAmountModel.setFinalPayout(finalPayout);
978
            LOGGER.info("Final Payout - {}", finalPayout);
35394 amit 979
        }
980
        return qtyAmountMap;
981
    }
982
 
31920 amit.gupta 983
    @Override
984
    public void processActivationtOffer(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
985
        List<OfferPayout> offerPayouts = offerPayoutRepository.selectAllByOfferId(createOfferRequest.getId());
986
        List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts();
987
        Map<Integer, ItemCriteriaPayout> itemCriteriaPayoutMap = itemCriteriaPayouts.stream().collect(Collectors.toMap(x -> x.getItemCriteria().getId(), x -> x));
31923 amit.gupta 988
        LOGGER.info("itemCriteriaPayoutMap {}", itemCriteriaPayoutMap);
989
        LOGGER.info("offerPayouts {}", offerPayouts);
31924 amit.gupta 990
        Map<Integer, Map<Integer, Double>> fixedSlabCriteriaPartnerMap = offerPayouts.stream().filter(x -> itemCriteriaPayoutMap.get((int) x.getCriteriaId()).getAmountType().equals(AmountType.SLAB_FIXED))
31920 amit.gupta 991
                .collect(Collectors.groupingBy(x -> (int) x.getCriteriaId(), Collectors.groupingBy(x -> (int) x.getFofoId(), Collectors.summingDouble(x -> x.getSlabAmount()))));
992
 
993
 
994
        Map<String, Double> serialNumberPaid = offerPayouts.stream().filter(x -> x.getRejectTimestamp() == null).collect(Collectors.groupingBy(x -> x.getSerialNumber(), Collectors.summingDouble(x -> x.getSlabAmount())));
995
        Map<Integer, Map<Integer, List<FofoOrderItem>>> criteriaPartnerwiseTertiary = offerRepository.getCriteriaWisePartnerTertiary(createOfferRequest);
996
 
33087 amit.gupta 997
        Map<String, AgeingSummaryModel> ageingSummaryModelsMap = null;
33662 amit.gupta 998
        final Map<String, LocalDateTime> activatedImeisActivationDateMap;
34217 amit.gupta 999
        //Find Only eligible imeis if any
1000
        List<String> imeisAllowedManually = offerEligibleImeiRepository.selectEligibleImeisByOfferId(createOfferRequest.getId());
1001
 
31920 amit.gupta 1002
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1003
            //All Serialnumbers for all eligible retailers
1004
            List<String> serialNumbers = criteriaPartnerwiseTertiary.entrySet().stream().flatMap(x -> x.getValue().entrySet().stream().flatMap(foiList -> foiList.getValue().stream()))
1005
                    .flatMap(y -> y.getFofoLineItems().stream()).filter(fli -> fli.getSerialNumber() != null)
1006
                    .map(x -> x.getSerialNumber()).collect(Collectors.toList());
1007
            if (serialNumbers.size() > 0) {
34217 amit.gupta 1008
                if (imeisAllowedManually != null) {
1009
                    serialNumbers = serialNumbers.stream().filter(x -> imeisAllowedManually.contains(x)).collect(Collectors.toList());
1010
                }
33662 amit.gupta 1011
                activatedImeisActivationDateMap = activatedImeiRepository.selectBySerialNumbers(serialNumbers).stream()
31920 amit.gupta 1012
                        .filter(x -> createOfferRequest.isWithinRange(x.getActivationTimestamp()))
33441 amit.gupta 1013
                        .collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x.getActivationTimestamp()));
33613 amit.gupta 1014
                ageingSummaryModelsMap = warehouseInventoryItemRepository.findStockAgeingByFofoIdSerialNumbers(0, serialNumbers).stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x, (u, v) -> v));
31920 amit.gupta 1015
            } else {
33662 amit.gupta 1016
                activatedImeisActivationDateMap = null;
31920 amit.gupta 1017
            }
1018
        } else {
33662 amit.gupta 1019
            activatedImeisActivationDateMap = null;
31920 amit.gupta 1020
        }
1021
 
1022
        Map<Integer, Integer> userBaseQtyMap = new HashMap<>();
1023
        Map<Integer, Integer> userBaseValueMap = new HashMap<>();
1024
        Map<Integer, Integer> eligibleBaseQtyMap = new HashMap<>();
1025
        Map<Integer, Integer> eligibleBaseValueMap = new HashMap<>();
1026
 
1027
        if (createOfferRequest.isBaseCriteria()) {
1028
            Map<Integer, List<FofoOrderItem>> foiMap = criteriaPartnerwiseTertiary.get(0);
1029
            for (Map.Entry<Integer, List<FofoOrderItem>> orderEntry : foiMap.entrySet()) {
1030
                int fofoId = orderEntry.getKey();
1031
                List<FofoOrderItem> fofoOrderItems = orderEntry.getValue();
1032
                int totalBaseQty = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (x.getQuantity())));
1033
                int totalBaseValue = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (Math.round(x.getDp())) * x.getQuantity()));
1034
                userBaseQtyMap.put(fofoId, totalBaseQty);
1035
                userBaseValueMap.put(fofoId, totalBaseValue);
1036
                if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1037
                    Map<Integer, Integer> inventoryItemValueMap = new HashMap<>();
1038
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1039
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1040
                                lineItem -> {
33662 amit.gupta 1041
                                    if (activatedImeisActivationDateMap == null || activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
31920 amit.gupta 1042
                                        inventoryItemValueMap.put(lineItem.getInventoryItemId(), (int) fofoOrderItem.getDp());
1043
                                    }
1044
                                }
1045
                        );
1046
                    }
1047
                    eligibleBaseQtyMap.put(fofoId, inventoryItemValueMap.size());
1048
                    eligibleBaseValueMap.put(fofoId, inventoryItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue())));
1049
                } else {
1050
                    eligibleBaseQtyMap.put(fofoId, totalBaseQty);
1051
                    eligibleBaseValueMap.put(fofoId, totalBaseValue);
1052
 
1053
                }
1054
 
1055
            }
1056
        }
1057
 
1058
        //As of now eligible sale is considered to be without special criteria like brand/
33441 amit.gupta 1059
        //CriteriaPayoutWise
31920 amit.gupta 1060
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
1061
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
1062
            Map<Integer, List<FofoOrderItem>> ordersMap = criteriaPartnerwiseTertiary.get(criteriaId);
33441 amit.gupta 1063
            //Partywise iteration
31920 amit.gupta 1064
            for (Map.Entry<Integer, List<FofoOrderItem>> orderEntry : ordersMap.entrySet()) {
31992 amit.gupta 1065
                double totalRolloutAmount = 0;
31920 amit.gupta 1066
                int fofoId = orderEntry.getKey();
1067
                List<FofoOrderItem> fofoOrderItems = orderEntry.getValue();
1068
                OfferRowModel offerRowModel = new OfferRowModel();
1069
                int totalQty = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (x.getQuantity())));
1070
                int totalValue = fofoOrderItems.stream().collect(Collectors.summingInt(x -> Math.round(x.getDp()) * (x.getQuantity())));
1071
                int eligibleQty = totalQty;
1072
                int eligibleValue = totalValue;
1073
                Map<FofoLineItem, Integer> lineItemValueMap = new HashMap<>();
1074
                if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1075
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1076
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1077
                                lineItem -> {
33662 amit.gupta 1078
                                    if (activatedImeisActivationDateMap == null) {
31920 amit.gupta 1079
                                        lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
33441 amit.gupta 1080
 
33662 amit.gupta 1081
                                    } else if (activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
1082
                                        if (itemCriteriaPayout.isWithinRange(activatedImeisActivationDateMap.get(lineItem.getSerialNumber()))) {
33441 amit.gupta 1083
                                            lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
1084
                                        }
31920 amit.gupta 1085
                                    }
33441 amit.gupta 1086
 
31920 amit.gupta 1087
                                }
1088
                        );
1089
                    }
1090
                    eligibleQty = lineItemValueMap.size();
1091
                    eligibleValue = lineItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue()));
1092
                    offerRowModel.setEligibleImeis(lineItemValueMap.keySet().stream().map(x -> x.getSerialNumber()).collect(Collectors.toList()));
1093
                }
1094
 
1095
                int totalBaseQty = totalQty;
1096
                int totalBaseValue = totalValue;
1097
                int eligibleBaseQty = eligibleQty;
1098
                int eligibleBaseValue = eligibleValue;
1099
                if (createOfferRequest.isBaseCriteria()) {
1100
                    totalBaseQty = userBaseQtyMap.get(fofoId) == null ? 0 : userBaseQtyMap.get(fofoId);
1101
                    totalBaseValue = userBaseValueMap.get(fofoId) == null ? 0 : userBaseValueMap.get(fofoId);
1102
                    eligibleBaseQty = eligibleBaseQtyMap.get(fofoId) == null ? 0 : eligibleBaseQtyMap.get(fofoId);
1103
                    eligibleBaseValue = eligibleBaseValueMap.get(fofoId) == null ? 0 : eligibleBaseValueMap.get(fofoId);
1104
                }
1105
 
1106
 
1107
                int totalSale = totalBaseValue;
1108
                int eligibleSale = eligibleBaseValue;
1109
                int eligibleCriteriaSale = eligibleValue;
1110
                int eligibleCriteriaSaleDp = eligibleValue;
1111
 
1112
                if (createOfferRequest.getTargetType().equals(AchievementType.QUANTITY)) {
1113
                    totalSale = totalBaseQty;
1114
                    eligibleSale = eligibleBaseQty;
1115
                    eligibleCriteriaSale = eligibleQty;
1116
                }
1117
 
1118
                offerRowModel.setTotalSale(totalSale);
1119
                offerRowModel.setEligibleSale(eligibleSale);
1120
                float eligiblePayoutValue = 0;
33662 amit.gupta 1121
                float previousPayoutValue = 0;
32345 amit.gupta 1122
                double finalPayout;
31920 amit.gupta 1123
                for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
1124
                    if (payoutSlab.getOnwardsAmount() <= eligibleSale) {
32039 amit.gupta 1125
                        LOGGER.info("Eligible Sale {}", eligibleSale);
31920 amit.gupta 1126
                        offerRowModel.setPayoutTargetAchieved(payoutSlab.getOnwardsAmount());
1127
                        eligiblePayoutValue = payoutSlab.getPayoutAmount();
33662 amit.gupta 1128
                        previousPayoutValue = Math.min(eligiblePayoutValue, previousPayoutValue);
31920 amit.gupta 1129
                        offerRowModel.setPayoutValue(eligiblePayoutValue);
33662 amit.gupta 1130
                    } else {
1131
                        break;
31920 amit.gupta 1132
                    }
1133
                }
1134
                if (AmountType.PERCENTAGE.equals(itemCriteriaPayout.getAmountType())) {
1135
                    finalPayout = (eligiblePayoutValue * eligibleCriteriaSaleDp) / 100;
1136
                } else if (AmountType.FIXED.equals(itemCriteriaPayout.getAmountType())) {
36051 amit 1137
                    // FIXED = per piece, always use qty regardless of target type
1138
                    finalPayout = eligiblePayoutValue * eligibleQty;
31920 amit.gupta 1139
                } else {
32039 amit.gupta 1140
                    Map<Integer, Double> fofoCriteriaMap = fixedSlabCriteriaPartnerMap.get(criteriaId);
1141
                    LOGGER.info("fofoCriteriaMap {}", fofoCriteriaMap);
31920 amit.gupta 1142
                    finalPayout = eligiblePayoutValue;
1143
                    if (fofoCriteriaMap != null) {
1144
                        if (fofoCriteriaMap.containsKey(fofoId)) {
33662 amit.gupta 1145
                            //double totalPayout = fofoCriteriaMap.get(fofoId);
1146
                            finalPayout = eligiblePayoutValue - previousPayoutValue;
32039 amit.gupta 1147
                            if (Math.abs(finalPayout) < Utils.DOUBLE_EPSILON) {
31920 amit.gupta 1148
                                finalPayout = 0;
32039 amit.gupta 1149
                            }
31920 amit.gupta 1150
                        }
1151
                    }
1152
                }
1153
 
32039 amit.gupta 1154
                LOGGER.info("Final Payout - {}", finalPayout);
1155
 
31920 amit.gupta 1156
                if (finalPayout > 0) {
1157
                    List<Integer> inventoryItemIds = lineItemValueMap.keySet().stream().map(x -> x.getInventoryItemId()).collect(Collectors.toList());
33662 amit.gupta 1158
                    int totalDpValue = lineItemValueMap.values().stream().collect(Collectors.summingInt(x -> x));
1159
                    LOGGER.info("Total DP Value {}", totalDpValue);
31920 amit.gupta 1160
                    Map<Integer, InventoryItem> inventoryItemsMap = inventoryItemRepository.selectAllByIds(inventoryItemIds).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));
1161
                    for (Map.Entry<FofoLineItem, Integer> lineItemValueEntry : lineItemValueMap.entrySet()) {
33087 amit.gupta 1162
                        FofoLineItem fofoLineItem = lineItemValueEntry.getKey();
31920 amit.gupta 1163
                        double amount = 0;
1164
                        if (AmountType.SLAB_FIXED.equals(itemCriteriaPayout.getAmountType())) {
32039 amit.gupta 1165
                            amount = (eligiblePayoutValue * lineItemValueEntry.getValue()) / totalDpValue;
31920 amit.gupta 1166
                        } else {
33662 amit.gupta 1167
                            if (ageingSummaryModelsMap.containsKey(fofoLineItem.getSerialNumber())) {
35394 amit 1168
                                if (ageingSummaryModelsMap.get(fofoLineItem.getSerialNumber()).isAgedAbove(STOCK_AGEING_THRESHOLD_DAYS)) {
33662 amit.gupta 1169
                                    continue;
1170
                                }
1171
                            }
31920 amit.gupta 1172
                            amount = eligiblePayoutValue;
1173
                        }
33662 amit.gupta 1174
                        if (serialNumberPaid.containsKey(fofoLineItem.getSerialNumber())) {
1175
                            amount = amount - serialNumberPaid.get(fofoLineItem.getSerialNumber());
1176
                        }
32039 amit.gupta 1177
                        LOGGER.info("Amount - {}", amount);
31920 amit.gupta 1178
                        //ignore reasonably small
1179
                        if (amount < Utils.DOUBLE_EPSILON) continue;
1180
                        AmountModel amountModel = new AmountModel();
1181
                        amountModel.setAmountType(itemCriteriaPayout.getAmountType());
1182
                        amountModel.setAmount(amount);
32021 amit.gupta 1183
                        amountModel.setDiscount(createOfferRequest.isDiscount());
33087 amit.gupta 1184
                        InventoryPayoutModel inventoryPayoutModel = priceCircularService.getPayouts(inventoryItemsMap.get(fofoLineItem.getInventoryItemId()));
31920 amit.gupta 1185
                        double rolloutAmount = inventoryPayoutModel.getRolloutAmount(amountModel);
1186
                        totalRolloutAmount += rolloutAmount;
1187
 
33087 amit.gupta 1188
                        OfferPayout offerPayout = new OfferPayout(fofoId, createOfferRequest.getId(), criteriaId, amount, fofoLineItem.getSerialNumber(), rolloutAmount, SchemePayoutStatus.CREDITED, createOfferRequest.getDescription(), LocalDateTime.now());
33459 amit.gupta 1189
                        offerPayout.setInventoryItemId(fofoLineItem.getInventoryItemId());
31920 amit.gupta 1190
                        offerPayoutRepository.persist(offerPayout);
1191
                    }
32039 amit.gupta 1192
                    walletService.addAmountToWallet((int) fofoId, createOfferRequest.getId(), WalletReferenceType.ADDITIONAL_SCHEME, createOfferRequest.getDescription(), (float) totalRolloutAmount, LocalDateTime.now());
31920 amit.gupta 1193
                }
1194
            }
1195
        }
1196
        Offer offer = offerRepository.selectById(createOfferRequest.getId());
1197
        offer.setProcessedTimestamp(LocalDateTime.now());
1198
    }
1199
 
1200
    @Override
1201
    public void processSellin(CreateOfferRequest createOfferRequest) throws Exception {
1202
 
1203
        //List<OfferRowModel> offerRowModels = new ArrayList<>();
1204
        List<OfferPayout> offerPayouts = offerPayoutRepository.selectAllByOfferId(createOfferRequest.getId());
32345 amit.gupta 1205
        Map<String, Double> serialNumberPaid = offerPayouts.stream().filter(x -> x.getRejectTimestamp() == null).collect(Collectors.groupingBy(x -> x.getSerialNumber(), Collectors.summingDouble(x -> x.getSlabAmount())));
34072 ranu 1206
        LOGGER.info("serialNumberPaid {}", serialNumberPaid);
32345 amit.gupta 1207
        List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts();
1208
        Map<Integer, ItemCriteriaPayout> itemCriteriaPayoutMap = itemCriteriaPayouts.stream().collect(Collectors.toMap(x -> x.getItemCriteria().getId(), x -> x));
1209
        Map<Integer, Map<Integer, Double>> fixedSlabCriteriaPartnerMap = offerPayouts.stream().filter(x -> itemCriteriaPayoutMap.get((int) x.getCriteriaId()).getAmountType().equals(AmountType.SLAB_FIXED))
1210
                .collect(Collectors.groupingBy(x -> (int) x.getCriteriaId(), Collectors.groupingBy(x -> (int) x.getFofoId(), Collectors.summingDouble(x -> x.getSlabAmount()))));
31920 amit.gupta 1211
        Set<Long> fofoIds = offerPayouts.stream().map(x -> x.getFofoId()).collect(Collectors.toSet());
1212
 
1213
        Map<Integer, Map<Integer, List<Order>>> criteriaOrdersMap = offerRepository.getPartnerWiseSellin(createOfferRequest, true);
1214
 
32345 amit.gupta 1215
 
31920 amit.gupta 1216
        Map<Integer, List<Order>> userBaseCriteriaOrdersMap = null;
1217
        if (criteriaOrdersMap.get(0) != null && criteriaOrdersMap.get(0).size() > 0) {
1218
            userBaseCriteriaOrdersMap = criteriaOrdersMap.get(0).entrySet().stream()
1219
                    .filter(x -> !fofoIds.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1220
        }
1221
 
32345 amit.gupta 1222
 
31920 amit.gupta 1223
        Map<Integer, Integer> userBaseQtyMap = null;
1224
        Map<Integer, Integer> userBaseValueMap = null;
1225
        if (userBaseCriteriaOrdersMap != null) {
1226
            userBaseQtyMap = new HashMap<>();
1227
            userBaseValueMap = new HashMap<>();
1228
            for (Map.Entry<Integer, List<Order>> orderEntry : userBaseCriteriaOrdersMap.entrySet()) {
1229
                int fofoId = orderEntry.getKey();
1230
                List<Order> orders = orderEntry.getValue();
1231
                int totalBaseQty = orders.stream().collect(Collectors.summingInt(x -> (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty())));
1232
                int totalBaseValue = orders.stream().collect(Collectors.summingInt(x ->
1233
                        Math.round(x.getLineItem().getUnitPrice() * (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))
1234
                ));
1235
                userBaseQtyMap.put(fofoId, totalBaseQty);
1236
                userBaseValueMap.put(fofoId, totalBaseValue);
1237
            }
1238
        }
1239
        LOGGER.info("Base Qty Map - {}", userBaseQtyMap);
1240
        LOGGER.info("Base Value Map - {}", userBaseValueMap);
1241
 
1242
        LOGGER.info("Processing sellin");
1243
        List<OfferPayout> offerPayoutsNew = new ArrayList<>();
1244
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
1245
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
1246
            Map<Integer, List<Order>> ordersMap = criteriaOrdersMap.get(criteriaId).entrySet().stream()
1247
                    .filter(x -> !fofoIds.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1248
            for (Map.Entry<Integer, List<Order>> orderEntry : ordersMap.entrySet()) {
1249
                int fofoId = orderEntry.getKey();
1250
                //CustomRetailer retailer = retailerService.getAllFofoRetailers().get(fofoId);
1251
                List<Order> orders = orderEntry.getValue();
32345 amit.gupta 1252
                //Set<String> returnedSerialNumbers = orders.stream().filter(x -> x.getSerialNumber() != null).flatMap(x -> x.getReturnedImeis().stream()).collect(Collectors.toSet());
31920 amit.gupta 1253
                int totalQty = orders.stream().collect(Collectors.summingInt(x -> (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty())));
1254
                int totalValue = orders.stream().collect(Collectors.summingInt(x -> Math.round(x.getLineItem().
1255
                        getUnitPrice() * (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))));
1256
                int totalBaseQty = totalQty;
1257
                int totalBaseValue = totalValue;
1258
                if (userBaseCriteriaOrdersMap != null) {
1259
                    if (userBaseQtyMap.containsKey(fofoId)) {
1260
                        totalBaseQty = userBaseQtyMap.get(fofoId);
1261
                        totalBaseValue = userBaseValueMap.get(fofoId);
1262
                    } else {
1263
                        continue;
1264
                    }
1265
                }
1266
 
1267
                int purchasedValue;
1268
                if (createOfferRequest.getTargetType().equals(AchievementType.VALUE)) {
1269
                    purchasedValue = totalBaseValue;
1270
                } else {
1271
                    purchasedValue = totalBaseQty;
1272
                }
1273
 
33695 amit.gupta 1274
                PayoutSlab eligibleSlab = null;
33662 amit.gupta 1275
 
1276
                for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
1277
                    if (payoutSlab.getOnwardsAmount() <= purchasedValue) {
1278
                        eligibleSlab = payoutSlab;
1279
                    } else {
1280
                        break;
1281
                    }
1282
                }
33695 amit.gupta 1283
                if (eligibleSlab == null) continue;
31920 amit.gupta 1284
                List<Integer> orderIds = orders.stream().map(x -> x.getId()).collect(Collectors.toList());
1285
                Map<Integer, LineItem> lineItemMap = orders.stream().collect(Collectors.toMap(x -> x.getLineItem().getId(), x -> x.getLineItem()));
1286
                List<WarehouseScan> warehouseScans = warehouseScanRepository.selectAllByOrderIds(orderIds);
32540 amit.gupta 1287
                LOGGER.info("Warehosue scans --> {}", warehouseScans);
32345 amit.gupta 1288
                List<Integer> warehouseInventoryItemIds = warehouseScans.stream().collect(Collectors.groupingBy(x -> x.getInventoryItemId())).entrySet()
31920 amit.gupta 1289
                        .stream().filter(x -> x.getValue().size() == 1).map(x -> x.getKey()).collect(Collectors.toList());
32795 amit.gupta 1290
 
1291
                List<OfferPayout> partnerPayouts = offerPayouts.stream().filter(x -> x.getFofoId() == fofoId).collect(Collectors.toList());
32868 amit.gupta 1292
                Set<String> serialNumbersRejected = partnerPayouts.stream().filter(x -> x.getStatus().equals(SchemePayoutStatus.REJECTED)).map(x -> x.getSerialNumber()).collect(Collectors.toSet());
32795 amit.gupta 1293
 
34092 amit.gupta 1294
                Set<String> billedNotCancelledSerialNumbers;
32345 amit.gupta 1295
                LOGGER.info("warehouseInventoryItemIds {}", warehouseInventoryItemIds);
1296
                if (warehouseInventoryItemIds.size() > 0) {
1297
                    List<WarehouseInventoryItem> warehouseInventoryItems = warehouseInventoryItemRepository.selectAllByIds(warehouseInventoryItemIds);
34092 amit.gupta 1298
                    billedNotCancelledSerialNumbers = warehouseInventoryItems.stream().map(x -> x.getSerialNumber()).collect(Collectors.toSet());
31920 amit.gupta 1299
                } else {
34092 amit.gupta 1300
                    billedNotCancelledSerialNumbers = new HashSet<>();
31920 amit.gupta 1301
                }
34092 amit.gupta 1302
                LOGGER.info("billedNotCancelledSerialNumbers {}", billedNotCancelledSerialNumbers);
1303
 
31920 amit.gupta 1304
                Map<String, LineItem> serialNumberMap = lineItemImeisRepository.selectByLineItemIds(new ArrayList<>(lineItemMap.keySet()))
32868 amit.gupta 1305
                        .stream().filter(x -> !serialNumbersRejected.contains(x.getSerialNumber())).collect(Collectors.toMap(x -> x.getSerialNumber(), x -> lineItemMap.get(x.getLineItemId()), (x1, x2) -> x1.getId() > x2.getId() ? x1 : x2));
31920 amit.gupta 1306
 
34226 amit.gupta 1307
                List<String> manuallyEligibleImeis = offerEligibleImeiRepository.selectEligibleImeisByOfferId(createOfferRequest.getId());
32795 amit.gupta 1308
 
34092 amit.gupta 1309
                serialNumberMap = serialNumberMap.entrySet().stream().filter(x -> billedNotCancelledSerialNumbers.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
34231 amit.gupta 1310
 
1311
                //Just a validation need to revaluate this
1312
                Map<String, InventoryItem> serialNumberInventoryItemMap = this.getInventoryItemMap(fofoId, serialNumberMap);
1313
                if (serialNumberInventoryItemMap.size() < billedNotCancelledSerialNumbers.size()) continue;
1314
 
34623 amit.gupta 1315
                LOGGER.info("serialNumberMap {}", serialNumberMap);
34226 amit.gupta 1316
                if (manuallyEligibleImeis != null) {
34227 amit.gupta 1317
                    serialNumberMap = serialNumberMap.entrySet().stream().filter(x -> manuallyEligibleImeis.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
34624 amit.gupta 1318
                    if (serialNumberMap.size() == 0) continue;
34231 amit.gupta 1319
                    serialNumberInventoryItemMap = this.getInventoryItemMap(fofoId, serialNumberMap);
34226 amit.gupta 1320
                }
32543 amit.gupta 1321
                if (serialNumberMap.size() == 0) continue;
32064 amit.gupta 1322
                //Continue if all imeis havent been grned
1323
 
32345 amit.gupta 1324
 
33662 amit.gupta 1325
                float eligiblePayoutValue = eligibleSlab.getPayoutAmount();
32345 amit.gupta 1326
                double finalPayout;
1327
                if (AmountType.PERCENTAGE.equals(itemCriteriaPayout.getAmountType())) {
1328
                    finalPayout = (eligiblePayoutValue * purchasedValue) / 100;
1329
                } else if (AmountType.FIXED.equals(itemCriteriaPayout.getAmountType())) {
36051 amit 1330
                    // FIXED = per piece, use per-criteria qty not base value
1331
                    finalPayout = eligiblePayoutValue * totalQty;
32345 amit.gupta 1332
                } else {
33695 amit.gupta 1333
                    Map<Integer, Double> fofoCriteriaPayoutMap = fixedSlabCriteriaPartnerMap.get(criteriaId);
1334
                    LOGGER.info("fofoCriteriaMap {}", fofoCriteriaPayoutMap);
32345 amit.gupta 1335
                    finalPayout = eligiblePayoutValue;
33695 amit.gupta 1336
                    if (fofoCriteriaPayoutMap != null && fofoCriteriaPayoutMap.containsKey(fofoId)) {
1337
                        finalPayout = eligiblePayoutValue - fofoCriteriaPayoutMap.get(fofoId);
1338
                        if (Math.abs(finalPayout) < Utils.DOUBLE_EPSILON) {
1339
                            finalPayout = 0;
32345 amit.gupta 1340
                        }
31920 amit.gupta 1341
                    }
1342
                }
32345 amit.gupta 1343
 
1344
                LOGGER.info("Or - {}", finalPayout);
1345
 
1346
                if (finalPayout > 0) {
1347
                    double totalRolloutAmount = 0;
1348
                    int totalDpValue = serialNumberInventoryItemMap.entrySet().stream().mapToInt(x -> (int) x.getValue().getUnitPrice()).sum();
1349
                    for (Map.Entry<String, InventoryItem> serialNumberInventoryItemEntry : serialNumberInventoryItemMap.entrySet()) {
1350
                        double amount = 0;
1351
                        LOGGER.info("Total DP Value {}", totalDpValue);
1352
                        if (AmountType.SLAB_FIXED.equals(itemCriteriaPayout.getAmountType())) {
1353
                            amount = (eligiblePayoutValue * serialNumberInventoryItemEntry.getValue().getUnitPrice()) / totalDpValue;
1354
                            LOGGER.info("Amount - {}", amount);
1355
                        } else {
1356
                            amount = eligiblePayoutValue;
1357
                            if (serialNumberPaid.containsKey(serialNumberInventoryItemEntry.getKey())) {
34073 ranu 1358
                                LOGGER.info("serial number slab amount {}", serialNumberPaid.get(serialNumberInventoryItemEntry.getKey()));
32345 amit.gupta 1359
                                amount = amount - serialNumberPaid.get(serialNumberInventoryItemEntry.getKey());
1360
                            }
1361
                        }
1362
                        LOGGER.info("Amount - {}", amount);
1363
                        //ignore reasonably small
33662 amit.gupta 1364
                        if (Math.abs(amount) < Utils.DOUBLE_EPSILON) continue;
32345 amit.gupta 1365
                        AmountModel amountModel = new AmountModel();
1366
                        amountModel.setAmountType(itemCriteriaPayout.getAmountType());
1367
                        amountModel.setAmount(amount);
1368
                        amountModel.setDiscount(createOfferRequest.isDiscount());
1369
                        InventoryPayoutModel inventoryPayoutModel = priceCircularService.getPayouts(serialNumberInventoryItemEntry.getValue());
1370
                        double rolloutAmount = inventoryPayoutModel.getRolloutAmount(amountModel);
1371
                        totalRolloutAmount += rolloutAmount;
1372
 
1373
                        OfferPayout offerPayout = new OfferPayout(fofoId, createOfferRequest.getId(), criteriaId, amount, serialNumberInventoryItemEntry.getKey(), rolloutAmount, SchemePayoutStatus.CREDITED, createOfferRequest.getDescription(), LocalDateTime.now());
33459 amit.gupta 1374
                        offerPayout.setInventoryItemId(serialNumberInventoryItemEntry.getValue().getId());
32345 amit.gupta 1375
                        offerPayoutRepository.persist(offerPayout);
1376
                    }
34623 amit.gupta 1377
                    walletService.addAmountToWallet(fofoId, createOfferRequest.getId(), WalletReferenceType.ADDITIONAL_SCHEME, createOfferRequest.getDescription(), (float) totalRolloutAmount, LocalDateTime.now());
32345 amit.gupta 1378
                }
31920 amit.gupta 1379
            }
1380
        }
1381
        Offer offer = offerRepository.selectById(createOfferRequest.getId());
1382
        offer.setProcessedTimestamp(LocalDateTime.now());
1383
    }
32064 amit.gupta 1384
 
33441 amit.gupta 1385
    private void rollbackPayout(int fofoId, int offerId, List<
1386
            OfferPayout> partnerPayouts, Set<String> returnedSerialNumbers) throws ProfitMandiBusinessException {
32795 amit.gupta 1387
        LOGGER.info("Rollback payout called for offerId {}", offerId);
1388
        float amountToRollback = 0;
1389
        int totalImeis = 0;
1390
        for (OfferPayout partnerPayout : partnerPayouts) {
1391
            LOGGER.info("serialNumberInventoryItemMap - {}", returnedSerialNumbers);
1392
            LOGGER.info("Serial Number - {}", partnerPayout.getSerialNumber());
1393
            if (returnedSerialNumbers.contains(partnerPayout.getSerialNumber()) && partnerPayout.getStatus().equals(SchemePayoutStatus.CREDITED)) {
1394
                partnerPayout.setRejectTimestamp(LocalDateTime.now());
1395
                partnerPayout.setStatus(SchemePayoutStatus.REJECTED);
1396
                amountToRollback += partnerPayout.getAmount();
1397
                totalImeis += 1;
1398
            }
1399
        }
1400
        if (amountToRollback > 0) {
1401
            LOGGER.info("Amount to Rollback - {}", amountToRollback);
1402
            walletService.rollbackAmountFromWallet(fofoId, amountToRollback, offerId, WalletReferenceType.ADDITIONAL_SCHEME, "Stock Returned, total " + totalImeis + "pc(s)", LocalDateTime.now());
1403
        }
1404
    }
1405
 
33441 amit.gupta 1406
    private Map<String, InventoryItem> getInventoryItemMap(int fofoId, Map<String, LineItem> serialNumberMap) throws
1407
            ProfitMandiBusinessException {
32064 amit.gupta 1408
        List<InventoryItem> inventoryItems = inventoryItemRepository.selectBySerialNumbers(serialNumberMap.keySet());
32345 amit.gupta 1409
        inventoryItems = inventoryItems.stream().filter(x -> x.getFofoId() == fofoId).collect(Collectors.toList());
1410
        Map<String, InventoryItem> inventoryItemMap = inventoryItems.stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x, (u, v) -> v.getCreateTimestamp().isAfter(u.getCreateTimestamp()) ? v : u));
32064 amit.gupta 1411
        return inventoryItemMap;
1412
    }
33030 amit.gupta 1413
 
1414
 
1415
    @Override
33247 ranu 1416
    public String getPartnerCriteriaString(PartnerCriteria partnerCriteria) throws ProfitMandiBusinessException {
33030 amit.gupta 1417
        StringBuilder sb = new StringBuilder();
1418
        if (partnerCriteria.getFofoIds().size() > 0) {
1419
            List<Integer> fofoIds = partnerCriteria.getFofoIds();
1420
            appendPartnerCodes(fofoIds, sb);
1421
 
1422
        } else {
1423
            sb.append("All");
1424
            if (partnerCriteria.getPartnerTypes().size() > 0) {
1425
                sb.append(" ").append(String.join(", ", partnerCriteria.getPartnerTypes().stream().map(x -> x.getValue()).collect(Collectors.toList())));
1426
            }
1427
            sb.append(" partners ");
1428
            if (partnerCriteria.getRegionIds().size() > 0) {
1429
                sb.append("from ");
1430
                sb.append(String.join(", ", partnerCriteria.getRegionIds().stream().map(x -> ProfitMandiConstants.WAREHOUSE_MAP.get(x)).collect(Collectors.toList())));
1431
            }
1432
            if (partnerCriteria.getExcludeFofoIds() != null && partnerCriteria.getExcludeFofoIds().size() > 0) {
35394 amit 1433
                sb.append("<b>excluding</b> ");
33030 amit.gupta 1434
                appendPartnerCodes(partnerCriteria.getExcludeFofoIds(), sb);
1435
            }
1436
        }
1437
        return sb.toString();
1438
    }
1439
 
33999 tejus.loha 1440
    @Override
1441
    public ByteArrayOutputStream createCSVOfferReport(CreateOfferRequest createOfferRequest) throws Exception {
1442
        List<List<?>> listOfRows = new ArrayList<>();
1443
        ByteArrayOutputStream baos = null;
1444
        Collection<OfferRowModel> offerRowModels = offerRepository.getOfferRows(createOfferRequest);
1445
        ItemCriteriaPayout itemCriteriaPayout = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts().get(0);
35394 amit 1446
        // Batch fetch all retailers once to avoid N+1 queries
1447
        Map<Integer, CustomRetailer> allRetailers = retailerService.getAllFofoRetailers();
33999 tejus.loha 1448
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
1449
            for (OfferRowModel offerRowModel : offerRowModels) {
35394 amit 1450
                CustomRetailer customRetailer = allRetailers.get(offerRowModel.getFofoId());
33999 tejus.loha 1451
                listOfRows.add(Arrays.asList(
1452
                        createOfferRequest.getId()
1453
                        , createOfferRequest.getName()
1454
                        , createOfferRequest.getTargetType()
1455
                        , createOfferRequest.getSchemeType()
1456
                        , itemCriteriaPayout.getStartDate()
1457
                        , itemCriteriaPayout.getEndDate()
1458
//                        , createOfferRequest.getBrandShareTerms()
1459
                        , createOfferRequest.getSellinPercentage()
1460
                        , "--"
1461
                        , createOfferRequest.getItemCriteriaString()
1462
                        , createOfferRequest.getStartDate()
1463
                        , createOfferRequest.getEndDate()
1464
                        , createOfferRequest.getCreatedOn()
1465
                        , customRetailer.getPartnerId()
1466
                        , customRetailer.getBusinessName()
1467
                        , customRetailer.getCode()
1468
                        , offerRowModel.getTotalBasePurchaseValue()
1469
                        , offerRowModel.getAchievedTarget()
1470
                        , offerRowModel.getPayoutPurchaseValue()
1471
                        , offerRowModel.getPayout()
1472
                        , offerRowModel.getPayoutType()
1473
                        , offerRowModel.getFinalPayout()
1474
                        , String.join(", ", offerRowModel.getEligibleImeis())));
1475
            }
1476
            baos = FileUtil.getCSVByteStream(
1477
                    Arrays.asList(
1478
                            "Id"
1479
                            , "Name"
1480
                            , "Target Type"
1481
                            , "Scheme Type"
1482
                            , "Payout Start"
1483
                            , "Payout End"
1484
//                            , "Brand %"
1485
                            , "Sellin %"
1486
                            , "Partner Criteria"
1487
                            , "Item Criteria"
1488
                            , "Start"
1489
                            , "End"
1490
                            , "Created"
1491
                            , "Partner Id"
1492
                            , "Partner Name"
1493
                            , "Partner Code"
1494
                            , "Base Purchase"
1495
                            , "Achieved Target"
1496
                            , "Eligible Purchase"
1497
                            , "Slab Amount"
1498
                            , "Slab Amount Type"
1499
                            , "Payout Value(Rs.)"
1500
                            , "Eligible IMEIs"
1501
                            , "Billing Pending Imeis"
1502
                    ), listOfRows);
1503
        } else {
1504
            for (OfferRowModel offerRowModel : offerRowModels) {
35394 amit 1505
                CustomRetailer customRetailer = allRetailers.get(offerRowModel.getFofoId());
33999 tejus.loha 1506
                listOfRows.add(Arrays.asList(
1507
                                createOfferRequest.getId()
1508
                                , createOfferRequest.getName()
1509
                                , createOfferRequest.getTargetType()
1510
                                , createOfferRequest.getSchemeType()
1511
                                , itemCriteriaPayout.getStartDate()
1512
                                , itemCriteriaPayout.getEndDate()
1513
//                                , createOfferRequest.getBrandShareTerms()
1514
                                , createOfferRequest.getSellinPercentage()
1515
                                , createOfferRequest.getPartnerCriteriaString()
1516
                                , createOfferRequest.getItemCriteriaString()
1517
                                , createOfferRequest.getStartDate()
1518
                                , createOfferRequest.getEndDate()
1519
                                , createOfferRequest.getCreatedOn()
1520
                                , customRetailer.getPartnerId()
1521
                                , customRetailer.getBusinessName()
1522
                                , customRetailer.getCode()
1523
                                , offerRowModel.getTotalSale()
1524
                                , offerRowModel.getEligibleSale()
1525
                                , offerRowModel.getPayoutTargetAchieved()
1526
                                , offerRowModel.getPayoutValue()
1527
                                , offerRowModel.getPayoutType()
1528
                                , offerRowModel.getPayoutValueDp()
1529
                                , offerRowModel.getFinalPayout()
1530
                                , String.join(", ", offerRowModel.getEligibleImeis())
1531
//                        ,String.join(", ", offerRowModel.getBaseCriteria())
1532
                        )
1533
                );
1534
            }
1535
            baos = FileUtil.getCSVByteStream(
1536
                    Arrays.asList(
1537
                            "Id"
1538
                            , "Name"
1539
                            , "Target Type"
1540
                            , "Scheme Type"
1541
                            , "Payout Start"
1542
                            , "Payout End"
1543
//                            , "Brand %"
1544
                            , "Sellin %"
1545
                            , "Partner Criteria"
1546
                            , "Item Criteria"
1547
                            , "Start"
1548
                            , "End"
1549
                            , "Created"
1550
                            , "Partner Id"
1551
                            , "Partner Name"
1552
                            , "Partner Code"
1553
                            , "Total Sale"
1554
                            , "Eligible Sale"
1555
                            , "Payout Target Achieved"
1556
                            , "Payout Amount"
1557
                            , "Payout Amount Type"
1558
                            , "Payout Value DP"
1559
                            , "Amount to be credited"
1560
                            , "Eligible Activated Imeis"
1561
                    ), listOfRows);
1562
        }
1563
        return baos;
1564
    }
1565
 
35205 amit 1566
    @Override
1567
    public void sendWhatsapp(Offer offer, List<Integer> fofoIds, String imageUrl) throws Exception {
1568
        if (fofoIds == null) {
1569
            fofoIds = fofoStoreRepository.selectActiveStores().stream().map(x -> x.getId()).collect(Collectors.toList());
1570
        }
1571
        final List<Integer> finalFofoIds = fofoIds;
1572
        //List<String> mobileNumbers = retailerService.getAllFofoRetailers().entrySet().stream().filter(x -> finalFofoIds.contains(x.getKey())).map(x -> x.getValue().getMobileNumber()).collect(Collectors.toList());
1573
        List<String> mobileNumbers = new ArrayList<>();
1574
        mobileNumbers.add("9911565032");
1575
        //mobileNumbers.add("9990381569");
1576
        //mobileNumbers.add("8383849914");
1577
        String message = "%s\n" +
1578
                "On %s of select models\n" +
1579
                "From %s to %s\n" +
1580
                "\n" +
1581
                "Happy Selling\n" +
1582
                "Team Smartdukaan";
1583
        //TV's mobile
1584
        for (String mobileNumber : mobileNumbers) {
1585
            notificationService.sendWhatsappMediaMessage(String.format(message, offer.getName(),
1586
                    offer.getSchemeType().toString(), FormattingUtils.formatDate(offer.getStartDate()),
1587
                    FormattingUtils.formatDate(offer.getEndDate())), mobileNumber, imageUrl, "offer-" + offer.getId() + ".png", WhatsappMessageType.IMAGE);
1588
        }
1589
    }
1590
 
33247 ranu 1591
    private void appendPartnerCodes(List<Integer> fofoIds, StringBuilder sb) throws ProfitMandiBusinessException {
33030 amit.gupta 1592
        Map<Integer, CustomRetailer> customRetailersMap = retailerService.getAllFofoRetailers();
33031 amit.gupta 1593
        List<String> businessNames = fofoIds.stream().map(x -> customRetailersMap.get(x)).filter(x -> x != null).map(x -> x.getBusinessName()).collect(Collectors.toList());
33030 amit.gupta 1594
        sb.append(String.join(", ", businessNames));
1595
    }
35856 amit 1596
 
1597
    @Override
1598
    public void deleteOffer(int offerId) throws ProfitMandiBusinessException {
1599
        Offer offer = offerRepository.selectById(offerId);
1600
        if (offer == null) {
1601
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
1602
        }
1603
        if (offer.isActive()) {
1604
            throw new ProfitMandiBusinessException("Cannot delete a published offer", "Cannot delete a published offer", "");
1605
        }
1606
        List<TargetSlabEntity> targetSlabs = offerTargetSlabRepository.selectByOfferIds(Collections.singletonList(offerId));
1607
        for (TargetSlabEntity targetSlab : targetSlabs) {
1608
            genericRepository.delete(targetSlab);
1609
        }
1610
        genericRepository.delete(offer);
1611
        LOGGER.info("Deleted offer {} and {} target slabs", offerId, targetSlabs.size());
1612
    }
1613
 
1614
    @Override
1615
    public List<Offer> publishAllUnpublished(YearMonth yearMonth) throws ProfitMandiBusinessException {
1616
        List<Offer> allOffers = offerRepository.selectAll(yearMonth, false);
1617
        List<Offer> unpublished = allOffers.stream().filter(o -> !o.isActive()).collect(Collectors.toList());
1618
        for (Offer offer : unpublished) {
1619
            offer.setActive(true);
1620
        }
1621
        LOGGER.info("Published {} unpublished offers for {}", unpublished.size(), yearMonth);
1622
        return unpublished;
1623
    }
35885 amit 1624
 
1625
    @Override
1626
    public void removePartnersFromOffer(int offerId, List<Integer> fofoIds) throws ProfitMandiBusinessException {
1627
        Offer offer = offerRepository.selectById(offerId);
1628
        if (offer == null) {
1629
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
1630
        }
1631
        PartnerCriteria partnerCriteria = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
1632
        if (partnerCriteria.getFofoIds() != null) {
1633
            partnerCriteria.getFofoIds().removeAll(fofoIds);
1634
        }
1635
        offer.setPartnerCriteria(gson.toJson(partnerCriteria));
1636
        genericRepository.persist(offer);
1637
        LOGGER.info("Removed partners {} from offer {}", fofoIds, offerId);
1638
    }
1639
 
1640
    @Override
1641
    public void addPartnersToOffer(int offerId, List<Integer> fofoIds) throws ProfitMandiBusinessException {
1642
        Offer offer = offerRepository.selectById(offerId);
1643
        if (offer == null) {
1644
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
1645
        }
1646
        PartnerCriteria partnerCriteria = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
1647
        List<Integer> existingFofoIds = partnerCriteria.getFofoIds();
1648
        if (existingFofoIds == null) {
1649
            existingFofoIds = new ArrayList<>();
1650
        }
1651
        for (int fofoId : fofoIds) {
1652
            if (!existingFofoIds.contains(fofoId)) {
1653
                existingFofoIds.add(fofoId);
1654
            }
1655
        }
1656
        partnerCriteria.setFofoIds(existingFofoIds);
1657
        offer.setPartnerCriteria(gson.toJson(partnerCriteria));
1658
        genericRepository.persist(offer);
1659
        LOGGER.info("Added partners {} to offer {}", fofoIds, offerId);
1660
    }
1661
 
1662
    @Override
1663
    public int cloneOfferForPartners(int sourceOfferId, List<Integer> fofoIds, List<Integer> targets) throws ProfitMandiBusinessException {
1664
        Offer sourceOffer = offerRepository.selectById(sourceOfferId);
1665
        if (sourceOffer == null) {
1666
            throw new ProfitMandiBusinessException("Source offer not found", "Source offer not found", "");
1667
        }
1668
        CreateOfferRequest clonedRequest = this.getCreateOfferRequest(sourceOffer);
1669
        clonedRequest.setId(0);
1670
        clonedRequest.setActive(false);
1671
 
1672
        PartnerCriteria newPartnerCriteria = new PartnerCriteria();
1673
        newPartnerCriteria.setFofoIds(new ArrayList<>(fofoIds));
1674
        newPartnerCriteria.setExcludeFofoIds(new ArrayList<>());
1675
        newPartnerCriteria.setRegionIds(clonedRequest.getPartnerCriteria().getRegionIds() != null
1676
                ? new ArrayList<>(clonedRequest.getPartnerCriteria().getRegionIds()) : new ArrayList<>());
1677
        newPartnerCriteria.setPartnerTypes(clonedRequest.getPartnerCriteria().getPartnerTypes() != null
1678
                ? new ArrayList<>(clonedRequest.getPartnerCriteria().getPartnerTypes()) : new ArrayList<>());
1679
        clonedRequest.setPartnerCriteria(newPartnerCriteria);
1680
 
1681
        if (targets != null && !targets.isEmpty() && !clonedRequest.getTargetSlabs().isEmpty()) {
1682
            List<PayoutSlab> payoutSlabs = clonedRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()
1683
                    .stream().flatMap(x -> x.getPayoutSlabs().stream()).collect(Collectors.toList());
1684
            int counter = 0;
1685
            for (PayoutSlab payoutSlab : payoutSlabs) {
1686
                if (counter < targets.size()) {
1687
                    payoutSlab.setOnwardsAmount(targets.get(counter));
1688
                    counter++;
1689
                }
1690
            }
1691
        }
1692
 
1693
        this.addOfferService(clonedRequest);
1694
        LOGGER.info("Cloned offer {} to new offer {} for partners {}", sourceOfferId, clonedRequest.getId(), fofoIds);
1695
        return clonedRequest.getId();
1696
    }
1697
 
1698
    @Override
1699
    public void updateOfferTargets(int offerId, List<Integer> newTargets) throws ProfitMandiBusinessException {
1700
        Offer offer = offerRepository.selectById(offerId);
1701
        if (offer == null) {
1702
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
1703
        }
1704
        List<TargetSlabEntity> targetSlabs = offerTargetSlabRepository.selectEntitiesByOfferId(offerId);
1705
        targetSlabs.sort(Comparator.comparing(TargetSlabEntity::getPayoutTarget));
1706
 
35889 amit 1707
        // Group slabs by unique payout_target (multiple item_criteria share the same target value)
1708
        LinkedHashMap<Integer, List<TargetSlabEntity>> groupedByTarget = new LinkedHashMap<>();
1709
        for (TargetSlabEntity slab : targetSlabs) {
1710
            groupedByTarget.computeIfAbsent(slab.getPayoutTarget(), k -> new ArrayList<>()).add(slab);
1711
        }
1712
        List<Integer> uniqueTargets = new ArrayList<>(groupedByTarget.keySet());
1713
 
1714
        if (newTargets.size() != uniqueTargets.size()) {
35885 amit 1715
            throw new ProfitMandiBusinessException(
35889 amit 1716
                    "Target count mismatch. Expected " + uniqueTargets.size() + " but got " + newTargets.size(),
35885 amit 1717
                    "Target count mismatch", "");
1718
        }
35889 amit 1719
 
1720
        // Update each group: all slabs sharing the same old target get the new target value
1721
        for (int i = 0; i < uniqueTargets.size(); i++) {
1722
            int oldTarget = uniqueTargets.get(i);
1723
            int newTarget = newTargets.get(i);
1724
            if (oldTarget != newTarget) {
1725
                for (TargetSlabEntity slab : groupedByTarget.get(oldTarget)) {
1726
                    genericRepository.updateById(TargetSlabEntity.class, "payoutTarget", newTarget, slab.getId());
1727
                }
1728
            }
35885 amit 1729
        }
1730
        LOGGER.info("Updated targets for offer {} to {}", offerId, newTargets);
1731
    }
35924 amit 1732
 
1733
    @Override
1734
    public void updateOfferSlabs(com.spice.profitmandi.dao.model.UpdateOfferSlabsRequest request) throws ProfitMandiBusinessException {
1735
        Offer offer = offerRepository.selectById(request.getOfferId());
1736
        if (offer == null) {
1737
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
1738
        }
1739
 
1740
        List<TargetSlabEntity> existingSlabs = offerTargetSlabRepository.selectEntitiesByOfferId(request.getOfferId());
1741
        Set<Integer> validSlabIds = existingSlabs.stream().map(TargetSlabEntity::getId).collect(Collectors.toSet());
1742
 
1743
        for (com.spice.profitmandi.dao.model.UpdateSlabRequest slab : request.getSlabs()) {
1744
            if (!validSlabIds.contains(slab.getId())) {
1745
                throw new ProfitMandiBusinessException("Invalid slab ID " + slab.getId(),
1746
                        "Slab does not belong to offer " + request.getOfferId(), "");
1747
            }
1748
            genericRepository.updateById(TargetSlabEntity.class, "payoutTarget", slab.getPayoutTarget(), slab.getId());
1749
            genericRepository.updateById(TargetSlabEntity.class, "payoutValue", slab.getPayoutValue(), slab.getId());
1750
        }
1751
        LOGGER.info("Updated slabs for offer {}: {}", request.getOfferId(), request.getSlabs());
1752
    }
27877 amit.gupta 1753
}