| Line 4... |
Line 4... |
| 4 |
import com.spice.profitmandi.common.model.ProfitMandiConstants;
|
4 |
import com.spice.profitmandi.common.model.ProfitMandiConstants;
|
| 5 |
import com.spice.profitmandi.common.model.UserInfo;
|
5 |
import com.spice.profitmandi.common.model.UserInfo;
|
| 6 |
import com.spice.profitmandi.dao.cart.CartService;
|
6 |
import com.spice.profitmandi.dao.cart.CartService;
|
| 7 |
import com.spice.profitmandi.dao.cart.v2.CartValidationService;
|
7 |
import com.spice.profitmandi.dao.cart.v2.CartValidationService;
|
| 8 |
import com.spice.profitmandi.dao.cart.v2.CheckoutValidationResult;
|
8 |
import com.spice.profitmandi.dao.cart.v2.CheckoutValidationResult;
|
| - |
|
9 |
import com.spice.profitmandi.dao.cart.v2.HydratedCart;
|
| - |
|
10 |
import com.spice.profitmandi.dao.cart.v2.HydratedLine;
|
| - |
|
11 |
import com.spice.profitmandi.dao.cart.v2.LineStatus;
|
| 9 |
import com.spice.profitmandi.dao.cart.v2.OpenCartValidationResult;
|
12 |
import com.spice.profitmandi.dao.cart.v2.OpenCartValidationResult;
|
| - |
|
13 |
import com.spice.profitmandi.dao.cart.v2.PricingBreakup;
|
| 10 |
import com.spice.profitmandi.dao.cart.v2.SaleType;
|
14 |
import com.spice.profitmandi.dao.cart.v2.SaleType;
|
| 11 |
import com.spice.profitmandi.dao.entity.catalog.Item;
|
15 |
import com.spice.profitmandi.dao.entity.catalog.Item;
|
| 12 |
import com.spice.profitmandi.dao.entity.catalog.TagListing;
|
16 |
import com.spice.profitmandi.dao.entity.catalog.TagListing;
|
| 13 |
import com.spice.profitmandi.dao.entity.fofo.PartnerType;
|
17 |
import com.spice.profitmandi.dao.entity.fofo.PartnerType;
|
| 14 |
import com.spice.profitmandi.dao.entity.user.CartLine;
|
18 |
import com.spice.profitmandi.dao.entity.user.CartLine;
|
| Line 29... |
Line 33... |
| 29 |
import org.springframework.http.ResponseEntity;
|
33 |
import org.springframework.http.ResponseEntity;
|
| 30 |
import org.springframework.ui.Model;
|
34 |
import org.springframework.ui.Model;
|
| 31 |
import org.springframework.web.bind.annotation.*;
|
35 |
import org.springframework.web.bind.annotation.*;
|
| 32 |
|
36 |
|
| 33 |
import javax.servlet.http.HttpServletRequest;
|
37 |
import javax.servlet.http.HttpServletRequest;
|
| - |
|
38 |
import java.math.BigDecimal;
|
| - |
|
39 |
import java.math.RoundingMode;
|
| 34 |
import java.time.LocalDate;
|
40 |
import java.time.LocalDate;
|
| 35 |
import java.util.ArrayList;
|
41 |
import java.util.ArrayList;
|
| 36 |
import java.util.Arrays;
|
42 |
import java.util.Arrays;
|
| 37 |
import java.util.HashSet;
|
43 |
import java.util.HashSet;
|
| 38 |
import java.util.List;
|
44 |
import java.util.List;
|
| Line 143... |
Line 149... |
| 143 |
public ResponseEntity<?> openCart(HttpServletRequest request)
|
149 |
public ResponseEntity<?> openCart(HttpServletRequest request)
|
| 144 |
throws ProfitMandiBusinessException {
|
150 |
throws ProfitMandiBusinessException {
|
| 145 |
java.util.Optional<AuthCtx> auth = resolveAuth(request);
|
151 |
java.util.Optional<AuthCtx> auth = resolveAuth(request);
|
| 146 |
if (!auth.isPresent()) return unauthorized();
|
152 |
if (!auth.isPresent()) return unauthorized();
|
| 147 |
AuthCtx ctx = auth.get();
|
153 |
AuthCtx ctx = auth.get();
|
| 148 |
OpenCartValidationResult result = cartValidationService.validateForOpen(
|
154 |
OpenCartValidationResult result = validateAndApplyCarryBagPrice(
|
| 149 |
ctx.cartId, ctx.storeId);
|
155 |
ctx.cartId, ctx.storeId);
|
| 150 |
return ResponseEntity.ok(ApiResponse.success(result));
|
156 |
return ResponseEntity.ok(ApiResponse.success(result));
|
| 151 |
}
|
157 |
}
|
| 152 |
|
158 |
|
| 153 |
/** STEP 2 — hard validation immediately before payment. Returns
|
159 |
/** STEP 2 — hard validation immediately before payment. Returns
|
| Line 232... |
Line 238... |
| 232 |
// Skip carry bag rebalance if user explicitly changed carry bag qty
|
238 |
// Skip carry bag rebalance if user explicitly changed carry bag qty
|
| 233 |
if (productId == ProfitMandiConstants.ITEM_CARRY_BAG) {
|
239 |
if (productId == ProfitMandiConstants.ITEM_CARRY_BAG) {
|
| 234 |
enrichPrices(ctx, desired);
|
240 |
enrichPrices(ctx, desired);
|
| 235 |
cartService.addItemsToCart(ctx.cartId, desired);
|
241 |
cartService.addItemsToCart(ctx.cartId, desired);
|
| 236 |
return ResponseEntity.ok(ApiResponse.success(
|
242 |
return ResponseEntity.ok(ApiResponse.success(
|
| 237 |
cartValidationService.validateForOpen(ctx.cartId, ctx.storeId)));
|
243 |
validateAndApplyCarryBagPrice(ctx.cartId, ctx.storeId)));
|
| 238 |
}
|
244 |
}
|
| 239 |
return applyAndHydrate(ctx, desired);
|
245 |
return applyAndHydrate(ctx, desired);
|
| 240 |
}
|
246 |
}
|
| 241 |
|
247 |
|
| 242 |
/** Remove a single line by productId. */
|
248 |
/** Remove a single line by productId. */
|
| Line 253... |
Line 259... |
| 253 |
// Skip carry bag rebalance if user explicitly removed the carry bag
|
259 |
// Skip carry bag rebalance if user explicitly removed the carry bag
|
| 254 |
if (productId == ProfitMandiConstants.ITEM_CARRY_BAG) {
|
260 |
if (productId == ProfitMandiConstants.ITEM_CARRY_BAG) {
|
| 255 |
enrichPrices(ctx, desired);
|
261 |
enrichPrices(ctx, desired);
|
| 256 |
cartService.addItemsToCart(ctx.cartId, desired);
|
262 |
cartService.addItemsToCart(ctx.cartId, desired);
|
| 257 |
return ResponseEntity.ok(ApiResponse.success(
|
263 |
return ResponseEntity.ok(ApiResponse.success(
|
| 258 |
cartValidationService.validateForOpen(ctx.cartId, ctx.storeId)));
|
264 |
validateAndApplyCarryBagPrice(ctx.cartId, ctx.storeId)));
|
| 259 |
}
|
265 |
}
|
| 260 |
return applyAndHydrate(ctx, desired);
|
266 |
return applyAndHydrate(ctx, desired);
|
| 261 |
}
|
267 |
}
|
| 262 |
|
268 |
|
| 263 |
/** Clear the entire cart. */
|
269 |
/** Clear the entire cart. */
|
| Line 267... |
Line 273... |
| 267 |
java.util.Optional<AuthCtx> auth = resolveAuth(request);
|
273 |
java.util.Optional<AuthCtx> auth = resolveAuth(request);
|
| 268 |
if (!auth.isPresent()) return unauthorized();
|
274 |
if (!auth.isPresent()) return unauthorized();
|
| 269 |
AuthCtx ctx = auth.get();
|
275 |
AuthCtx ctx = auth.get();
|
| 270 |
cartService.clearCart(ctx.cartId);
|
276 |
cartService.clearCart(ctx.cartId);
|
| 271 |
return ResponseEntity.ok(ApiResponse.success(
|
277 |
return ResponseEntity.ok(ApiResponse.success(
|
| 272 |
cartValidationService.validateForOpen(ctx.cartId, ctx.storeId)));
|
278 |
validateAndApplyCarryBagPrice(ctx.cartId, ctx.storeId)));
|
| 273 |
}
|
279 |
}
|
| 274 |
|
280 |
|
| 275 |
/**
|
281 |
/**
|
| 276 |
* Enriches each desired CartItem with the live selling price, runs the
|
282 |
* Enriches each desired CartItem with the live selling price, runs the
|
| 277 |
* procurement carry-bag rebalance, applies the change, then returns a
|
283 |
* procurement carry-bag rebalance, applies the change, then returns a
|
| Line 282... |
Line 288... |
| 282 |
throws ProfitMandiBusinessException {
|
288 |
throws ProfitMandiBusinessException {
|
| 283 |
enrichPrices(ctx, desired);
|
289 |
enrichPrices(ctx, desired);
|
| 284 |
rebalanceCarryBag(desired, ctx.storeId);
|
290 |
rebalanceCarryBag(desired, ctx.storeId);
|
| 285 |
cartService.addItemsToCart(ctx.cartId, desired);
|
291 |
cartService.addItemsToCart(ctx.cartId, desired);
|
| 286 |
return ResponseEntity.ok(ApiResponse.success(
|
292 |
return ResponseEntity.ok(ApiResponse.success(
|
| 287 |
cartValidationService.validateForOpen(ctx.cartId, ctx.storeId)));
|
293 |
validateAndApplyCarryBagPrice(ctx.cartId, ctx.storeId)));
|
| 288 |
}
|
294 |
}
|
| 289 |
|
295 |
|
| 290 |
/**
|
296 |
/**
|
| 291 |
* Populates {@link CartItem#setSellingPrice(double)} for each non-carry-bag item
|
297 |
* Populates {@link CartItem#setSellingPrice(double)} for each non-carry-bag item
|
| 292 |
* with the live (MOP - scheme cashback) figure. Preserves the existing value on
|
298 |
* with the live (MOP - scheme cashback) figure. Preserves the existing value on
|
| Line 343... |
Line 349... |
| 343 |
bag.setSellingPrice(resolveCarryBagPrice(fofoId));
|
349 |
bag.setSellingPrice(resolveCarryBagPrice(fofoId));
|
| 344 |
desired.add(bag);
|
350 |
desired.add(bag);
|
| 345 |
}
|
351 |
}
|
| 346 |
}
|
352 |
}
|
| 347 |
|
353 |
|
| - |
|
354 |
/**
|
| - |
|
355 |
* Wraps {@link CartValidationService#validateForOpen} and overrides the
|
| - |
|
356 |
* carry-bag line's LivePrice + rolls up totals using the tier logic that
|
| - |
|
357 |
* v1's {@code CartServiceImpl.getCartValidation} already applies (lines
|
| - |
|
358 |
* 271-278). Needed because the shared v2 hydrator prices every line from
|
| - |
|
359 |
* {@code TagListing.getMop()} without a tier check, so premium partners
|
| - |
|
360 |
* would otherwise see MRP (₹15) instead of ₹1.
|
| - |
|
361 |
*/
|
| - |
|
362 |
private OpenCartValidationResult validateAndApplyCarryBagPrice(int cartId, int fofoId)
|
| - |
|
363 |
throws ProfitMandiBusinessException {
|
| - |
|
364 |
OpenCartValidationResult result = cartValidationService.validateForOpen(cartId, fofoId);
|
| - |
|
365 |
if (result == null || result.getCart() == null || result.getCart().getLines() == null) {
|
| - |
|
366 |
return result;
|
| - |
|
367 |
}
|
| - |
|
368 |
HydratedCart cart = result.getCart();
|
| - |
|
369 |
BigDecimal tierPrice = BigDecimal.valueOf(resolveCarryBagPrice(fofoId))
|
| - |
|
370 |
.setScale(2, RoundingMode.HALF_UP);
|
| - |
|
371 |
boolean overridden = false;
|
| - |
|
372 |
for (HydratedLine line : cart.getLines()) {
|
| - |
|
373 |
if (line.getProductId() != ProfitMandiConstants.ITEM_CARRY_BAG) continue;
|
| - |
|
374 |
if (line.getPrice() == null) continue;
|
| - |
|
375 |
if (line.getPrice().getSelling() == null
|
| - |
|
376 |
|| line.getPrice().getSelling().compareTo(tierPrice) != 0) {
|
| - |
|
377 |
line.getPrice().setMrp(tierPrice);
|
| - |
|
378 |
line.getPrice().setSelling(tierPrice);
|
| - |
|
379 |
line.getPrice().setSchemeCashback(BigDecimal.ZERO);
|
| - |
|
380 |
overridden = true;
|
| - |
|
381 |
}
|
| - |
|
382 |
}
|
| - |
|
383 |
if (overridden && cart.getPricing() != null) {
|
| - |
|
384 |
// Mirrors CartHydrationServiceImpl.computePricing so grand total
|
| - |
|
385 |
// reflects the overridden carry-bag price.
|
| - |
|
386 |
BigDecimal subtotal = BigDecimal.ZERO;
|
| - |
|
387 |
BigDecimal discounts = BigDecimal.ZERO;
|
| - |
|
388 |
BigDecimal insuranceTotal = BigDecimal.ZERO;
|
| - |
|
389 |
for (HydratedLine line : cart.getLines()) {
|
| - |
|
390 |
if (line.getStatus() != LineStatus.ACTIVE || line.getPrice() == null) continue;
|
| - |
|
391 |
BigDecimal qty = BigDecimal.valueOf(line.getQuantity());
|
| - |
|
392 |
subtotal = subtotal.add(line.getPrice().getMrp().multiply(qty));
|
| - |
|
393 |
BigDecimal cashback = line.getPrice().getSchemeCashback() == null
|
| - |
|
394 |
? BigDecimal.ZERO : line.getPrice().getSchemeCashback();
|
| - |
|
395 |
discounts = discounts.add(cashback.multiply(qty));
|
| - |
|
396 |
if (line.getInsurance() != null && line.getInsurance().getPremium() != null) {
|
| - |
|
397 |
insuranceTotal = insuranceTotal.add(line.getInsurance().getPremium());
|
| - |
|
398 |
}
|
| - |
|
399 |
}
|
| - |
|
400 |
PricingBreakup p = cart.getPricing();
|
| - |
|
401 |
p.setSubtotal(subtotal);
|
| - |
|
402 |
p.setLineDiscounts(discounts);
|
| - |
|
403 |
p.setTaxableBase(subtotal.subtract(discounts));
|
| - |
|
404 |
p.setGrandTotal(p.getTaxableBase().add(insuranceTotal));
|
| - |
|
405 |
}
|
| - |
|
406 |
return result;
|
| - |
|
407 |
}
|
| - |
|
408 |
|
| 348 |
private float resolveCarryBagPrice(int fofoId) {
|
409 |
private float resolveCarryBagPrice(int fofoId) {
|
| 349 |
PartnerType tier = null;
|
410 |
PartnerType tier = null;
|
| 350 |
try {
|
411 |
try {
|
| 351 |
tier = partnerTypeChangeService.getTypeOnDate(fofoId, LocalDate.now());
|
412 |
tier = partnerTypeChangeService.getTypeOnDate(fofoId, LocalDate.now());
|
| 352 |
} catch (Exception e) {
|
413 |
} catch (Exception e) {
|