Subversion Repositories SmartDukaan

Rev

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