Subversion Repositories SmartDukaan

Rev

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