Subversion Repositories SmartDukaan

Rev

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

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