Subversion Repositories SmartDukaan

Rev

Rev 36633 | Details | Compare with Previous | Last modification | View Log | RSS feed

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