Subversion Repositories SmartDukaan

Rev

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