Subversion Repositories SmartDukaan

Rev

Rev 24830 | Rev 24870 | 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()));
24831 amit.gupta 88
			Arrays.asList(WalletReferenceType.PURCHASE, WalletReferenceType.SCHEME_IN, WalletReferenceType.SCHEME_OUT)
89
					.forEach(x -> {
90
						if (!referenceWiseWalletHistory.containsKey(x)) {
24830 amit.gupta 91
							referenceWiseWalletHistory.put(x, new ArrayList<>());
92
						}
93
					});
24810 amit.gupta 94
 
24831 amit.gupta 95
			List<Serializable> reconciliation = new ArrayList<>();
96
			LocalDate dateToReconcile = yesterday;
97
			reconciliation.addAll(Arrays.asList(partnerId, retailerNameMap.get(partnerId), dateToReconcile));
98
 
24810 amit.gupta 99
			for (Map.Entry<WalletReferenceType, List<UserWalletHistory>> entry : referenceWiseWalletHistory
100
					.entrySet()) {
24783 amit.gupta 101
				List<UserWalletHistory> history = entry.getValue();
24810 amit.gupta 102
				Map<Integer, Integer> referenceWalletMap = entry.getValue().stream().collect(
103
						Collectors.groupingBy(x -> x.getReference(), Collectors.summingInt(x -> x.getAmount())));
104
				switch (entry.getKey()) {
105
				case PURCHASE:
106
					reconciliation.addAll(
107
							reconcileOrdersAndWallet(uw.getUserId(), dateToReconcile, referenceWalletMap, history));
108
					break;
109
				case SCHEME_IN:
110
					reconciliation.addAll(reconcileSchemeInAndWallet(uw.getUserId(), dateToReconcile,
111
							referenceWalletMap, history, schemeTypeMap.get(SchemeType.IN)));
112
					break;
113
				case SCHEME_OUT:
24826 amit.gupta 114
					reconciliation.addAll(reconcileSchemeOutAndWallet(uw.getUserId(), dateToReconcile,
115
							referenceWalletMap, history, schemeTypeMap.get(SchemeType.OUT)));
24810 amit.gupta 116
					break;
117
				default:
118
					break;
119
 
120
				}
24783 amit.gupta 121
			}
24831 amit.gupta 122
			reconciled = reconciled || Boolean.TRUE.equals(reconciliation.get(0));
123
			rows.add(reconciliation);
24783 amit.gupta 124
		}
24826 amit.gupta 125
		ByteArrayOutputStream baos = FileUtil.getCSVByteStream(Arrays.asList("PartnerId", "Store Name",
126
				"Reconciliation Date", "Purchase Reconciled", "Wallet amount consumed", "Ordered Total",
127
				"Cancelled Total", "Refunded Total", "", "Scheme In to Wallet", "Scheme In disbursed",
128
				"Scheme In rolledback", "Scheme Out to Wallet", "Scheme Out Disbursed", "Scheme Out Rolledback"), rows);
24783 amit.gupta 129
 
24810 amit.gupta 130
		Utils.sendMailWithAttachment(mailSender, new String[] { "amit.gupta@shop2020.in" }, new String[] {},
131
				reconciled ? "Reconciled Successfully" : "Reconciliation failed", "Report attached",
132
				String.format("reconciliation-%s.csv", FormattingUtils.formatDate(yesterday.atStartOfDay())),
133
				new ByteArrayResource(baos.toByteArray()));
24783 amit.gupta 134
	}
135
 
24810 amit.gupta 136
	private List<? extends Serializable> reconcileOrdersAndWallet(int fofoId, LocalDate localDate,
137
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history) throws Exception {
24783 amit.gupta 138
 
139
		int totalWalletConsumed = 0;
140
		float cancelledAmount = 0;
141
		float returnedAmount = 0;
142
		float totalDeductedAmount = 0;
143
		for (int transactionId : transactionsOnThatDate.keySet()) {
144
			List<Order> orders = orderRepository.selectAllByTransactionId(transactionId);
145
			for (Order o : orders) {
146
				if (o.getCreateTimestamp().toLocalDate().equals(localDate)) {
147
					if (Arrays.asList(OrderStatus.PAYMENT_PENDING, OrderStatus.PAYMENT_FAILED)
148
							.contains(o.getStatus())) {
149
						cancelledAmount += o.getWalletAmount();
150
					} else if (o.getRefundTimestamp() != null
151
							&& o.getRefundTimestamp().toLocalDate().equals(localDate)) {
152
						ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
153
						if (returnedOrder == null) {
154
							cancelledAmount += o.getWalletAmount();
155
						} else {
156
							returnedAmount += returnedOrder.getTotalPrice();
157
						}
158
					}
159
					totalDeductedAmount += o.getWalletAmount();
160
 
161
				} else if (o.getRefundTimestamp() != null && o.getRefundTimestamp().toLocalDate().equals(localDate)) {
162
					ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
163
					if (returnedOrder == null) {
164
						cancelledAmount += o.getWalletAmount();
165
					} else {
166
						returnedAmount += returnedOrder.getTotalPrice();
167
					}
168
				}
169
			}
170
			totalWalletConsumed -= transactionsOnThatDate.get(transactionId);
24810 amit.gupta 171
 
24783 amit.gupta 172
		}
24810 amit.gupta 173
		boolean reconciled = Math
174
				.abs(totalWalletConsumed - (totalDeductedAmount - cancelledAmount - returnedAmount)) < 2;
24783 amit.gupta 175
 
24826 amit.gupta 176
		return Arrays.asList(reconciled, totalWalletConsumed, totalDeductedAmount, cancelledAmount, returnedAmount, "");
24783 amit.gupta 177
 
178
	}
179
 
24810 amit.gupta 180
	private List<? extends Serializable> reconcileSchemeInAndWallet(int fofoId, LocalDate localDate,
181
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
24783 amit.gupta 182
 
24810 amit.gupta 183
		int totalSchemeInWalletCredited = 0;
184
		float schemeInAmountAdded = 0;
185
		float schemeInAmountRolledBack = 0;
186
		for (int transactionId : transactionsOnThatDate.keySet()) {
187
			List<InventoryItem> inventoryItems = inventoryRepository.selectByPurchaseId(transactionId).stream()
188
					.filter(x -> x.getSerialNumber() != null).collect(Collectors.toList());
189
			Set<Integer> inventoryItemIds = inventoryItems.stream().map(x -> x.getId()).collect(Collectors.toSet());
190
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
191
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
192
			totalSchemeInWalletCredited += transactionsOnThatDate.get(transactionId);
193
			for (SchemeInOut sio : sios) {
194
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
195
					schemeInAmountAdded += sio.getAmount();
196
				}
24829 amit.gupta 197
				if (sio.getRolledBackTimestamp() != null
198
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 199
					schemeInAmountRolledBack += sio.getAmount();
24810 amit.gupta 200
				}
201
			}
202
 
203
		}
24826 amit.gupta 204
		boolean reconciled = Math
205
				.abs(totalSchemeInWalletCredited - (schemeInAmountAdded - schemeInAmountRolledBack)) < 5;
24810 amit.gupta 206
 
24826 amit.gupta 207
		return Arrays.asList(reconciled, totalSchemeInWalletCredited, schemeInAmountAdded, schemeInAmountRolledBack,
208
				"");
24810 amit.gupta 209
 
24783 amit.gupta 210
	}
211
 
24826 amit.gupta 212
	private List<? extends Serializable> reconcileSchemeOutAndWallet(int fofoId, LocalDate localDate,
213
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
214
		int totalSchemeOutWalletCredited = 0;
215
		float schemeOutAmountAdded = 0;
216
		float schemeOutAmountRolledBack = 0;
217
		for (int fofoOrderId : transactionsOnThatDate.keySet()) {
218
			Set<Integer> fofoOrderItemIds = fofoOrderItemRepository.selectByOrderId(fofoOrderId).stream()
219
					.map(x -> x.getId()).collect(Collectors.toSet());
220
			List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
221
			Set<Integer> inventoryItemIds = fofoLineItems.stream().map(x -> x.getInventoryItemId())
222
					.collect(Collectors.toSet());
223
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
224
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
225
			totalSchemeOutWalletCredited += transactionsOnThatDate.get(fofoOrderId);
226
			for (SchemeInOut sio : sios) {
227
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
228
					schemeOutAmountAdded += sio.getAmount();
229
				}
24829 amit.gupta 230
				if (sio.getRolledBackTimestamp() != null
231
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 232
					schemeOutAmountRolledBack += sio.getAmount();
233
				}
234
			}
235
		}
236
		boolean reconciled = Math
237
				.abs(totalSchemeOutWalletCredited - (schemeOutAmountAdded - schemeOutAmountRolledBack)) < 5;
238
		return Arrays.asList(reconciled, totalSchemeOutWalletCredited, schemeOutAmountAdded, schemeOutAmountRolledBack,
239
				"");
24783 amit.gupta 240
	}
241
}