Subversion Repositories SmartDukaan

Rev

Rev 24829 | Rev 24831 | Go to most recent revision | 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;
5
import java.util.ArrayList;
6
import java.util.Arrays;
24810 amit.gupta 7
import java.util.HashSet;
24783 amit.gupta 8
import java.util.List;
9
import java.util.Map;
24810 amit.gupta 10
import java.util.Set;
24783 amit.gupta 11
import java.util.stream.Collectors;
12
 
13
import org.apache.commons.io.output.ByteArrayOutputStream;
14
import org.springframework.beans.factory.annotation.Autowired;
15
import org.springframework.core.io.ByteArrayResource;
16
import org.springframework.mail.javamail.JavaMailSender;
17
import org.springframework.stereotype.Component;
18
 
19
import com.spice.profitmandi.common.util.FileUtil;
20
import com.spice.profitmandi.common.util.FormattingUtils;
21
import com.spice.profitmandi.common.util.Utils;
24810 amit.gupta 22
import com.spice.profitmandi.dao.entity.catalog.Scheme;
24826 amit.gupta 23
import com.spice.profitmandi.dao.entity.fofo.FofoLineItem;
24810 amit.gupta 24
import com.spice.profitmandi.dao.entity.fofo.InventoryItem;
25
import com.spice.profitmandi.dao.entity.fofo.SchemeInOut;
24783 amit.gupta 26
import com.spice.profitmandi.dao.entity.transaction.Order;
27
import com.spice.profitmandi.dao.entity.transaction.ReturnOrder;
28
import com.spice.profitmandi.dao.entity.transaction.UserWallet;
29
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
24810 amit.gupta 30
import com.spice.profitmandi.dao.enumuration.catalog.SchemeType;
31
import com.spice.profitmandi.dao.repository.catalog.SchemeRepository;
24783 amit.gupta 32
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
24826 amit.gupta 33
import com.spice.profitmandi.dao.repository.fofo.FofoLineItemRepository;
34
import com.spice.profitmandi.dao.repository.fofo.FofoOrderItemRepository;
24810 amit.gupta 35
import com.spice.profitmandi.dao.repository.fofo.InventoryItemRepository;
36
import com.spice.profitmandi.dao.repository.fofo.SchemeInOutRepository;
24783 amit.gupta 37
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
38
import com.spice.profitmandi.dao.repository.transaction.ReturnOrderRepository;
39
import com.spice.profitmandi.dao.repository.transaction.UserWalletHistoryRepository;
40
import com.spice.profitmandi.dao.repository.transaction.UserWalletRepository;
41
import com.spice.profitmandi.service.user.RetailerService;
42
 
43
import in.shop2020.model.v1.order.OrderStatus;
44
import in.shop2020.model.v1.order.WalletReferenceType;
45
 
46
@Component
47
public class Reconciliation {
48
	@Autowired
49
	private FofoStoreRepository fofoStoreRepository;
50
	@Autowired
24826 amit.gupta 51
	private FofoOrderItemRepository fofoOrderItemRepository;
52
	@Autowired
53
	private FofoLineItemRepository fofoLineItemRepository;
54
	@Autowired
24783 amit.gupta 55
	private UserWalletRepository userWalletRepository;
56
	@Autowired
57
	private UserWalletHistoryRepository userWalletHistoryRepository;
58
	@Autowired
24810 amit.gupta 59
	private SchemeInOutRepository schemeInOutRepository;
60
	@Autowired
61
	private SchemeRepository schemeRepository;
62
	@Autowired
63
	private InventoryItemRepository inventoryRepository;
64
	@Autowired
24783 amit.gupta 65
	private RetailerService retailerService;
66
	@Autowired
67
	private ReturnOrderRepository returnOrderRepository;
68
	@Autowired
69
	private OrderRepository orderRepository;
70
	@Autowired
71
	private JavaMailSender mailSender;
72
 
73
	public void dailyReconciliation() throws Exception {
24810 amit.gupta 74
		Map<SchemeType, Set<Integer>> schemeTypeMap = schemeRepository.selectAll().stream()
75
				.collect(Collectors.groupingBy(Scheme::getType, Collectors.mapping(Scheme::getId, Collectors.toSet())));
24783 amit.gupta 76
		boolean reconciled = true;
77
		Map<Integer, String> stores = fofoStoreRepository.getStoresMap();
24810 amit.gupta 78
		List<List<? extends Serializable>> rows = new ArrayList<>();
24783 amit.gupta 79
		LocalDate yesterday = LocalDate.now().minusDays(1);
80
		Map<Integer, String> retailerNameMap = retailerService
81
				.getAllFofoRetailerIdNameMap(new ArrayList<>(stores.keySet()));
82
		for (int partnerId : stores.keySet()) {
83
			UserWallet uw = userWalletRepository.selectByRetailerId(partnerId);
84
			List<UserWalletHistory> walletHistory = userWalletHistoryRepository.selectByWalletIdAndDate(uw.getId(),
85
					yesterday);
24810 amit.gupta 86
			Map<WalletReferenceType, List<UserWalletHistory>> referenceWiseWalletHistory = walletHistory.stream()
87
					.collect(Collectors.groupingBy(x -> x.getReferenceType(), Collectors.toList()));
24830 amit.gupta 88
			Arrays.asList(WalletReferenceType.PURCHASE, WalletReferenceType.SCHEME_IN, WalletReferenceType.SCHEME_OUT).forEach(
89
					x-> {
90
						if(!referenceWiseWalletHistory.containsKey(x)) {
91
							referenceWiseWalletHistory.put(x, new ArrayList<>());
92
						}
93
					});
24810 amit.gupta 94
 
95
			for (Map.Entry<WalletReferenceType, List<UserWalletHistory>> entry : referenceWiseWalletHistory
96
					.entrySet()) {
97
				LocalDate dateToReconcile = yesterday;
24783 amit.gupta 98
				List<UserWalletHistory> history = entry.getValue();
24829 amit.gupta 99
				List<Serializable> reconciliation = new ArrayList<>();
100
				reconciliation.addAll(Arrays.asList(partnerId, retailerNameMap.get(partnerId), dateToReconcile));
24810 amit.gupta 101
				Map<Integer, Integer> referenceWalletMap = entry.getValue().stream().collect(
102
						Collectors.groupingBy(x -> x.getReference(), Collectors.summingInt(x -> x.getAmount())));
103
				switch (entry.getKey()) {
104
				case PURCHASE:
105
					reconciliation.addAll(
106
							reconcileOrdersAndWallet(uw.getUserId(), dateToReconcile, referenceWalletMap, history));
107
					break;
108
				case SCHEME_IN:
109
					reconciliation.addAll(reconcileSchemeInAndWallet(uw.getUserId(), dateToReconcile,
110
							referenceWalletMap, history, schemeTypeMap.get(SchemeType.IN)));
111
					break;
112
				case SCHEME_OUT:
24826 amit.gupta 113
					reconciliation.addAll(reconcileSchemeOutAndWallet(uw.getUserId(), dateToReconcile,
114
							referenceWalletMap, history, schemeTypeMap.get(SchemeType.OUT)));
24810 amit.gupta 115
					break;
116
				default:
117
					break;
118
 
119
				}
120
				reconciled = reconciled || Boolean.TRUE.equals(reconciliation.get(0));
24783 amit.gupta 121
				rows.add(reconciliation);
122
			}
123
		}
24826 amit.gupta 124
		ByteArrayOutputStream baos = FileUtil.getCSVByteStream(Arrays.asList("PartnerId", "Store Name",
125
				"Reconciliation Date", "Purchase Reconciled", "Wallet amount consumed", "Ordered Total",
126
				"Cancelled Total", "Refunded Total", "", "Scheme In to Wallet", "Scheme In disbursed",
127
				"Scheme In rolledback", "Scheme Out to Wallet", "Scheme Out Disbursed", "Scheme Out Rolledback"), rows);
24783 amit.gupta 128
 
24810 amit.gupta 129
		Utils.sendMailWithAttachment(mailSender, new String[] { "amit.gupta@shop2020.in" }, new String[] {},
130
				reconciled ? "Reconciled Successfully" : "Reconciliation failed", "Report attached",
131
				String.format("reconciliation-%s.csv", FormattingUtils.formatDate(yesterday.atStartOfDay())),
132
				new ByteArrayResource(baos.toByteArray()));
24783 amit.gupta 133
	}
134
 
24810 amit.gupta 135
	private List<? extends Serializable> reconcileOrdersAndWallet(int fofoId, LocalDate localDate,
136
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history) throws Exception {
24783 amit.gupta 137
 
138
		int totalWalletConsumed = 0;
139
		float cancelledAmount = 0;
140
		float returnedAmount = 0;
141
		float totalDeductedAmount = 0;
142
		for (int transactionId : transactionsOnThatDate.keySet()) {
143
			List<Order> orders = orderRepository.selectAllByTransactionId(transactionId);
144
			for (Order o : orders) {
145
				if (o.getCreateTimestamp().toLocalDate().equals(localDate)) {
146
					if (Arrays.asList(OrderStatus.PAYMENT_PENDING, OrderStatus.PAYMENT_FAILED)
147
							.contains(o.getStatus())) {
148
						cancelledAmount += o.getWalletAmount();
149
					} else if (o.getRefundTimestamp() != null
150
							&& o.getRefundTimestamp().toLocalDate().equals(localDate)) {
151
						ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
152
						if (returnedOrder == null) {
153
							cancelledAmount += o.getWalletAmount();
154
						} else {
155
							returnedAmount += returnedOrder.getTotalPrice();
156
						}
157
					}
158
					totalDeductedAmount += o.getWalletAmount();
159
 
160
				} else if (o.getRefundTimestamp() != null && o.getRefundTimestamp().toLocalDate().equals(localDate)) {
161
					ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
162
					if (returnedOrder == null) {
163
						cancelledAmount += o.getWalletAmount();
164
					} else {
165
						returnedAmount += returnedOrder.getTotalPrice();
166
					}
167
				}
168
			}
169
			totalWalletConsumed -= transactionsOnThatDate.get(transactionId);
24810 amit.gupta 170
 
24783 amit.gupta 171
		}
24810 amit.gupta 172
		boolean reconciled = Math
173
				.abs(totalWalletConsumed - (totalDeductedAmount - cancelledAmount - returnedAmount)) < 2;
24783 amit.gupta 174
 
24826 amit.gupta 175
		return Arrays.asList(reconciled, totalWalletConsumed, totalDeductedAmount, cancelledAmount, returnedAmount, "");
24783 amit.gupta 176
 
177
	}
178
 
24810 amit.gupta 179
	private List<? extends Serializable> reconcileSchemeInAndWallet(int fofoId, LocalDate localDate,
180
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
24783 amit.gupta 181
 
24810 amit.gupta 182
		int totalSchemeInWalletCredited = 0;
183
		float schemeInAmountAdded = 0;
184
		float schemeInAmountRolledBack = 0;
185
		for (int transactionId : transactionsOnThatDate.keySet()) {
186
			List<InventoryItem> inventoryItems = inventoryRepository.selectByPurchaseId(transactionId).stream()
187
					.filter(x -> x.getSerialNumber() != null).collect(Collectors.toList());
188
			Set<Integer> inventoryItemIds = inventoryItems.stream().map(x -> x.getId()).collect(Collectors.toSet());
189
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
190
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
191
			totalSchemeInWalletCredited += transactionsOnThatDate.get(transactionId);
192
			for (SchemeInOut sio : sios) {
193
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
194
					schemeInAmountAdded += sio.getAmount();
195
				}
24829 amit.gupta 196
				if (sio.getRolledBackTimestamp() != null
197
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 198
					schemeInAmountRolledBack += sio.getAmount();
24810 amit.gupta 199
				}
200
			}
201
 
202
		}
24826 amit.gupta 203
		boolean reconciled = Math
204
				.abs(totalSchemeInWalletCredited - (schemeInAmountAdded - schemeInAmountRolledBack)) < 5;
24810 amit.gupta 205
 
24826 amit.gupta 206
		return Arrays.asList(reconciled, totalSchemeInWalletCredited, schemeInAmountAdded, schemeInAmountRolledBack,
207
				"");
24810 amit.gupta 208
 
24783 amit.gupta 209
	}
210
 
24826 amit.gupta 211
	private List<? extends Serializable> reconcileSchemeOutAndWallet(int fofoId, LocalDate localDate,
212
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
213
		int totalSchemeOutWalletCredited = 0;
214
		float schemeOutAmountAdded = 0;
215
		float schemeOutAmountRolledBack = 0;
216
		for (int fofoOrderId : transactionsOnThatDate.keySet()) {
217
			Set<Integer> fofoOrderItemIds = fofoOrderItemRepository.selectByOrderId(fofoOrderId).stream()
218
					.map(x -> x.getId()).collect(Collectors.toSet());
219
			List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
220
			Set<Integer> inventoryItemIds = fofoLineItems.stream().map(x -> x.getInventoryItemId())
221
					.collect(Collectors.toSet());
222
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
223
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
224
			totalSchemeOutWalletCredited += transactionsOnThatDate.get(fofoOrderId);
225
			for (SchemeInOut sio : sios) {
226
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
227
					schemeOutAmountAdded += sio.getAmount();
228
				}
24829 amit.gupta 229
				if (sio.getRolledBackTimestamp() != null
230
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 231
					schemeOutAmountRolledBack += sio.getAmount();
232
				}
233
			}
234
		}
235
		boolean reconciled = Math
236
				.abs(totalSchemeOutWalletCredited - (schemeOutAmountAdded - schemeOutAmountRolledBack)) < 5;
237
		return Arrays.asList(reconciled, totalSchemeOutWalletCredited, schemeOutAmountAdded, schemeOutAmountRolledBack,
238
				"");
24783 amit.gupta 239
	}
240
}