Subversion Repositories SmartDukaan

Rev

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

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