Fixed Coupon to use in sales

This commit is contained in:
Alex
2026-04-12 00:25:33 -06:00
parent 0311887185
commit 96e6cd6dc7
4 changed files with 120 additions and 9 deletions

View File

@@ -201,7 +201,7 @@ public class SaleDetailFragment extends Fragment {
if (sale.getItems() != null) {
binding.llSaleItems.removeAllViews();
for (SaleDTO.SaleItemDTO item : sale.getItems()) {
addItemRow(item.getProductName(), Math.abs(item.getQuantity()), item.getUnitPrice());
addItemRow(item.getProductName(), Math.abs(item.getQuantity()), item.getUnitPrice(), null);
}
}
}
@@ -308,15 +308,16 @@ public class SaleDetailFragment extends Fragment {
break;
}
}
addItemRow(name, item.getQuantity(), price);
addItemRow(name, item.getQuantity(), price, item.getProdId());
}
}
private void addItemRow(String name, int qty, BigDecimal price) {
private void addItemRow(String name, int qty, BigDecimal price, Long prodId) {
if (getContext() == null) return;
LinearLayout row = new LinearLayout(getContext());
row.setOrientation(LinearLayout.HORIZONTAL);
row.setPadding(0, 8, 0, 8);
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
TextView tvName = new TextView(getContext());
tvName.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 2f));
@@ -333,6 +334,20 @@ public class SaleDetailFragment extends Fragment {
row.addView(tvName);
row.addView(tvQty);
row.addView(tvPrice);
if (prodId != null) {
Button btnRemove = new Button(getContext());
btnRemove.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
btnRemove.setText("");
btnRemove.setTextSize(12f);
btnRemove.setBackgroundTintList(android.content.res.ColorStateList.valueOf(0xFFE53935));
btnRemove.setTextColor(0xFFFFFFFF);
btnRemove.setPadding(16, 4, 16, 4);
btnRemove.setOnClickListener(v -> viewModel.removeFromCart(prodId));
row.addView(btnRemove);
}
binding.llSaleItems.addView(row);
}

View File

@@ -95,6 +95,12 @@ public class SaleDetailViewModel extends ViewModel {
cartItems.setValue(currentCart);
}
public void removeFromCart(Long prodId) {
List<SaleDTO.SaleItemDTO> currentCart = new ArrayList<>(cartItems.getValue());
currentCart.removeIf(item -> item.getProdId().equals(prodId));
cartItems.setValue(currentCart);
}
public LiveData<List<SaleDTO.SaleItemDTO>> getCartItems() { return cartItems; }
public LiveData<Resource<CouponDTO>> lookupCoupon(String code) {

View File

@@ -12,6 +12,8 @@ public class SaleResponse {
private String employeeName;
private Long storeId;
private String storeName;
private Long customerId;
private String customerName;
private BigDecimal totalAmount;
private BigDecimal subtotalAmount;
private BigDecimal couponDiscountAmount;
@@ -77,6 +79,22 @@ public class SaleResponse {
this.storeName = storeName;
}
public Long getCustomerId() {
return customerId;
}
public void setCustomerId(Long customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public BigDecimal getTotalAmount() {
return totalAmount;
}

View File

@@ -13,6 +13,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -20,6 +21,8 @@ import java.util.List;
@Service
public class SaleService {
private static final BigDecimal EMPLOYEE_DISCOUNT_PERCENT = new BigDecimal("0.10");
private final SaleRepository saleRepository;
private final ProductRepository productRepository;
private final StoreRepository storeRepository;
@@ -76,6 +79,7 @@ public class SaleService {
if (request.getCouponId() != null) {
Coupon coupon = couponRepository.findById(request.getCouponId())
.orElseThrow(() -> new ResourceNotFoundException("Coupon not found with id: " + request.getCouponId()));
validateCoupon(coupon);
sale.setCoupon(coupon);
}
@@ -85,8 +89,9 @@ public class SaleService {
sale.setCart(cart);
}
User customer = null;
if (request.getCustomerId() != null) {
User customer = userRepository.findById(request.getCustomerId())
customer = userRepository.findById(request.getCustomerId())
.orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + request.getCustomerId()));
sale.setCustomer(customer);
}
@@ -97,7 +102,7 @@ public class SaleService {
sale.setOriginalSale(originalSale);
}
BigDecimal totalAmount = BigDecimal.ZERO;
BigDecimal subtotalAmount = BigDecimal.ZERO;
List<SaleItem> saleItems = new ArrayList<>();
if (sale.getIsRefund() && sale.getOriginalSale() != null) {
@@ -145,9 +150,11 @@ public class SaleService {
saleItem.setUnitPrice(unitPrice);
saleItems.add(saleItem);
totalAmount = totalAmount.add(itemTotal);
subtotalAmount = subtotalAmount.add(itemTotal);
}
totalAmount = totalAmount.negate();
subtotalAmount = subtotalAmount.negate();
sale.setSubtotalAmount(subtotalAmount);
sale.setTotalAmount(subtotalAmount);
} else {
for (var itemRequest : request.getItems()) {
Product product = productRepository.findById(itemRequest.getProdId())
@@ -174,17 +181,77 @@ public class SaleService {
saleItem.setUnitPrice(unitPrice);
saleItems.add(saleItem);
totalAmount = totalAmount.add(itemTotal);
subtotalAmount = subtotalAmount.add(itemTotal);
}
sale.setSubtotalAmount(subtotalAmount);
BigDecimal couponDiscount = calculateCouponDiscount(sale.getCoupon(), subtotalAmount);
sale.setCouponDiscountAmount(couponDiscount);
BigDecimal employeeDiscount = calculateEmployeeDiscount(customer, subtotalAmount.subtract(couponDiscount));
sale.setEmployeeDiscountAmount(employeeDiscount);
BigDecimal finalTotal = subtotalAmount.subtract(couponDiscount).subtract(employeeDiscount);
sale.setTotalAmount(finalTotal.max(BigDecimal.ZERO));
sale.setPointsEarned(sale.getTotalAmount().setScale(0, RoundingMode.FLOOR).intValue());
if (customer != null) {
customer.setLoyaltyPoints(customer.getLoyaltyPoints() + sale.getPointsEarned());
userRepository.save(customer);
}
}
sale.setTotalAmount(totalAmount);
sale.setItems(saleItems);
Sale savedSale = saleRepository.save(sale);
return mapToResponse(savedSale);
}
private void validateCoupon(Coupon coupon) {
if (!Boolean.TRUE.equals(coupon.getActive())) {
throw new BusinessException("Coupon is not active");
}
LocalDateTime now = LocalDateTime.now();
if (coupon.getStartsAt() != null && now.isBefore(coupon.getStartsAt())) {
throw new BusinessException("Coupon has not started yet");
}
if (coupon.getEndsAt() != null && now.isAfter(coupon.getEndsAt())) {
throw new BusinessException("Coupon has expired");
}
}
private BigDecimal calculateCouponDiscount(Coupon coupon, BigDecimal subtotal) {
if (coupon == null || subtotal.compareTo(BigDecimal.ZERO) <= 0) {
return BigDecimal.ZERO;
}
if (coupon.getMinOrderAmount() != null && subtotal.compareTo(coupon.getMinOrderAmount()) < 0) {
return BigDecimal.ZERO;
}
BigDecimal discount = BigDecimal.ZERO;
String type = coupon.getDiscountType().trim().toUpperCase();
if ("PERCENTAGE".equals(type) || "PERCENT".equals(type)) {
discount = subtotal.multiply(coupon.getDiscountValue().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP));
} else if ("FIXED".equals(type)) {
discount = coupon.getDiscountValue();
}
return discount.min(subtotal).setScale(2, RoundingMode.HALF_UP);
}
private BigDecimal calculateEmployeeDiscount(User customer, BigDecimal remainingAmount) {
if (customer == null || remainingAmount.compareTo(BigDecimal.ZERO) <= 0) {
return BigDecimal.ZERO;
}
if (customer.getRole() == User.Role.STAFF || customer.getRole() == User.Role.ADMIN) {
return remainingAmount.multiply(EMPLOYEE_DISCOUNT_PERCENT).setScale(2, RoundingMode.HALF_UP);
}
return BigDecimal.ZERO;
}
private SaleResponse mapToResponse(Sale sale) {
SaleResponse response = new SaleResponse();
response.setSaleId(sale.getSaleId());
@@ -197,6 +264,11 @@ public class SaleService {
response.setStoreName(sale.getStore().getStoreName());
}
if (sale.getCustomer() != null) {
response.setCustomerId(sale.getCustomer().getId());
response.setCustomerName(sale.getCustomer().getFirstName() + " " + sale.getCustomer().getLastName());
}
response.setTotalAmount(sale.getTotalAmount());
response.setSubtotalAmount(sale.getSubtotalAmount());
response.setCouponDiscountAmount(sale.getCouponDiscountAmount());