Subversion Repositories SmartDukaan

Rev

Rev 25082 | Rev 25299 | 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());
230
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
231
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
232
			totalSchemeInWalletCredited += transactionsOnThatDate.get(transactionId);
233
			for (SchemeInOut sio : sios) {
234
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
235
					schemeInAmountAdded += sio.getAmount();
236
				}
24829 amit.gupta 237
				if (sio.getRolledBackTimestamp() != null
238
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 239
					schemeInAmountRolledBack += sio.getAmount();
24810 amit.gupta 240
				}
241
			}
242
 
243
		}
24826 amit.gupta 244
		boolean reconciled = Math
245
				.abs(totalSchemeInWalletCredited - (schemeInAmountAdded - schemeInAmountRolledBack)) < 5;
24810 amit.gupta 246
 
24826 amit.gupta 247
		return Arrays.asList(reconciled, totalSchemeInWalletCredited, schemeInAmountAdded, schemeInAmountRolledBack,
248
				"");
24810 amit.gupta 249
 
24783 amit.gupta 250
	}
251
 
24870 amit.gupta 252
	private List<? extends Serializable> reconcileSchemeOutAndWallet(LocalDate localDate,
24826 amit.gupta 253
			Map<Integer, Integer> transactionsOnThatDate, List<UserWalletHistory> history, Set<Integer> schemeIds) {
254
		int totalSchemeOutWalletCredited = 0;
255
		float schemeOutAmountAdded = 0;
256
		float schemeOutAmountRolledBack = 0;
257
		for (int fofoOrderId : transactionsOnThatDate.keySet()) {
258
			Set<Integer> fofoOrderItemIds = fofoOrderItemRepository.selectByOrderId(fofoOrderId).stream()
259
					.map(x -> x.getId()).collect(Collectors.toSet());
260
			List<FofoLineItem> fofoLineItems = fofoLineItemRepository.selectByFofoOrderItemIds(fofoOrderItemIds);
261
			Set<Integer> inventoryItemIds = fofoLineItems.stream().map(x -> x.getInventoryItemId())
262
					.collect(Collectors.toSet());
263
			List<SchemeInOut> sios = schemeInOutRepository.selectByInventoryItemIds(new HashSet<>(inventoryItemIds))
264
					.stream().filter(x -> schemeIds.contains(x.getSchemeId())).collect(Collectors.toList());
265
			totalSchemeOutWalletCredited += transactionsOnThatDate.get(fofoOrderId);
266
			for (SchemeInOut sio : sios) {
267
				if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
268
					schemeOutAmountAdded += sio.getAmount();
269
				}
24829 amit.gupta 270
				if (sio.getRolledBackTimestamp() != null
271
						&& sio.getRolledBackTimestamp().toLocalDate().equals(localDate)) {
24826 amit.gupta 272
					schemeOutAmountRolledBack += sio.getAmount();
273
				}
274
			}
275
		}
276
		boolean reconciled = Math
277
				.abs(totalSchemeOutWalletCredited - (schemeOutAmountAdded - schemeOutAmountRolledBack)) < 5;
278
		return Arrays.asList(reconciled, totalSchemeOutWalletCredited, schemeOutAmountAdded, schemeOutAmountRolledBack,
279
				"");
24783 amit.gupta 280
	}
25072 amit.gupta 281
 
282
	public void reconcileExpiredFixedSchemes() throws Exception {
283
		List<Scheme> allSchemes = schemeRepository.selectAll();
284
		// .stream().filter(x ->
285
		// x.getAmountType().equals(AmountType.FIXED)).collect(Collectors.toList());
286
 
25082 amit.gupta 287
		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 288
		for (Scheme scheme : allSchemes) {
289
			if (scheme.getExpireTimestamp() != null) {
290
				if (scheme.getExpireTimestamp().isBefore(scheme.getEndDateTime())) {
291
					List<SchemeInOut> inOuts = schemeInOutRepository
292
							.selectBySchemeIds(Sets.newHashSet(scheme.getId()));
293
					if (scheme.getType().equals(SchemeType.IN)) {
294
						for (SchemeInOut schemeInOut : inOuts) {
295
							ScanRecord inRecord = scanRecordRepository
296
									.selectByInventoryItemId(schemeInOut.getInventoryItemId()).stream()
297
									.filter(x -> x.getType().equals(ScanType.PURCHASE)).collect(Collectors.toList())
298
									.get(0);
25078 amit.gupta 299
							if (inRecord.getCreateTimestamp().isAfter(scheme.getExpireTimestamp())) {
25072 amit.gupta 300
								InventoryItem ii = inventoryItemRepository.selectById(inRecord.getInventoryItemId());
301
								Purchase purchase = purchaseRepository.selectByIdAndFofoId(ii.getPurchaseId(), ii.getFofoId());
25082 amit.gupta 302
								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 303
										ii.getId(), ii.getSerialNumber(), ii.getItemId(), schemeInOut.getSchemeId(), scheme.getName(), scheme.getType(),
25082 amit.gupta 304
										scheme.getAmount(), schemeInOut.getAmount(), purchase.getId(), inRecord.getCreateTimestamp(), scheme.getStartDateTime(), scheme.getEndDateTime(), scheme.getExpireTimestamp()));
25072 amit.gupta 305
							}
306
 
307
						}
308
					}
309
					if (scheme.getType().equals(SchemeType.OUT)) {
310
						for (SchemeInOut schemeInOut : inOuts) {
311
							ScanRecord outRecord = scanRecordRepository
312
									.selectByInventoryItemId(schemeInOut.getInventoryItemId()).stream()
313
									.filter(x -> x.getType().equals(ScanType.SALE)).sorted((x1,x2)->x1.getId() - x2.getId()).collect(Collectors.toList()).get(0);
25078 amit.gupta 314
							if (outRecord.getCreateTimestamp().isAfter(scheme.getExpireTimestamp())) {
25072 amit.gupta 315
								InventoryItem ii = inventoryItemRepository.selectById(outRecord.getInventoryItemId());
25081 amit.gupta 316
								FofoOrder fofoOrder;
25075 amit.gupta 317
								if(outRecord.getOrderId()==0) {
25083 amit.gupta 318
									fofoOrder = orderService.getOrderByInventoryItemId(ii.getId());
25074 amit.gupta 319
								} else {
25081 amit.gupta 320
									fofoOrder = fofoOrderRepository.selectByOrderId(outRecord.getOrderId());
321
									if(fofoOrder==null) {
25077 amit.gupta 322
										LOGGER.info("Order id does not exits - {}", outRecord.getOrderId());
323
										continue;
25076 amit.gupta 324
									}
25074 amit.gupta 325
								}
25082 amit.gupta 326
								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 327
										ii.getId(), ii.getSerialNumber(), ii.getItemId(), schemeInOut.getSchemeId(), scheme.getName(), scheme.getType(),
25082 amit.gupta 328
										scheme.getAmount(), schemeInOut.getAmount(), fofoOrder.getId(), outRecord.getCreateTimestamp(), scheme.getStartDateTime(), scheme.getEndDateTime(), scheme.getExpireTimestamp()));
25072 amit.gupta 329
 
330
							}
331
 
332
						}
333
					}
334
				}
335
			}
336
		}
337
 
338
	}
24783 amit.gupta 339
}