Merge branch 'AttachmentsToChat'
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,7 +29,9 @@ public class SaleRequest {
|
||||
|
||||
private Long cartId;
|
||||
|
||||
private Boolean useLoyaltyPoints = false;
|
||||
private Integer pointsUsed;
|
||||
|
||||
private BigDecimal pointsDiscountAmount;
|
||||
|
||||
public Long getStoreId() {
|
||||
return storeId;
|
||||
@@ -102,12 +105,20 @@ public class SaleRequest {
|
||||
this.cartId = cartId;
|
||||
}
|
||||
|
||||
public Boolean getUseLoyaltyPoints() {
|
||||
return useLoyaltyPoints;
|
||||
public Integer getPointsUsed() {
|
||||
return pointsUsed;
|
||||
}
|
||||
|
||||
public void setUseLoyaltyPoints(Boolean useLoyaltyPoints) {
|
||||
this.useLoyaltyPoints = useLoyaltyPoints;
|
||||
public void setPointsUsed(Integer pointsUsed) {
|
||||
this.pointsUsed = pointsUsed;
|
||||
}
|
||||
|
||||
public BigDecimal getPointsDiscountAmount() {
|
||||
return pointsDiscountAmount;
|
||||
}
|
||||
|
||||
public void setPointsDiscountAmount(BigDecimal pointsDiscountAmount) {
|
||||
this.pointsDiscountAmount = pointsDiscountAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,8 @@ public class SaleResponse {
|
||||
private BigDecimal loyaltyDiscountAmount;
|
||||
private Integer pointsUsed;
|
||||
private Integer pointsEarned;
|
||||
private Integer pointsUsed;
|
||||
private BigDecimal pointsDiscountAmount;
|
||||
private String channel;
|
||||
private Long couponId;
|
||||
private Long cartId;
|
||||
@@ -153,6 +155,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;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ public class UserRequest {
|
||||
|
||||
private Boolean active = true;
|
||||
|
||||
private Integer loyaltyPoints;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
@@ -127,6 +129,14 @@ public class UserRequest {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public Integer getLoyaltyPoints() {
|
||||
return loyaltyPoints;
|
||||
}
|
||||
|
||||
public void setLoyaltyPoints(Integer loyaltyPoints) {
|
||||
this.loyaltyPoints = loyaltyPoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -75,6 +75,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<>();
|
||||
|
||||
@@ -233,6 +239,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;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public interface PetRepository extends JpaRepository<Pet, Long> {
|
||||
"WHERE LOWER(p.petStatus) = 'available' " +
|
||||
"AND NOT EXISTS (" +
|
||||
" SELECT 1 FROM Adoption a " +
|
||||
" WHERE a.pet = p AND LOWER(a.adoptionStatus) = 'completed'" +
|
||||
" WHERE a.pet = p AND (LOWER(a.adoptionStatus) = 'completed' OR LOWER(a.adoptionStatus) = 'pending')" +
|
||||
") " +
|
||||
"ORDER BY p.petName ASC")
|
||||
List<Pet> findAdoptablePetsOrderByPetNameAsc();
|
||||
@@ -29,7 +29,7 @@ public interface PetRepository extends JpaRepository<Pet, Long> {
|
||||
"AND (:storeId IS NULL OR p.store.storeId = :storeId) " +
|
||||
"AND NOT EXISTS (" +
|
||||
" SELECT 1 FROM Adoption a " +
|
||||
" WHERE a.pet = p AND LOWER(a.adoptionStatus) = 'completed'" +
|
||||
" WHERE a.pet = p AND (LOWER(a.adoptionStatus) = 'completed' OR LOWER(a.adoptionStatus) = 'pending')" +
|
||||
") " +
|
||||
"ORDER BY p.petName ASC")
|
||||
List<Pet> findAdoptablePetsByStore(@Param("storeId") Long storeId);
|
||||
|
||||
@@ -32,6 +32,7 @@ public class AdoptionService {
|
||||
private static final String ADOPTION_STATUS_MISSED = "Missed";
|
||||
private static final String PET_STATUS_AVAILABLE = "Available";
|
||||
private static final String PET_STATUS_ADOPTED = "Adopted";
|
||||
private static final String PET_STATUS_PENDING = "Pending";
|
||||
|
||||
private final AdoptionRepository adoptionRepository;
|
||||
private final PetRepository petRepository;
|
||||
@@ -263,10 +264,14 @@ public class AdoptionService {
|
||||
private void syncPetStatus(Pet pet, String adoptionStatus, Long adoptionId, User customer) {
|
||||
boolean completedElsewhere = adoptionId != null
|
||||
&& adoptionRepository.existsByPet_IdAndAdoptionStatusIgnoreCaseAndAdoptionIdNot(pet.getPetId(), ADOPTION_STATUS_COMPLETED, adoptionId);
|
||||
|
||||
if (ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus) || completedElsewhere) {
|
||||
pet.setPetStatus(PET_STATUS_ADOPTED);
|
||||
pet.setOwner(customer);
|
||||
pet.setStore(null);
|
||||
} else if (ADOPTION_STATUS_PENDING.equalsIgnoreCase(adoptionStatus)) {
|
||||
pet.setPetStatus(PET_STATUS_PENDING);
|
||||
pet.setOwner(customer);
|
||||
} else {
|
||||
pet.setPetStatus(PET_STATUS_AVAILABLE);
|
||||
pet.setOwner(null);
|
||||
|
||||
@@ -160,14 +160,33 @@ public class SaleService {
|
||||
saleItems.add(saleItem);
|
||||
subtotalAmount = subtotalAmount.add(itemTotal);
|
||||
}
|
||||
subtotalAmount = subtotalAmount.negate();
|
||||
sale.setSubtotalAmount(subtotalAmount);
|
||||
sale.setTotalAmount(subtotalAmount);
|
||||
sale.setCouponDiscountAmount(BigDecimal.ZERO);
|
||||
sale.setEmployeeDiscountAmount(BigDecimal.ZERO);
|
||||
sale.setLoyaltyDiscountAmount(BigDecimal.ZERO);
|
||||
sale.setPointsUsed(0);
|
||||
sale.setPointsEarned(0);
|
||||
|
||||
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 {
|
||||
if (request.getItems() == null || request.getItems().isEmpty()) {
|
||||
throw new BusinessException("At least one item is required");
|
||||
@@ -204,14 +223,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 loyaltyDiscount = calculateLoyaltyDiscount(customer, subtotalAmount.subtract(couponDiscount).subtract(employeeDiscount), Boolean.TRUE.equals(request.getUseLoyaltyPoints()));
|
||||
sale.setLoyaltyDiscountAmount(loyaltyDiscount);
|
||||
sale.setPointsUsed(toPointsUsed(loyaltyDiscount));
|
||||
|
||||
BigDecimal finalTotal = subtotalAmount.subtract(couponDiscount).subtract(employeeDiscount).subtract(loyaltyDiscount);
|
||||
BigDecimal finalTotal = subtotalAmount.subtract(couponDiscount).subtract(pointsDiscount).subtract(employeeDiscount);
|
||||
sale.setTotalAmount(finalTotal.max(BigDecimal.ZERO));
|
||||
|
||||
sale.setPointsEarned(sale.getTotalAmount().setScale(0, RoundingMode.FLOOR).intValue());
|
||||
@@ -262,6 +290,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;
|
||||
@@ -328,6 +360,8 @@ public class SaleService {
|
||||
response.setLoyaltyDiscountAmount(sale.getLoyaltyDiscountAmount());
|
||||
response.setPointsUsed(sale.getPointsUsed());
|
||||
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());
|
||||
|
||||
@@ -75,6 +75,9 @@ public class UserService {
|
||||
user.setStaffRole(trimToNull(request.getStaffRole()));
|
||||
user.setPrimaryStore(resolveStore(request.getPrimaryStoreId()));
|
||||
user.setActive(request.getActive() != null ? request.getActive() : true);
|
||||
if (request.getLoyaltyPoints() != null) {
|
||||
user.setLoyaltyPoints(request.getLoyaltyPoints());
|
||||
}
|
||||
|
||||
validateUniquePhone(user.getPhone(), null);
|
||||
|
||||
@@ -111,6 +114,9 @@ public class UserService {
|
||||
user.setStaffRole(trimToNull(request.getStaffRole()));
|
||||
user.setPrimaryStore(resolveStore(request.getPrimaryStoreId()));
|
||||
user.setActive(request.getActive() != null ? request.getActive() : true);
|
||||
if (request.getLoyaltyPoints() != null) {
|
||||
user.setLoyaltyPoints(request.getLoyaltyPoints());
|
||||
}
|
||||
if (invalidateToken) {
|
||||
user.setTokenVersion(user.getTokenVersion() + 1);
|
||||
}
|
||||
|
||||
@@ -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