Subversion Repositories SmartDukaan

Rev

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