| Line 25... |
Line 25... |
| 25 |
import com.spice.profitmandi.dao.enumuration.transaction.TransactionApprovalStatus;
|
25 |
import com.spice.profitmandi.dao.enumuration.transaction.TransactionApprovalStatus;
|
| 26 |
import com.spice.profitmandi.dao.model.CartItem;
|
26 |
import com.spice.profitmandi.dao.model.CartItem;
|
| 27 |
import com.spice.profitmandi.dao.model.UserCart;
|
27 |
import com.spice.profitmandi.dao.model.UserCart;
|
| 28 |
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
|
28 |
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
|
| 29 |
import com.spice.profitmandi.dao.repository.catalog.BidRepository;
|
29 |
import com.spice.profitmandi.dao.repository.catalog.BidRepository;
|
| - |
|
30 |
import com.spice.profitmandi.dao.entity.catalog.Category;
|
| - |
|
31 |
import com.spice.profitmandi.dao.entity.user.CartLine;
|
| - |
|
32 |
import com.spice.profitmandi.dao.repository.catalog.CategoryRepository;
|
| 30 |
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
|
33 |
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
|
| - |
|
34 |
import com.spice.profitmandi.dao.repository.user.CartLineRepository;
|
| 31 |
import com.spice.profitmandi.dao.repository.catalog.LiquidationRepository;
|
35 |
import com.spice.profitmandi.dao.repository.catalog.LiquidationRepository;
|
| 32 |
import com.spice.profitmandi.dao.repository.catalog.TagListingRepository;
|
36 |
import com.spice.profitmandi.dao.repository.catalog.TagListingRepository;
|
| 33 |
import com.spice.profitmandi.dao.repository.cs.CsService;
|
37 |
import com.spice.profitmandi.dao.repository.cs.CsService;
|
| 34 |
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
|
38 |
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
|
| 35 |
import com.spice.profitmandi.dao.repository.dtr.UserRepository;
|
39 |
import com.spice.profitmandi.dao.repository.dtr.UserRepository;
|
| Line 101... |
Line 105... |
| 101 |
@Autowired
|
105 |
@Autowired
|
| 102 |
private BidService bidService;
|
106 |
private BidService bidService;
|
| 103 |
@Autowired
|
107 |
@Autowired
|
| 104 |
ItemRepository itemRepository;
|
108 |
ItemRepository itemRepository;
|
| 105 |
@Autowired
|
109 |
@Autowired
|
| - |
|
110 |
CategoryRepository categoryRepository;
|
| - |
|
111 |
@Autowired
|
| - |
|
112 |
CartLineRepository cartLineRepository;
|
| - |
|
113 |
@Autowired
|
| 106 |
private BrandsService brandsService;
|
114 |
private BrandsService brandsService;
|
| 107 |
@Autowired
|
115 |
@Autowired
|
| 108 |
private LoanTransactionRepository loanTransactionRepository;
|
116 |
private LoanTransactionRepository loanTransactionRepository;
|
| 109 |
|
117 |
|
| 110 |
@Autowired
|
118 |
@Autowired
|
| Line 266... |
Line 274... |
| 266 |
if (enforceCombo) {
|
274 |
if (enforceCombo) {
|
| 267 |
comboService.validateCombo(userCart);
|
275 |
comboService.validateCombo(userCart);
|
| 268 |
}
|
276 |
}
|
| 269 |
// createtransactionInternally set the value in transaction table
|
277 |
// createtransactionInternally set the value in transaction table
|
| 270 |
|
278 |
|
| - |
|
279 |
// Refurbished (margin scheme) lines are invoiced on their own RF- series, so they must not share a
|
| - |
|
280 |
// transaction with regular lines - one billing group per invoice. Everything above (pricing, combo,
|
| - |
|
281 |
// credit availability) still validates the order as a whole; only the transaction is raised per group.
|
| - |
|
282 |
List<List<CartLine>> cartLineGroups = this.splitCartLinesByMarginScheme(userCart.getCartId());
|
| - |
|
283 |
// A loan settles against an invoice, so each group needs its own. Wallet is consumed in group order,
|
| - |
|
284 |
// so only what a group cannot fund from the balance left to it is borrowed.
|
| - |
|
285 |
List<Integer> groupLoanIds = new ArrayList<>();
|
| - |
|
286 |
double remainingWalletAmount = walletAmount;
|
| - |
|
287 |
for (List<CartLine> groupCartLines : cartLineGroups) {
|
| - |
|
288 |
double groupPayableAmount = this.getPayableAmount(groupCartLines);
|
| - |
|
289 |
double walletUsedByGroup = Math.min(remainingWalletAmount, groupPayableAmount);
|
| 271 |
double creditAmountRequired = totalPayableAmount - walletAmount;
|
290 |
double creditAmountRequired = groupPayableAmount - walletUsedByGroup;
|
| - |
|
291 |
remainingWalletAmount -= walletUsedByGroup;
|
| 272 |
int loanId = 0;
|
292 |
int loanId = 0;
|
| 273 |
try {
|
293 |
try {
|
| 274 |
if (creditAmountRequired > ProfitMandiConstants.MAX_NEGATIVE_WALLET_VALUE) {
|
294 |
if (creditAmountRequired > ProfitMandiConstants.MAX_NEGATIVE_WALLET_VALUE) {
|
| 275 |
LOGGER.info("Creating new loan for: {}",userCart.getUserId());
|
295 |
LOGGER.info("Creating new loan for: {}",userCart.getUserId());
|
| 276 |
BlockLoanIdSanctionId loan = sdCreditService.createSDDirectOrder(userCart.getUserId(), totalPayableAmount, 0);
|
296 |
BlockLoanIdSanctionId loan = sdCreditService.createSDDirectOrder(userCart.getUserId(), groupPayableAmount, 0);
|
| 277 |
loanId = loan.getLoanId();
|
297 |
loanId = loan.getLoanId();
|
| 278 |
}
|
298 |
}
|
| 279 |
} catch (Exception exception){
|
299 |
} catch (Exception exception){
|
| 280 |
if (type.equals(ProfitMandiConstants.PO_TYPE.AUTO)) {
|
300 |
if (type.equals(ProfitMandiConstants.PO_TYPE.AUTO)) {
|
| 281 |
finalBidStatus = bidService.sendMailToRBM(netAmountInHand, totalPayableAmount, fofoId);
|
301 |
finalBidStatus = bidService.sendMailToRBM(netAmountInHand, totalPayableAmount, fofoId);
|
| 282 |
LOGGER.info("Skipping order due to insufficient balance for id - "+ fofoId+ " Cancelling the BID");
|
302 |
LOGGER.info("Skipping order due to insufficient balance for id - "+ fofoId+ " Cancelling the BID");
|
| 283 |
//throw new ProfitMandiBusinessException("Skipping order unable to create load for id - ", fofoId, " ,Sending mail to RBM");
|
303 |
//throw new ProfitMandiBusinessException("Skipping order unable to create load for id - ", fofoId, " ,Sending mail to RBM");
|
| - |
|
304 |
}
|
| 284 |
}
|
305 |
}
|
| - |
|
306 |
groupLoanIds.add(loanId);
|
| 285 |
}
|
307 |
}
|
| 286 |
|
308 |
|
| 287 |
LOGGER.info("finalBidStatus: {}",finalBidStatus);
|
309 |
LOGGER.info("finalBidStatus: {}",finalBidStatus);
|
| 288 |
if (finalBidStatus.equals(ProfitMandiConstants.BID_ENUM.CLOSED)) {
|
310 |
if (finalBidStatus.equals(ProfitMandiConstants.BID_ENUM.CLOSED)) {
|
| 289 |
// Block all PO creation while a first PO is pending approval for this partner
|
311 |
// Block all PO creation while a first PO is pending approval for this partner
|
| Line 355... |
Line 377... |
| 355 |
|
377 |
|
| 356 |
}
|
378 |
}
|
| 357 |
}
|
379 |
}
|
| 358 |
}
|
380 |
}
|
| 359 |
|
381 |
|
| 360 |
LOGGER.info("totalPayableAmount - {}", totalPayableAmount);
|
- |
|
| 361 |
int transactionId = transactionService.createTransactionInternally(userCart, totalPayableAmount, 0);
|
- |
|
| 362 |
//Set here created by
|
- |
|
| 363 |
Transaction transaction = transactionRepository.selectById(transactionId);
|
- |
|
| 364 |
transaction.setCreatedBy(creatorId);
|
- |
|
| 365 |
LOGGER.info("transaction created by {}", transaction.getCreatedBy());
|
- |
|
| 366 |
commonPaymentService.payThroughWallet(transactionId);
|
- |
|
| 367 |
|
- |
|
| 368 |
// First PO always requires approval
|
382 |
// First PO always requires approval
|
| 369 |
if (isFirstPO) {
|
383 |
if (isFirstPO) {
|
| 370 |
approvalRequired = true;
|
384 |
approvalRequired = true;
|
| 371 |
}
|
385 |
}
|
| 372 |
|
386 |
|
| - |
|
387 |
for (int groupIndex = 0; groupIndex < cartLineGroups.size(); groupIndex++) {
|
| - |
|
388 |
List<CartLine> groupCartLines = cartLineGroups.get(groupIndex);
|
| - |
|
389 |
int loanId = groupLoanIds.get(groupIndex);
|
| - |
|
390 |
double groupPayableAmount = this.getPayableAmount(groupCartLines);
|
| - |
|
391 |
|
| - |
|
392 |
LOGGER.info("totalPayableAmount - {}", groupPayableAmount);
|
| - |
|
393 |
int transactionId = transactionService.createTransactionForCartLines(userCart, groupCartLines, groupPayableAmount, 0);
|
| - |
|
394 |
//Set here created by
|
| - |
|
395 |
Transaction transaction = transactionRepository.selectById(transactionId);
|
| - |
|
396 |
transaction.setCreatedBy(creatorId);
|
| - |
|
397 |
LOGGER.info("transaction created by {}", transaction.getCreatedBy());
|
| - |
|
398 |
commonPaymentService.payThroughWallet(transactionId);
|
| - |
|
399 |
|
| 373 |
if (approvalRequired) {
|
400 |
if (approvalRequired) {
|
| 374 |
this.createApproval(transactionId, isFirstPO);
|
401 |
this.createApproval(transactionId, isFirstPO);
|
| 375 |
if (loanId > 0) {
|
402 |
if (loanId > 0) {
|
| 376 |
LoanTransaction loanTransaction = new LoanTransaction();
|
403 |
LoanTransaction loanTransaction = new LoanTransaction();
|
| 377 |
loanTransaction.setLoanId(loanId);
|
404 |
loanTransaction.setLoanId(loanId);
|
| 378 |
loanTransaction.setTransactionId(transactionId);
|
405 |
loanTransaction.setTransactionId(transactionId);
|
| 379 |
loanTransactionRepository.persist(loanTransaction);
|
406 |
loanTransactionRepository.persist(loanTransaction);
|
| - |
|
407 |
}
|
| - |
|
408 |
} else {
|
| - |
|
409 |
transactionService.processTransaction(transactionId, loanId);
|
| 380 |
}
|
410 |
}
|
| 381 |
} else {
|
- |
|
| 382 |
transactionService.processTransaction(transactionId, loanId);
|
- |
|
| 383 |
}
|
- |
|
| 384 |
|
411 |
|
| 385 |
// Send approval email and track timeline for first PO
|
412 |
// Send approval email and track timeline for first PO
|
| 386 |
if (isFirstPO) {
|
413 |
if (isFirstPO) {
|
| 387 |
try {
|
414 |
try {
|
| 388 |
sendFirstPOApprovalEmail(fofoStore, transactionId, totalPayableAmount, creatorId);
|
415 |
sendFirstPOApprovalEmail(fofoStore, transactionId, groupPayableAmount, creatorId);
|
| 389 |
} catch (Exception e) {
|
416 |
} catch (Exception e) {
|
| 390 |
LOGGER.error("Failed to send first PO approval email for fofoId: " + fofoId, e);
|
417 |
LOGGER.error("Failed to send first PO approval email for fofoId: " + fofoId, e);
|
| 391 |
}
|
418 |
}
|
| 392 |
// Track PO_CREATION on timeline for first PO (direct call like BILLING — bypasses BLOCKER_MAP
|
419 |
// Track PO_CREATION on timeline for first PO (direct call like BILLING — bypasses BLOCKER_MAP
|
| 393 |
// since the PO is actually being created, the timeline must record it)
|
420 |
// since the PO is actually being created, the timeline must record it)
|
| 394 |
try {
|
421 |
try {
|
| 395 |
if (fofoStore != null && fofoStore.getCode() != null) {
|
422 |
if (fofoStore != null && fofoStore.getCode() != null) {
|
| 396 |
com.spice.profitmandi.dao.entity.fofo.PartnerOnBoardingPanel pob =
|
423 |
com.spice.profitmandi.dao.entity.fofo.PartnerOnBoardingPanel pob =
|
| 397 |
partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode());
|
424 |
partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode());
|
| 398 |
if (pob != null) {
|
425 |
if (pob != null) {
|
| 399 |
storeTimelineTatService.createStoreTimelinetb(pob.getId(), StoreTimeline.PO_CREATION);
|
426 |
storeTimelineTatService.createStoreTimelinetb(pob.getId(), StoreTimeline.PO_CREATION);
|
| - |
|
427 |
}
|
| 400 |
}
|
428 |
}
|
| - |
|
429 |
} catch (Exception e) {
|
| - |
|
430 |
LOGGER.error("Failed to track PO_CREATION timeline for fofoId: " + fofoId, e);
|
| 401 |
}
|
431 |
}
|
| 402 |
} catch (Exception e) {
|
- |
|
| 403 |
LOGGER.error("Failed to track PO_CREATION timeline for fofoId: " + fofoId, e);
|
- |
|
| 404 |
}
|
432 |
}
|
| 405 |
}
|
433 |
}
|
| 406 |
}
|
434 |
}
|
| 407 |
|
435 |
|
| 408 |
}
|
436 |
}
|
| Line 419... |
Line 447... |
| 419 |
LOGGER.warn("Combo-enforce gate: could not resolve positions for creator {} - {}", creatorId, e.getMessage());
|
447 |
LOGGER.warn("Combo-enforce gate: could not resolve positions for creator {} - {}", creatorId, e.getMessage());
|
| 420 |
return false;
|
448 |
return false;
|
| 421 |
}
|
449 |
}
|
| 422 |
}
|
450 |
}
|
| 423 |
|
451 |
|
| - |
|
452 |
/**
|
| - |
|
453 |
* Splits the cart into billing groups: regular lines and margin-scheme (refurbished) lines. Returns one
|
| - |
|
454 |
* group when the cart is homogeneous - which is the common case - so a single-kind bulk order behaves
|
| - |
|
455 |
* exactly as it did before. Lines whose item or category cannot be resolved stay with the regular group.
|
| - |
|
456 |
*/
|
| - |
|
457 |
private List<List<CartLine>> splitCartLinesByMarginScheme(int cartId) throws ProfitMandiBusinessException {
|
| - |
|
458 |
List<CartLine> cartLines = cartLineRepository.selectAllByCart(cartId);
|
| - |
|
459 |
Set<Integer> itemIds = cartLines.stream().map(CartLine::getItemId).collect(Collectors.toSet());
|
| - |
|
460 |
Map<Integer, Item> itemMap = itemRepository.selectByIds(itemIds).stream()
|
| - |
|
461 |
.collect(Collectors.toMap(Item::getId, x -> x));
|
| - |
|
462 |
List<Integer> categoryIds = itemMap.values().stream().map(Item::getCategoryId).distinct().collect(Collectors.toList());
|
| - |
|
463 |
Map<Integer, Category> categoryMap = categoryRepository.selectByIds(categoryIds).stream()
|
| - |
|
464 |
.collect(Collectors.toMap(Category::getId, x -> x));
|
| - |
|
465 |
|
| - |
|
466 |
List<CartLine> regularCartLines = new ArrayList<>();
|
| - |
|
467 |
List<CartLine> marginSchemeCartLines = new ArrayList<>();
|
| - |
|
468 |
for (CartLine cartLine : cartLines) {
|
| - |
|
469 |
Item item = itemMap.get(cartLine.getItemId());
|
| - |
|
470 |
Category category = (item == null) ? null : categoryMap.get(item.getCategoryId());
|
| - |
|
471 |
if (category != null && category.isMarginOnly()) {
|
| - |
|
472 |
marginSchemeCartLines.add(cartLine);
|
| - |
|
473 |
} else {
|
| - |
|
474 |
regularCartLines.add(cartLine);
|
| - |
|
475 |
}
|
| - |
|
476 |
}
|
| - |
|
477 |
|
| - |
|
478 |
List<List<CartLine>> cartLineGroups = new ArrayList<>();
|
| - |
|
479 |
if (!regularCartLines.isEmpty()) {
|
| - |
|
480 |
cartLineGroups.add(regularCartLines);
|
| - |
|
481 |
}
|
| - |
|
482 |
if (!marginSchemeCartLines.isEmpty()) {
|
| - |
|
483 |
cartLineGroups.add(marginSchemeCartLines);
|
| - |
|
484 |
}
|
| - |
|
485 |
return cartLineGroups;
|
| - |
|
486 |
}
|
| - |
|
487 |
|
| - |
|
488 |
/**
|
| - |
|
489 |
* Cart value of a billing group, matching the rule createTransactionForWarehouse validates against - the
|
| - |
|
490 |
* 0.01 carry bag is excluded - so the amount passed in always reconciles with the lines it is passed with.
|
| - |
|
491 |
*/
|
| - |
|
492 |
private double getPayableAmount(List<CartLine> cartLines) {
|
| - |
|
493 |
BigDecimal payableAmount = new BigDecimal(0);
|
| - |
|
494 |
for (CartLine cartLine : cartLines) {
|
| - |
|
495 |
if (cartLine.getItemId() == ProfitMandiConstants.ITEM_CARRY_BAG
|
| - |
|
496 |
&& Utils.compareDouble(cartLine.getActualPrice(), 0.01) == 0) {
|
| - |
|
497 |
continue;
|
| - |
|
498 |
}
|
| - |
|
499 |
payableAmount = payableAmount.add(BigDecimal.valueOf(cartLine.getActualPrice())
|
| - |
|
500 |
.multiply(BigDecimal.valueOf(cartLine.getQuantity())));
|
| - |
|
501 |
}
|
| - |
|
502 |
return payableAmount.doubleValue();
|
| - |
|
503 |
}
|
| - |
|
504 |
|
| 424 |
public void createApproval(int transactionId, boolean firstPo) {
|
505 |
public void createApproval(int transactionId, boolean firstPo) {
|
| 425 |
TransactionApproval transactionApproval = new TransactionApproval();
|
506 |
TransactionApproval transactionApproval = new TransactionApproval();
|
| 426 |
transactionApproval.setId(transactionId);
|
507 |
transactionApproval.setId(transactionId);
|
| 427 |
transactionApproval.setStatus(TransactionApprovalStatus.PENDING);
|
508 |
transactionApproval.setStatus(TransactionApprovalStatus.PENDING);
|
| 428 |
transactionApproval.setFirstPo(firstPo);
|
509 |
transactionApproval.setFirstPo(firstPo);
|