Subversion Repositories SmartDukaan

Rev

Rev 25072 | Rev 25075 | 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;
25072 amit.gupta 18
import org.springframework.transaction.annotation.Transactional;
24783 amit.gupta 19
 
25072 amit.gupta 20
import com.google.common.collect.Sets;
24783 amit.gupta 21
import com.spice.profitmandi.common.util.FileUtil;
22
import com.spice.profitmandi.common.util.FormattingUtils;
23
import com.spice.profitmandi.common.util.Utils;
24810 amit.gupta 24
import com.spice.profitmandi.dao.entity.catalog.Scheme;
24826 amit.gupta 25
import com.spice.profitmandi.dao.entity.fofo.FofoLineItem;
24810 amit.gupta 26
import com.spice.profitmandi.dao.entity.fofo.InventoryItem;
25072 amit.gupta 27
import com.spice.profitmandi.dao.entity.fofo.Purchase;
28
import com.spice.profitmandi.dao.entity.fofo.ScanRecord;
24810 amit.gupta 29
import com.spice.profitmandi.dao.entity.fofo.SchemeInOut;
24783 amit.gupta 30
import com.spice.profitmandi.dao.entity.transaction.Order;
31
import com.spice.profitmandi.dao.entity.transaction.ReturnOrder;
32
import com.spice.profitmandi.dao.entity.transaction.UserWallet;
33
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
24810 amit.gupta 34
import com.spice.profitmandi.dao.enumuration.catalog.SchemeType;
25072 amit.gupta 35
import com.spice.profitmandi.dao.enumuration.fofo.ScanType;
24810 amit.gupta 36
import com.spice.profitmandi.dao.repository.catalog.SchemeRepository;
24783 amit.gupta 37
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
24826 amit.gupta 38
import com.spice.profitmandi.dao.repository.fofo.FofoLineItemRepository;
39
import com.spice.profitmandi.dao.repository.fofo.FofoOrderItemRepository;
24810 amit.gupta 40
import com.spice.profitmandi.dao.repository.fofo.InventoryItemRepository;
25072 amit.gupta 41
import com.spice.profitmandi.dao.repository.fofo.PurchaseRepository;
42
import com.spice.profitmandi.dao.repository.fofo.ScanRecordRepository;
24810 amit.gupta 43
import com.spice.profitmandi.dao.repository.fofo.SchemeInOutRepository;
24783 amit.gupta 44
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
45
import com.spice.profitmandi.dao.repository.transaction.ReturnOrderRepository;
46
import com.spice.profitmandi.dao.repository.transaction.UserWalletHistoryRepository;
47
import com.spice.profitmandi.dao.repository.transaction.UserWalletRepository;
48
import com.spice.profitmandi.service.user.RetailerService;
49
 
50
import in.shop2020.model.v1.order.OrderStatus;
51
import in.shop2020.model.v1.order.WalletReferenceType;
52
 
53
@Component
25072 amit.gupta 54
@Transactional(rollbackFor = Throwable.class)
24783 amit.gupta 55
public class Reconciliation {
56
	@Autowired
57
	private FofoStoreRepository fofoStoreRepository;
25072 amit.gupta 58
 
24783 amit.gupta 59
	@Autowired
25072 amit.gupta 60
	private PurchaseRepository purchaseRepository;
61
 
62
	@Autowired
24826 amit.gupta 63
	private FofoOrderItemRepository fofoOrderItemRepository;
64
	@Autowired
65
	private FofoLineItemRepository fofoLineItemRepository;
66
	@Autowired
24783 amit.gupta 67
	private UserWalletRepository userWalletRepository;
25072 amit.gupta 68
 
24783 amit.gupta 69
	@Autowired
25072 amit.gupta 70
	private InventoryItemRepository inventoryItemRepository;
71
 
72
	@Autowired
73
	private ScanRecordRepository scanRecordRepository;
74
	@Autowired
24783 amit.gupta 75
	private UserWalletHistoryRepository userWalletHistoryRepository;
76
	@Autowired
24810 amit.gupta 77
	private SchemeInOutRepository schemeInOutRepository;
78
	@Autowired
79
	private SchemeRepository schemeRepository;
80
	@Autowired
81
	private InventoryItemRepository inventoryRepository;
82
	@Autowired
24783 amit.gupta 83
	private RetailerService retailerService;
84
	@Autowired
85
	private ReturnOrderRepository returnOrderRepository;
86
	@Autowired
87
	private OrderRepository orderRepository;
88
	@Autowired
89
	private JavaMailSender mailSender;
90
 
91
	public void dailyReconciliation() throws Exception {
24870 amit.gupta 92
		LocalDate date = LocalDate.now().minusDays(1);
93
		dailyReconciliation(date);
94
	}
25072 amit.gupta 95
 
24870 amit.gupta 96
	private void dailyReconciliation(LocalDate localDate) throws Exception {
24810 amit.gupta 97
		Map<SchemeType, Set<Integer>> schemeTypeMap = schemeRepository.selectAll().stream()
98
				.collect(Collectors.groupingBy(Scheme::getType, Collectors.mapping(Scheme::getId, Collectors.toSet())));
24783 amit.gupta 99
		boolean reconciled = true;
100
		Map<Integer, String> stores = fofoStoreRepository.getStoresMap();
24810 amit.gupta 101
		List<List<? extends Serializable>> rows = new ArrayList<>();
24783 amit.gupta 102
		LocalDate yesterday = LocalDate.now().minusDays(1);
103
		Map<Integer, String> retailerNameMap = retailerService
104
				.getAllFofoRetailerIdNameMap(new ArrayList<>(stores.keySet()));
105
		for (int partnerId : stores.keySet()) {
106
			UserWallet uw = userWalletRepository.selectByRetailerId(partnerId);
107
			List<UserWalletHistory> walletHistory = userWalletHistoryRepository.selectByWalletIdAndDate(uw.getId(),
108
					yesterday);
24810 amit.gupta 109
			Map<WalletReferenceType, List<UserWalletHistory>> referenceWiseWalletHistory = walletHistory.stream()
110
					.collect(Collectors.groupingBy(x -> x.getReferenceType(), Collectors.toList()));
24831 amit.gupta 111
			Arrays.asList(WalletReferenceType.PURCHASE, WalletReferenceType.SCHEME_IN, WalletReferenceType.SCHEME_OUT)
112
					.forEach(x -> {
113
						if (!referenceWiseWalletHistory.containsKey(x)) {
24830 amit.gupta 114
							referenceWiseWalletHistory.put(x, new ArrayList<>());
115
						}
116
					});
24810 amit.gupta 117
 
24831 amit.gupta 118
			List<Serializable> reconciliation = new ArrayList<>();
119
			LocalDate dateToReconcile = yesterday;
25072 amit.gupta 120
			// "PartnerId", "Partner Name", "Reconciliation Date"
24831 amit.gupta 121
			reconciliation.addAll(Arrays.asList(partnerId, retailerNameMap.get(partnerId), dateToReconcile));
122
 
24810 amit.gupta 123
			for (Map.Entry<WalletReferenceType, List<UserWalletHistory>> entry : referenceWiseWalletHistory
124
					.entrySet()) {
24783 amit.gupta 125
				List<UserWalletHistory> history = entry.getValue();
24810 amit.gupta 126
				Map<Integer, Integer> referenceWalletMap = entry.getValue().stream().collect(
127
						Collectors.groupingBy(x -> x.getReference(), Collectors.summingInt(x -> x.getAmount())));
128
				switch (entry.getKey()) {
129
				case PURCHASE:
25072 amit.gupta 130
					reconciliation.addAll(reconcileOrdersAndWallet(dateToReconcile, referenceWalletMap, history));
24810 amit.gupta 131
					break;
132
				case SCHEME_IN:
25072 amit.gupta 133
					reconciliation.addAll(reconcileSchemeInAndWallet(dateToReconcile, referenceWalletMap, history,
134
							schemeTypeMap.get(SchemeType.IN)));
24810 amit.gupta 135
					break;
136
				case SCHEME_OUT:
25072 amit.gupta 137
					reconciliation.addAll(reconcileSchemeOutAndWallet(dateToReconcile, referenceWalletMap, history,
138
							schemeTypeMap.get(SchemeType.OUT)));
24810 amit.gupta 139
					break;
140
				default:
141
					break;
142
 
143
				}
24783 amit.gupta 144
			}
24831 amit.gupta 145
			reconciled = reconciled || Boolean.TRUE.equals(reconciliation.get(0));
146
			rows.add(reconciliation);
24783 amit.gupta 147
		}
25072 amit.gupta 148
		ByteArrayOutputStream baos = FileUtil.getCSVByteStream(Arrays.asList("PartnerId", "Partner Name",
149
				"Reconciliation Date", "Purchase Reconciled", "Wallet amount consumed", "Ordered Total",
150
				"Cancelled Total", "Refunded Total", "Scheme In Reconciled", "Scheme In to Wallet",
151
				"Scheme In disbursed", "Scheme In rolledback", "SchemeOut Reconciled", "Scheme Out to Wallet",
152
				"Scheme Out Disbursed", "Scheme Out Rolledback"), rows);
24783 amit.gupta 153
 
25072 amit.gupta 154
		Utils.sendMailWithAttachment(mailSender,
155
				new String[] { "amit.gupta@shop2020.in", "neeraj.gupta@smartdukaan.com" }, new String[] {},
24810 amit.gupta 156
				reconciled ? "Reconciled Successfully" : "Reconciliation failed", "Report attached",
157
				String.format("reconciliation-%s.csv", FormattingUtils.formatDate(yesterday.atStartOfDay())),
158
				new ByteArrayResource(baos.toByteArray()));
24783 amit.gupta 159
	}
160
 
24870 amit.gupta 161
	private List<? extends Serializable> reconcileOrdersAndWallet(LocalDate localDate,
24810 amit.gupta 162
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history) throws Exception {
24783 amit.gupta 163
 
164
		int totalWalletConsumed = 0;
165
		float cancelledAmount = 0;
166
		float returnedAmount = 0;
167
		float totalDeductedAmount = 0;
168
		for (int transactionId : transactionsOnThatDate.keySet()) {
169
			List<Order> orders = orderRepository.selectAllByTransactionId(transactionId);
170
			for (Order o : orders) {
171
				if (o.getCreateTimestamp().toLocalDate().equals(localDate)) {
172
					if (Arrays.asList(OrderStatus.PAYMENT_PENDING, OrderStatus.PAYMENT_FAILED)
173
							.contains(o.getStatus())) {
174
						cancelledAmount += o.getWalletAmount();
175
					} else if (o.getRefundTimestamp() != null
176
							&& 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
					totalDeductedAmount += o.getWalletAmount();
185
 
186
				} else if (o.getRefundTimestamp() != null && o.getRefundTimestamp().toLocalDate().equals(localDate)) {
187
					ReturnOrder returnedOrder = returnOrderRepository.selectByOrderId(o.getId());
188
					if (returnedOrder == null) {
189
						cancelledAmount += o.getWalletAmount();
190
					} else {
191
						returnedAmount += returnedOrder.getTotalPrice();
192
					}
193
				}
194
			}
195
			totalWalletConsumed -= transactionsOnThatDate.get(transactionId);
24810 amit.gupta 196
 
24783 amit.gupta 197
		}
24810 amit.gupta 198
		boolean reconciled = Math
199
				.abs(totalWalletConsumed - (totalDeductedAmount - cancelledAmount - returnedAmount)) < 2;
24783 amit.gupta 200
 
24826 amit.gupta 201
		return Arrays.asList(reconciled, totalWalletConsumed, totalDeductedAmount, cancelledAmount, returnedAmount, "");
24783 amit.gupta 202
 
203
	}
204
 
24870 amit.gupta 205
	private List<? extends Serializable> reconcileSchemeInAndWallet(LocalDate localDate,
24810 amit.gupta 206
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
24783 amit.gupta 207
 
24810 amit.gupta 208
		int totalSchemeInWalletCredited = 0;
209
		float schemeInAmountAdded = 0;
210
		float schemeInAmountRolledBack = 0;
211
		for (int transactionId : transactionsOnThatDate.keySet()) {
212
			List<InventoryItem> inventoryItems = inventoryRepository.selectByPurchaseId(transactionId).stream()
213
					.filter(x -> x.getSerialNumber() != null).collect(Collectors.toList());
214
			Set<Integer> inventoryItemIds = inventoryItems.stream().map(x -> x.getId()).collect(Collectors.toSet());
215
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
216
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
217
			totalSchemeInWalletCredited += transactionsOnThatDate.get(transactionId);
218
			for (SchemeInOut sio : sios) {
219
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
220
					schemeInAmountAdded += sio.getAmount();
221
				}
24829 amit.gupta 222
				if (sio.getRolledBackTimestamp() != null
223
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 224
					schemeInAmountRolledBack += sio.getAmount();
24810 amit.gupta 225
				}
226
			}
227
 
228
		}
24826 amit.gupta 229
		boolean reconciled = Math
230
				.abs(totalSchemeInWalletCredited - (schemeInAmountAdded - schemeInAmountRolledBack)) < 5;
24810 amit.gupta 231
 
24826 amit.gupta 232
		return Arrays.asList(reconciled, totalSchemeInWalletCredited, schemeInAmountAdded, schemeInAmountRolledBack,
233
				"");
24810 amit.gupta 234
 
24783 amit.gupta 235
	}
236
 
24870 amit.gupta 237
	private List<? extends Serializable> reconcileSchemeOutAndWallet(LocalDate localDate,
24826 amit.gupta 238
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
239
		int totalSchemeOutWalletCredited = 0;
240
		float schemeOutAmountAdded = 0;
241
		float schemeOutAmountRolledBack = 0;
242
		for (int fofoOrderId : transactionsOnThatDate.keySet()) {
243
			Set<Integer> fofoOrderItemIds = fofoOrderItemRepository.selectByOrderId(fofoOrderId).stream()
244
					.map(x -> x.getId()).collect(Collectors.toSet());
245
			List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
246
			Set<Integer> inventoryItemIds = fofoLineItems.stream().map(x -> x.getInventoryItemId())
247
					.collect(Collectors.toSet());
248
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
249
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
250
			totalSchemeOutWalletCredited += transactionsOnThatDate.get(fofoOrderId);
251
			for (SchemeInOut sio : sios) {
252
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
253
					schemeOutAmountAdded += sio.getAmount();
254
				}
24829 amit.gupta 255
				if (sio.getRolledBackTimestamp() != null
256
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 257
					schemeOutAmountRolledBack += sio.getAmount();
258
				}
259
			}
260
		}
261
		boolean reconciled = Math
262
				.abs(totalSchemeOutWalletCredited - (schemeOutAmountAdded - schemeOutAmountRolledBack)) < 5;
263
		return Arrays.asList(reconciled, totalSchemeOutWalletCredited, schemeOutAmountAdded, schemeOutAmountRolledBack,
264
				"");
24783 amit.gupta 265
	}
25072 amit.gupta 266
 
267
	public void reconcileExpiredFixedSchemes() throws Exception {
268
		List<Scheme> allSchemes = schemeRepository.selectAll();
269
		// .stream().filter(x ->
270
		// x.getAmountType().equals(AmountType.FIXED)).collect(Collectors.toList());
271
 
272
		System.out.println("InventoryId\tSerialNumber\tItem Id\tScheme Id\tScheme Name\tScheme Type\tAmount Type\tScheme Amount\tAmount Paid\tReference\tTransaction Time");
273
		for (Scheme scheme : allSchemes) {
274
			if (scheme.getExpireTimestamp() != null) {
275
				if (scheme.getExpireTimestamp().isBefore(scheme.getEndDateTime())) {
276
					List<SchemeInOut> inOuts = schemeInOutRepository
277
							.selectBySchemeIds(Sets.newHashSet(scheme.getId()));
278
					if (scheme.getType().equals(SchemeType.IN)) {
279
						for (SchemeInOut schemeInOut : inOuts) {
280
							ScanRecord inRecord = scanRecordRepository
281
									.selectByInventoryItemId(schemeInOut.getInventoryItemId()).stream()
282
									.filter(x -> x.getType().equals(ScanType.PURCHASE)).collect(Collectors.toList())
283
									.get(0);
284
							if (inRecord.getCreateTimestamp().isAfter(scheme.getEndDateTime())) {
285
								InventoryItem ii = inventoryItemRepository.selectById(inRecord.getInventoryItemId());
286
								Purchase purchase = purchaseRepository.selectByIdAndFofoId(ii.getPurchaseId(), ii.getFofoId());
287
								purchase.getPurchaseReference();
288
								ii.getSerialNumber();
289
								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",
290
										ii.getId(), ii.getSerialNumber(), ii.getId(), schemeInOut.getSchemeId(), scheme.getName(), scheme.getType(),
291
										scheme.getAmount(), schemeInOut.getAmount(), purchase.getId(), inRecord.getCreateTimestamp()));
292
							}
293
 
294
						}
295
					}
296
					if (scheme.getType().equals(SchemeType.OUT)) {
297
						for (SchemeInOut schemeInOut : inOuts) {
298
							ScanRecord outRecord = scanRecordRepository
299
									.selectByInventoryItemId(schemeInOut.getInventoryItemId()).stream()
300
									.filter(x -> x.getType().equals(ScanType.SALE)).sorted((x1,x2)->x1.getId() - x2.getId()).collect(Collectors.toList()).get(0);
301
							if (outRecord.getCreateTimestamp().isAfter(scheme.getEndDateTime())) {
302
								InventoryItem ii = inventoryItemRepository.selectById(outRecord.getInventoryItemId());
25074 amit.gupta 303
								Order order;
304
								if(outRecord.getId()==0) {
305
									continue;
306
								} else {
307
									order = orderRepository.selectById(outRecord.getId());
308
								}
25072 amit.gupta 309
								order.getInvoiceNumber();
310
								ii.getSerialNumber();
311
								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",
312
										ii.getId(), ii.getSerialNumber(), ii.getId(), schemeInOut.getSchemeId(), scheme.getName(), scheme.getType(),
313
										scheme.getAmount(), schemeInOut.getAmount(), order.getId(), outRecord.getCreateTimestamp()));
314
 
315
							}
316
 
317
						}
318
					}
319
				}
320
			}
321
		}
322
 
323
	}
24783 amit.gupta 324
}