Subversion Repositories SmartDukaan

Rev

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