Subversion Repositories SmartDukaan

Rev

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