added points to sale and logic backend
This commit is contained in:
@@ -5,6 +5,7 @@ import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class SaleRequest {
|
||||
@NotNull(message = "Store ID is required")
|
||||
@@ -28,6 +29,10 @@ public class SaleRequest {
|
||||
|
||||
private Long cartId;
|
||||
|
||||
private Integer pointsUsed;
|
||||
|
||||
private BigDecimal pointsDiscountAmount;
|
||||
|
||||
public Long getStoreId() {
|
||||
return storeId;
|
||||
}
|
||||
@@ -100,6 +105,22 @@ public class SaleRequest {
|
||||
this.cartId = cartId;
|
||||
}
|
||||
|
||||
public Integer getPointsUsed() {
|
||||
return pointsUsed;
|
||||
}
|
||||
|
||||
public void setPointsUsed(Integer pointsUsed) {
|
||||
this.pointsUsed = pointsUsed;
|
||||
}
|
||||
|
||||
public BigDecimal getPointsDiscountAmount() {
|
||||
return pointsDiscountAmount;
|
||||
}
|
||||
|
||||
public void setPointsDiscountAmount(BigDecimal pointsDiscountAmount) {
|
||||
this.pointsDiscountAmount = pointsDiscountAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -19,6 +19,8 @@ public class SaleResponse {
|
||||
private BigDecimal couponDiscountAmount;
|
||||
private BigDecimal employeeDiscountAmount;
|
||||
private Integer pointsEarned;
|
||||
private Integer pointsUsed;
|
||||
private BigDecimal pointsDiscountAmount;
|
||||
private String channel;
|
||||
private Long couponId;
|
||||
private Long cartId;
|
||||
@@ -135,6 +137,22 @@ public class SaleResponse {
|
||||
this.pointsEarned = pointsEarned;
|
||||
}
|
||||
|
||||
public Integer getPointsUsed() {
|
||||
return pointsUsed;
|
||||
}
|
||||
|
||||
public void setPointsUsed(Integer pointsUsed) {
|
||||
this.pointsUsed = pointsUsed;
|
||||
}
|
||||
|
||||
public BigDecimal getPointsDiscountAmount() {
|
||||
return pointsDiscountAmount;
|
||||
}
|
||||
|
||||
public void setPointsDiscountAmount(BigDecimal pointsDiscountAmount) {
|
||||
this.pointsDiscountAmount = pointsDiscountAmount;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,12 @@ public class Sale {
|
||||
@Column(nullable = false)
|
||||
private Integer pointsEarned = 0;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer pointsUsed = 0;
|
||||
|
||||
@Column(nullable = false, precision = 10, scale = 2)
|
||||
private BigDecimal pointsDiscountAmount = BigDecimal.ZERO;
|
||||
|
||||
@OneToMany(mappedBy = "sale", cascade = CascadeType.ALL)
|
||||
private List<SaleItem> items = new ArrayList<>();
|
||||
|
||||
@@ -211,6 +217,22 @@ public class Sale {
|
||||
this.pointsEarned = pointsEarned;
|
||||
}
|
||||
|
||||
public Integer getPointsUsed() {
|
||||
return pointsUsed;
|
||||
}
|
||||
|
||||
public void setPointsUsed(Integer pointsUsed) {
|
||||
this.pointsUsed = pointsUsed;
|
||||
}
|
||||
|
||||
public BigDecimal getPointsDiscountAmount() {
|
||||
return pointsDiscountAmount;
|
||||
}
|
||||
|
||||
public void setPointsDiscountAmount(BigDecimal pointsDiscountAmount) {
|
||||
this.pointsDiscountAmount = pointsDiscountAmount;
|
||||
}
|
||||
|
||||
public List<SaleItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -152,9 +152,33 @@ public class SaleService {
|
||||
saleItems.add(saleItem);
|
||||
subtotalAmount = subtotalAmount.add(itemTotal);
|
||||
}
|
||||
subtotalAmount = subtotalAmount.negate();
|
||||
sale.setSubtotalAmount(subtotalAmount);
|
||||
sale.setTotalAmount(subtotalAmount);
|
||||
|
||||
Sale originalSale = sale.getOriginalSale();
|
||||
BigDecimal originalSubtotal = originalSale.getSubtotalAmount() != null
|
||||
? originalSale.getSubtotalAmount()
|
||||
: originalSale.getItems().stream()
|
||||
.map(i -> i.getUnitPrice().multiply(BigDecimal.valueOf(Math.abs(i.getQuantity()))))
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
BigDecimal refundRatio = originalSubtotal.compareTo(BigDecimal.ZERO) != 0
|
||||
? subtotalAmount.divide(originalSubtotal, 10, RoundingMode.HALF_UP)
|
||||
: BigDecimal.ONE;
|
||||
|
||||
BigDecimal refundTotal = originalSale.getTotalAmount().abs()
|
||||
.multiply(refundRatio).setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
sale.setSubtotalAmount(subtotalAmount.negate());
|
||||
sale.setTotalAmount(refundTotal.negate());
|
||||
|
||||
User refundCustomer = customer != null ? customer : originalSale.getCustomer();
|
||||
if (refundCustomer != null) {
|
||||
int pointsToRestore = BigDecimal.valueOf(originalSale.getPointsUsed())
|
||||
.multiply(refundRatio).setScale(0, RoundingMode.FLOOR).intValue();
|
||||
int pointsToDeduct = BigDecimal.valueOf(originalSale.getPointsEarned())
|
||||
.multiply(refundRatio).setScale(0, RoundingMode.FLOOR).intValue();
|
||||
refundCustomer.setLoyaltyPoints(refundCustomer.getLoyaltyPoints() + pointsToRestore - pointsToDeduct);
|
||||
userRepository.save(refundCustomer);
|
||||
}
|
||||
} else {
|
||||
for (var itemRequest : request.getItems()) {
|
||||
Product product = productRepository.findById(itemRequest.getProdId())
|
||||
@@ -188,10 +212,23 @@ public class SaleService {
|
||||
BigDecimal couponDiscount = calculateCouponDiscount(sale.getCoupon(), subtotalAmount);
|
||||
sale.setCouponDiscountAmount(couponDiscount);
|
||||
|
||||
BigDecimal employeeDiscount = calculateEmployeeDiscount(customer, subtotalAmount.subtract(couponDiscount));
|
||||
BigDecimal pointsDiscount = BigDecimal.ZERO;
|
||||
int pointsUsed = 0;
|
||||
if (customer != null && request.getPointsUsed() != null && request.getPointsUsed() > 0) {
|
||||
if (customer.getLoyaltyPoints() < request.getPointsUsed()) {
|
||||
throw new BusinessException("Customer does not have enough loyalty points");
|
||||
}
|
||||
pointsUsed = request.getPointsUsed();
|
||||
pointsDiscount = calculatePointsDiscount(pointsUsed);
|
||||
customer.setLoyaltyPoints(customer.getLoyaltyPoints() - pointsUsed);
|
||||
}
|
||||
sale.setPointsUsed(pointsUsed);
|
||||
sale.setPointsDiscountAmount(pointsDiscount);
|
||||
|
||||
BigDecimal employeeDiscount = calculateEmployeeDiscount(customer, subtotalAmount.subtract(couponDiscount).subtract(pointsDiscount));
|
||||
sale.setEmployeeDiscountAmount(employeeDiscount);
|
||||
|
||||
BigDecimal finalTotal = subtotalAmount.subtract(couponDiscount).subtract(employeeDiscount);
|
||||
BigDecimal finalTotal = subtotalAmount.subtract(couponDiscount).subtract(pointsDiscount).subtract(employeeDiscount);
|
||||
sale.setTotalAmount(finalTotal.max(BigDecimal.ZERO));
|
||||
|
||||
sale.setPointsEarned(sale.getTotalAmount().setScale(0, RoundingMode.FLOOR).intValue());
|
||||
@@ -240,6 +277,10 @@ public class SaleService {
|
||||
return discount.min(subtotal).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal calculatePointsDiscount(int pointsUsed) {
|
||||
return new BigDecimal(pointsUsed).divide(new BigDecimal("20"), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal calculateEmployeeDiscount(User customer, BigDecimal remainingAmount) {
|
||||
if (customer == null || remainingAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return BigDecimal.ZERO;
|
||||
@@ -274,6 +315,8 @@ public class SaleService {
|
||||
response.setCouponDiscountAmount(sale.getCouponDiscountAmount());
|
||||
response.setEmployeeDiscountAmount(sale.getEmployeeDiscountAmount());
|
||||
response.setPointsEarned(sale.getPointsEarned());
|
||||
response.setPointsUsed(sale.getPointsUsed());
|
||||
response.setPointsDiscountAmount(sale.getPointsDiscountAmount());
|
||||
response.setChannel(sale.getChannel());
|
||||
if (sale.getCoupon() != null) {
|
||||
response.setCouponId(sale.getCoupon().getCouponId());
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sale
|
||||
ADD COLUMN pointsUsed INT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN pointsDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00;
|
||||
@@ -230,6 +230,8 @@ CREATE TABLE IF NOT EXISTS sale (
|
||||
couponDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
|
||||
employeeDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
|
||||
pointsEarned INT NOT NULL DEFAULT 0,
|
||||
pointsUsed INT NOT NULL DEFAULT 0,
|
||||
pointsDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_sale_employee FOREIGN KEY (employeeId) REFERENCES users(id),
|
||||
|
||||
Reference in New Issue
Block a user