Subversion Repositories SmartDukaan

Rev

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