Coupon.java
package com.rbctcsworld.ecommerce.coupon;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
@Entity
@Table(name = "coupons")
public class Coupon {
public static final String PERCENT = "PERCENT";
public static final String FIXED = "FIXED";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 40)
private String code;
@Column(nullable = false, length = 10)
private String type;
@Column(name = "discount_value", nullable = false, precision = 12, scale = 2)
private BigDecimal discountValue;
@Column(name = "min_order_amount", nullable = false, precision = 12, scale = 2)
private BigDecimal minOrderAmount = BigDecimal.ZERO;
@Column(name = "max_uses")
private Integer maxUses;
@Column(name = "used_count", nullable = false)
private int usedCount;
@Column(name = "valid_from")
private LocalDateTime validFrom;
@Column(name = "valid_until")
private LocalDateTime validUntil;
@Column(nullable = false)
private boolean active = true;
protected Coupon() {
}
public Coupon(String code, String type, BigDecimal discountValue, BigDecimal minOrderAmount, Integer maxUses,
LocalDateTime validFrom, LocalDateTime validUntil) {
this.code = code;
this.type = type;
this.discountValue = discountValue;
this.minOrderAmount = minOrderAmount == null ? BigDecimal.ZERO : minOrderAmount;
this.maxUses = maxUses;
this.validFrom = validFrom;
this.validUntil = validUntil;
}
/** Discount amount for a given subtotal (PERCENT of subtotal, or FIXED amount), never above the subtotal. */
public BigDecimal discountFor(BigDecimal subtotal) {
BigDecimal d = PERCENT.equals(type)
? subtotal.multiply(discountValue).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)
: discountValue;
return d.min(subtotal).setScale(2, RoundingMode.HALF_UP);
}
public boolean usageLimitReached() {
return maxUses != null && usedCount >= maxUses;
}
public Long getId() { return id; }
public String getCode() { return code; }
public String getType() { return type; }
public BigDecimal getDiscountValue() { return discountValue; }
public BigDecimal getMinOrderAmount() { return minOrderAmount; }
public Integer getMaxUses() { return maxUses; }
public int getUsedCount() { return usedCount; }
public LocalDateTime getValidFrom() { return validFrom; }
public LocalDateTime getValidUntil() { return validUntil; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
/** Changes the terms; the code and the usage count stay. */
public void update(String type, BigDecimal discountValue, BigDecimal minOrderAmount, Integer maxUses,
LocalDateTime validFrom, LocalDateTime validUntil) {
this.type = type;
this.discountValue = discountValue;
this.minOrderAmount = minOrderAmount == null ? BigDecimal.ZERO : minOrderAmount;
this.maxUses = maxUses;
this.validFrom = validFrom;
this.validUntil = validUntil;
}
}