Subversion Repositories SmartDukaan

Rev

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