Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
24783 amit.gupta 1
package com.smartdukaan.cron.scheduled;
2
 
24810 amit.gupta 3
import java.io.Serializable;
24783 amit.gupta 4
import java.time.LocalDate;
25503 amit.gupta 5
import java.time.LocalDateTime;
24783 amit.gupta 6
import java.util.ArrayList;
7
import java.util.Arrays;
24810 amit.gupta 8
import java.util.HashSet;
24783 amit.gupta 9
import java.util.List;
10
import java.util.Map;
24810 amit.gupta 11
import java.util.Set;
24783 amit.gupta 12
import java.util.stream.Collectors;
13
 
33256 amit.gupta 14
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
34320 amit.gupta 15
import com.spice.profitmandi.dao.enumuration.catalog.StockTransactionType;
24783 amit.gupta 16
import org.apache.commons.io.output.ByteArrayOutputStream;
25076 amit.gupta 17
import org.apache.logging.log4j.LogManager;
18
import org.apache.logging.log4j.Logger;
24783 amit.gupta 19
import org.springframework.beans.factory.annotation.Autowired;
20
import org.springframework.core.io.ByteArrayResource;
21
import org.springframework.mail.javamail.JavaMailSender;
22
import org.springframework.stereotype.Component;
25072 amit.gupta 23
import org.springframework.transaction.annotation.Transactional;
24783 amit.gupta 24
 
25072 amit.gupta 25
import com.google.common.collect.Sets;
25076 amit.gupta 26
import com.smartdukaan.cron.Application;
24783 amit.gupta 27
import com.spice.profitmandi.common.util.FileUtil;
28
import com.spice.profitmandi.common.util.FormattingUtils;
29
import com.spice.profitmandi.common.util.Utils;
24810 amit.gupta 30
import com.spice.profitmandi.dao.entity.catalog.Scheme;
24826 amit.gupta 31
import com.spice.profitmandi.dao.entity.fofo.FofoLineItem;
25081 amit.gupta 32
import com.spice.profitmandi.dao.entity.fofo.FofoOrder;
24810 amit.gupta 33
import com.spice.profitmandi.dao.entity.fofo.InventoryItem;
25072 amit.gupta 34
import com.spice.profitmandi.dao.entity.fofo.Purchase;
35
import com.spice.profitmandi.dao.entity.fofo.ScanRecord;
24810 amit.gupta 36
import com.spice.profitmandi.dao.entity.fofo.SchemeInOut;
24783 amit.gupta 37
import com.spice.profitmandi.dao.entity.transaction.Order;
38
import com.spice.profitmandi.dao.entity.transaction.ReturnOrder;
39
import com.spice.profitmandi.dao.entity.transaction.UserWallet;
40
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
24810 amit.gupta 41
import com.spice.profitmandi.dao.enumuration.catalog.SchemeType;
25072 amit.gupta 42
import com.spice.profitmandi.dao.enumuration.fofo.ScanType;
24810 amit.gupta 43
import com.spice.profitmandi.dao.repository.catalog.SchemeRepository;
24783 amit.gupta 44
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
24826 amit.gupta 45
import com.spice.profitmandi.dao.repository.fofo.FofoLineItemRepository;
46
import com.spice.profitmandi.dao.repository.fofo.FofoOrderItemRepository;
25081 amit.gupta 47
import com.spice.profitmandi.dao.repository.fofo.FofoOrderRepository;
24810 amit.gupta 48
import com.spice.profitmandi.dao.repository.fofo.InventoryItemRepository;
25072 amit.gupta 49
import com.spice.profitmandi.dao.repository.fofo.PurchaseRepository;
50
import com.spice.profitmandi.dao.repository.fofo.ScanRecordRepository;
24810 amit.gupta 51
import com.spice.profitmandi.dao.repository.fofo.SchemeInOutRepository;
24783 amit.gupta 52
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
53
import com.spice.profitmandi.dao.repository.transaction.ReturnOrderRepository;
54
import com.spice.profitmandi.dao.repository.transaction.UserWalletHistoryRepository;
55
import com.spice.profitmandi.dao.repository.transaction.UserWalletRepository;
25083 amit.gupta 56
import com.spice.profitmandi.service.order.OrderService;
24783 amit.gupta 57
import com.spice.profitmandi.service.user.RetailerService;
58
 
59
import in.shop2020.model.v1.order.OrderStatus;
60
import in.shop2020.model.v1.order.WalletReferenceType;
61
 
62
@Component
25072 amit.gupta 63
@Transactional(rollbackFor = Throwable.class)
24783 amit.gupta 64
public class Reconciliation {
25503 amit.gupta 65
 
33256 amit.gupta 66
    private static final Logger LOGGER = LogManager.getLogger(Application.class);
25503 amit.gupta 67
 
33256 amit.gupta 68
    @Autowired
69
    private FofoStoreRepository fofoStoreRepository;
25072 amit.gupta 70
 
33256 amit.gupta 71
    private static final List<WalletReferenceType> reconciliationReferenceTypes = Arrays
72
            .asList(WalletReferenceType.PURCHASE, WalletReferenceType.SCHEME_IN, WalletReferenceType.SCHEME_OUT);
27745 amit.gupta 73
 
33256 amit.gupta 74
    @Autowired
75
    private PurchaseRepository purchaseRepository;
25503 amit.gupta 76
 
33256 amit.gupta 77
    @Autowired
78
    private OrderService orderService;
25503 amit.gupta 79
 
33256 amit.gupta 80
    @Autowired
81
    private FofoOrderItemRepository fofoOrderItemRepository;
82
    @Autowired
83
    private FofoLineItemRepository fofoLineItemRepository;
84
    @Autowired
85
    private UserWalletRepository userWalletRepository;
25072 amit.gupta 86
 
33256 amit.gupta 87
    @Autowired
88
    private InventoryItemRepository inventoryItemRepository;
25072 amit.gupta 89
 
33256 amit.gupta 90
    @Autowired
91
    private ScanRecordRepository scanRecordRepository;
92
    @Autowired
93
    private UserWalletHistoryRepository userWalletHistoryRepository;
94
    @Autowired
95
    private SchemeInOutRepository schemeInOutRepository;
96
    @Autowired
97
    private SchemeRepository schemeRepository;
25081 amit.gupta 98
 
33256 amit.gupta 99
    @Autowired
100
    private RetailerService retailerService;
101
    @Autowired
102
    private ReturnOrderRepository returnOrderRepository;
103
    @Autowired
104
    private OrderRepository orderRepository;
105
    @Autowired
106
    private FofoOrderRepository fofoOrderRepository;
24783 amit.gupta 107
 
33256 amit.gupta 108
    @Autowired
109
    private JavaMailSender mailSender;
25072 amit.gupta 110
 
33256 amit.gupta 111
    public void dailyReconciliation() throws Exception {
112
        LocalDate date = LocalDate.now().minusDays(1);
113
        dailyReconciliation(date);
114
    }
24810 amit.gupta 115
 
33256 amit.gupta 116
    public void dailyReconciliation(LocalDate localDate) throws Exception {
117
        Map<SchemeType, Set<Integer>> schemeTypeMap = schemeRepository.selectAll().stream()
118
                .collect(Collectors.groupingBy(Scheme::getType, Collectors.mapping(Scheme::getId, Collectors.toSet())));
119
        boolean reconciled = true;
120
        Map<Integer, String> stores = fofoStoreRepository.getStoresMap();
121
        List<List<?>> rows = new ArrayList<>();
122
        LocalDate yesterday = LocalDate.now().minusDays(1);
123
        Map<Integer, String> retailerNameMap = retailerService
124
                .getAllFofoRetailerIdNameMap(new ArrayList<>(stores.keySet()));
125
        for (int partnerId : stores.keySet()) {
126
            UserWallet uw = userWalletRepository.selectByRetailerId(partnerId);
127
            List<UserWalletHistory> walletHistory = userWalletHistoryRepository.selectByWalletIdAndDate(uw.getId(),
128
                    yesterday);
129
            Map<WalletReferenceType, List<UserWalletHistory>> referenceWiseWalletHistory = walletHistory.stream()
130
                    .collect(Collectors.groupingBy(x -> x.getReferenceType(), Collectors.toList()));
131
            reconciliationReferenceTypes.forEach(x -> {
132
                if (!referenceWiseWalletHistory.containsKey(x)) {
133
                    referenceWiseWalletHistory.put(x, new ArrayList<>());
134
                }
135
            });
24831 amit.gupta 136
 
33256 amit.gupta 137
            List<Serializable> reconciliation = new ArrayList<>();
138
            LocalDate dateToReconcile = yesterday;
139
            // "PartnerId", "Partner Name", "Reconciliation Date"
140
            reconciliation.addAll(Arrays.asList(partnerId, retailerNameMap.get(partnerId), dateToReconcile));
24810 amit.gupta 141
 
33256 amit.gupta 142
            for (WalletReferenceType walletReferenceType : reconciliationReferenceTypes) {
143
                List<UserWalletHistory> history = referenceWiseWalletHistory.get(walletReferenceType);
144
                Map<Integer, Integer> referenceWalletMap = history.stream().collect(
145
                        Collectors.groupingBy(x -> x.getReference(), Collectors.summingInt(x -> x.getAmount())));
146
                switch (walletReferenceType) {
147
                    case PURCHASE:
148
                        reconciliation.addAll(reconcileOrdersAndWallet(dateToReconcile, referenceWalletMap, history));
149
                        break;
150
                    case SCHEME_IN:
34320 amit.gupta 151
                        for (SchemeType schemeType : SchemeType.IN_TYPES) {
152
                            reconciliation.addAll(reconcileSchemeInAndWallet(dateToReconcile, referenceWalletMap, history,
153
                                    schemeTypeMap.get(schemeType)));
154
                        }
33256 amit.gupta 155
                        break;
156
                    case SCHEME_OUT:
34320 amit.gupta 157
                        for (SchemeType schemeType : SchemeType.OUT_TYPES) {
158
                            reconciliation.addAll(reconcileSchemeOutAndWallet(dateToReconcile, referenceWalletMap, history,
159
                                    schemeTypeMap.get(schemeType)));
160
                            break;
161
                        }
33256 amit.gupta 162
                    default:
163
                        break;
24783 amit.gupta 164
 
33256 amit.gupta 165
                }
166
            }
167
            reconciled = reconciled || Boolean.TRUE.equals(reconciliation.get(0));
168
            rows.add(reconciliation);
169
        }
170
        ByteArrayOutputStream baos = FileUtil.getCSVByteStream(Arrays.asList("PartnerId", "Partner Name",
171
                "Reconciliation Date", "Purchase Reconciled", "Wallet amount consumed", "Ordered Total",
172
                "Cancelled Total", "Refunded Total", "Scheme In Reconciled", "Scheme In to Wallet",
173
                "Scheme In disbursed", "Scheme In rolledback", "SchemeOut Reconciled", "Scheme Out to Wallet",
174
                "Scheme Out Disbursed", "Scheme Out Rolledback"), rows);
24783 amit.gupta 175
 
33256 amit.gupta 176
        Utils.sendMailWithAttachment(mailSender,
177
                new String[]{"amit.gupta@shop2020.in", "neeraj.gupta@smartdukaan.com"}, new String[]{},
178
                reconciled ? "Reconciled Successfully" : "Reconciliation failed", "Report attached",
179
                String.format("reconciliation-%s.csv", FormattingUtils.formatDate(yesterday.atStartOfDay())),
180
                new ByteArrayResource(baos.toByteArray()));
181
    }
24783 amit.gupta 182
 
33256 amit.gupta 183
    private List<? extends Serializable> reconcileOrdersAndWallet(LocalDate localDate,
184
                                                                  Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history) throws Exception {
24783 amit.gupta 185
 
33256 amit.gupta 186
        int totalWalletConsumed = 0;
187
        float cancelledAmount = 0;
188
        float returnedAmount = 0;
189
        float totalDeductedAmount = 0;
190
        for (int transactionId : transactionsOnThatDate.keySet()) {
191
            List<Order> orders = orderRepository.selectAllByTransactionId(transactionId);
192
            for (Order o : orders) {
193
                if (o.getCreateTimestamp().toLocalDate().equals(localDate)) {
194
                    if (Arrays.asList(OrderStatus.PAYMENT_PENDING, OrderStatus.PAYMENT_FAILED)
195
                            .contains(o.getStatus())) {
196
                        cancelledAmount += o.getWalletAmount();
197
                    } else if (o.getRefundTimestamp() != null
198
                            && o.getRefundTimestamp().toLocalDate().equals(localDate)) {
199
                        ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
200
                        if (returnedOrder == null) {
201
                            cancelledAmount += o.getWalletAmount();
202
                        } else {
203
                            returnedAmount += returnedOrder.getTotalPrice();
204
                        }
205
                    }
206
                    totalDeductedAmount += o.getWalletAmount();
24810 amit.gupta 207
 
33256 amit.gupta 208
                } else if (o.getRefundTimestamp() != null && o.getRefundTimestamp().toLocalDate().equals(localDate)) {
209
                    ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
210
                    if (returnedOrder == null) {
211
                        cancelledAmount += o.getWalletAmount();
212
                    } else {
213
                        returnedAmount += returnedOrder.getTotalPrice();
214
                    }
215
                }
216
            }
217
            totalWalletConsumed -= transactionsOnThatDate.get(transactionId);
24783 amit.gupta 218
 
33256 amit.gupta 219
        }
220
        boolean reconciled = Math
221
                .abs(totalWalletConsumed - (totalDeductedAmount - cancelledAmount - returnedAmount)) < 2;
24783 amit.gupta 222
 
33256 amit.gupta 223
        return Arrays.asList(reconciled, totalWalletConsumed, totalDeductedAmount, cancelledAmount, returnedAmount, "");
24783 amit.gupta 224
 
33256 amit.gupta 225
    }
24783 amit.gupta 226
 
33256 amit.gupta 227
    private List<? extends Serializable> reconcileSchemeInAndWallet(LocalDate localDate,
228
                                                                    Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) throws ProfitMandiBusinessException {
24810 amit.gupta 229
 
33256 amit.gupta 230
        int totalSchemeInWalletCredited = 0;
231
        float schemeInAmountAdded = 0;
232
        float schemeInAmountRolledBack = 0;
233
        for (int transactionId : transactionsOnThatDate.keySet()) {
234
            List<InventoryItem> inventoryItems = inventoryItemRepository.selectByPurchaseId(transactionId).stream()
235
                    .filter(x -> x.getSerialNumber() != null).collect(Collectors.toList());
236
            Set<Integer> inventoryItemIds = inventoryItems.stream().map(x -> x.getId()).collect(Collectors.toSet());
237
            if (inventoryItemIds.size() == 0) {
238
                continue;
239
            }
240
            List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
241
                    .stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
242
            totalSchemeInWalletCredited += transactionsOnThatDate.get(transactionId);
243
            for (SchemeInOut sio : sios) {
244
                if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
245
                    schemeInAmountAdded += sio.getAmount();
246
                }
247
                if (sio.getRolledBackTimestamp() != null
248
                        && sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
249
                    schemeInAmountRolledBack += sio.getAmount();
250
                }
251
            }
24810 amit.gupta 252
 
33256 amit.gupta 253
        }
254
        boolean reconciled = Math
255
                .abs(totalSchemeInWalletCredited - (schemeInAmountAdded - schemeInAmountRolledBack)) < 5;
24810 amit.gupta 256
 
33256 amit.gupta 257
        return Arrays.asList(reconciled, totalSchemeInWalletCredited, schemeInAmountAdded, schemeInAmountRolledBack,
258
                "");
24783 amit.gupta 259
 
33256 amit.gupta 260
    }
25072 amit.gupta 261
 
33256 amit.gupta 262
    private List<? extends Serializable> reconcileSchemeOutAndWallet(LocalDate localDate,
263
                                                                     Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) throws ProfitMandiBusinessException {
264
        int totalSchemeOutWalletCredited = 0;
265
        float schemeOutAmountAdded = 0;
266
        float schemeOutAmountRolledBack = 0;
267
        for (int fofoOrderId : transactionsOnThatDate.keySet()) {
268
            Set<Integer> fofoOrderItemIds = fofoOrderItemRepository.selectByOrderId(fofoOrderId).stream()
269
                    .map(x -> x.getId()).collect(Collectors.toSet());
270
            List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
271
            Set<Integer> inventoryItemIds = fofoLineItems.stream().map(x -> x.getInventoryItemId())
272
                    .collect(Collectors.toSet());
273
            List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
274
                    .stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
275
            totalSchemeOutWalletCredited += transactionsOnThatDate.get(fofoOrderId);
276
            for (SchemeInOut sio : sios) {
277
                if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
278
                    schemeOutAmountAdded += sio.getAmount();
279
                }
280
                if (sio.getRolledBackTimestamp() != null
281
                        && sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
282
                    schemeOutAmountRolledBack += sio.getAmount();
283
                }
284
            }
285
        }
286
        boolean reconciled = Math
287
                .abs(totalSchemeOutWalletCredited - (schemeOutAmountAdded - schemeOutAmountRolledBack)) < 5;
288
        return Arrays.asList(reconciled, totalSchemeOutWalletCredited, schemeOutAmountAdded, schemeOutAmountRolledBack,
289
                "");
290
    }
25072 amit.gupta 291
 
33256 amit.gupta 292
    public void reconcileExpiredFixedSchemes() throws Exception {
293
        List<Scheme> allSchemes = schemeRepository.selectAll();
294
        // .stream().filter(x ->
295
        // x.getAmountType().equals(AmountType.FIXED)).collect(Collectors.toList());
296
        allSchemes = allSchemes.stream()
297
                .filter(x -> x.getEndDateTime().isAfter(LocalDate.of(2019, 3, 31).atStartOfDay()))
298
                .collect(Collectors.toList());
299
        System.out.println(
300
                "InventoryId\tSerialNumber\tItem Id\tScheme Id\tScheme Name\tScheme Type\tAmount Type\tScheme Amount\tAmount Paid\tReference\tTransaction Time\tScheme Start\tScheme End\tScheme Expiry");
301
        for (Scheme scheme : allSchemes) {
302
            if (scheme.getExpireTimestamp() != null) {
303
                if (scheme.getExpireTimestamp().isBefore(scheme.getEndDateTime())) {
304
                    List<SchemeInOut> inOuts = schemeInOutRepository.selectBySchemeIds(Sets.newHashSet(scheme.getId()));
34320 amit.gupta 305
                    if (scheme.getType().getTransactionType().equals(StockTransactionType.IN)) {
33256 amit.gupta 306
                        for (SchemeInOut schemeInOut : inOuts) {
307
                            ScanRecord inRecord = scanRecordRepository
308
                                    .selectByInventoryItemId(schemeInOut.getInventoryItemId()).stream()
309
                                    .filter(x -> x.getType().equals(ScanType.PURCHASE)).collect(Collectors.toList())
310
                                    .get(0);
311
                            if (inRecord.getCreateTimestamp().isAfter(scheme.getExpireTimestamp())) {
312
                                InventoryItem ii = inventoryItemRepository.selectById(inRecord.getInventoryItemId());
313
                                Purchase purchase = purchaseRepository.selectByIdAndFofoId(ii.getPurchaseId(),
314
                                        ii.getFofoId());
315
                                System.out.println(String.format("%d\t%s\t%d\t%d\t%s\t%s\t%f\t%f\t%d\t%s\t%s\t%s\t%s",
316
                                        ii.getId(), ii.getSerialNumber(), ii.getItemId(), schemeInOut.getSchemeId(),
317
                                        scheme.getName(), scheme.getType(), scheme.getAmount(), schemeInOut.getAmount(),
318
                                        purchase.getId(), inRecord.getCreateTimestamp(), scheme.getStartDateTime(),
319
                                        scheme.getEndDateTime(), scheme.getExpireTimestamp()));
320
                            }
25503 amit.gupta 321
 
33256 amit.gupta 322
                        }
323
                    }
34320 amit.gupta 324
                    if (scheme.getType().getTransactionType().equals(StockTransactionType.OUT)) {
33256 amit.gupta 325
                        for (SchemeInOut schemeInOut : inOuts) {
326
                            ScanRecord outRecord = scanRecordRepository
327
                                    .selectByInventoryItemId(schemeInOut.getInventoryItemId()).stream()
328
                                    .filter(x -> x.getType().equals(ScanType.SALE))
329
                                    .sorted((x1, x2) -> x1.getId() - x2.getId()).collect(Collectors.toList()).get(0);
330
                            if (outRecord.getCreateTimestamp().isAfter(scheme.getExpireTimestamp())) {
331
                                InventoryItem ii = inventoryItemRepository.selectById(outRecord.getInventoryItemId());
332
                                FofoOrder fofoOrder;
333
                                if (outRecord.getOrderId() == 0) {
334
                                    fofoOrder = orderService.getOrderByInventoryItemId(ii.getId());
335
                                } else {
336
                                    fofoOrder = fofoOrderRepository.selectByOrderId(outRecord.getOrderId());
337
                                    if (fofoOrder == null) {
338
                                        LOGGER.info("Order id does not exits - {}", outRecord.getOrderId());
339
                                        continue;
340
                                    }
341
                                }
342
                                System.out.println(String.format("%d\t%s\t%d\t%d\t%s\t%s\t%f\t%f\t%d\t%s\t%s\t%s\t%s",
343
                                        ii.getId(), ii.getSerialNumber(), ii.getItemId(), schemeInOut.getSchemeId(),
344
                                        scheme.getName(), scheme.getType(), scheme.getAmount(), schemeInOut.getAmount(),
345
                                        fofoOrder.getId(), outRecord.getCreateTimestamp(), scheme.getStartDateTime(),
346
                                        scheme.getEndDateTime(), scheme.getExpireTimestamp()));
25072 amit.gupta 347
 
33256 amit.gupta 348
                            }
25072 amit.gupta 349
 
33256 amit.gupta 350
                        }
351
                    }
352
                }
353
            }
354
        }
25503 amit.gupta 355
 
33256 amit.gupta 356
    }
25503 amit.gupta 357
 
33256 amit.gupta 358
    private void checkForDblClickIssues() {
359
        // For all schmes from April onwards
360
    }
25503 amit.gupta 361
 
33256 amit.gupta 362
    private void dbClickPurchase() {
363
        List<Purchase> purchases = purchaseRepository
364
                .selectAllBetweenPurchaseDate(LocalDate.of(2019, 4, 1).atStartOfDay(), LocalDateTime.now());
365
    }
25503 amit.gupta 366
 
33256 amit.gupta 367
    private void dbClickSale() {
368
        List<FofoOrder> sales = fofoOrderRepository.selectBetweenSaleDate(LocalDate.of(2019, 4, 1).atStartOfDay(),
369
                LocalDateTime.now());
370
 
371
    }
24783 amit.gupta 372
}