Subversion Repositories SmartDukaan

Rev

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