DiscountRequest.java

package com.university.bookstore.chain;

import java.util.Objects;

import com.university.bookstore.model.Material;

/**
 * Request object for discount approval in the Chain of Responsibility pattern.
 * Contains all information needed to process a discount request.
 * 
 * @author Navid Mohaghegh
 * @version 3.0
 * @since 2024-09-15
 */
public class DiscountRequest {
    
    private final Material material;
    private final double requestedDiscount;
    private final String customerId;
    private final String reason;
    private boolean approved;
    private String approvedBy;
    private String rejectionReason;
    private final long timestamp;
    
    /**
     * Creates a new discount request.
     * 
     * @param material the material for which discount is requested
     * @param requestedDiscount the requested discount rate (0.0 to 1.0)
     * @param customerId the customer requesting the discount
     * @param reason the reason for the discount request
     * @throws IllegalArgumentException if parameters are invalid
     */
    public DiscountRequest(Material material, double requestedDiscount, 
                          String customerId, String reason) {
        this.material = Objects.requireNonNull(material, "Material cannot be null");
        this.requestedDiscount = Math.max(0.0, Math.min(1.0, requestedDiscount));
        this.customerId = Objects.requireNonNull(customerId, "Customer ID cannot be null");
        this.reason = Objects.requireNonNull(reason, "Reason cannot be null");
        this.approved = false;
        this.timestamp = System.currentTimeMillis();
    }
    
    /**
     * Gets the material for which discount is requested.
     * 
     * @return the material
     */
    public Material getMaterial() {
        return material;
    }
    
    /**
     * Gets the requested discount rate.
     * 
     * @return the discount rate (0.0 to 1.0)
     */
    public double getRequestedDiscount() {
        return requestedDiscount;
    }
    
    /**
     * Gets the requested discount percentage.
     * 
     * @return the discount percentage (0.0 to 100.0)
     */
    public double getRequestedDiscountPercentage() {
        return requestedDiscount * 100.0;
    }
    
    /**
     * Gets the customer ID.
     * 
     * @return the customer ID
     */
    public String getCustomerId() {
        return customerId;
    }
    
    /**
     * Gets the reason for the discount request.
     * 
     * @return the reason
     */
    public String getReason() {
        return reason;
    }
    
    /**
     * Checks if the request is approved.
     * 
     * @return true if approved
     */
    public boolean isApproved() {
        return approved;
    }
    
    /**
     * Sets the approval status.
     * 
     * @param approved the approval status
     */
    public void setApproved(boolean approved) {
        this.approved = approved;
    }
    
    /**
     * Gets who approved the request.
     * 
     * @return the approver name
     */
    public String getApprovedBy() {
        return approvedBy;
    }
    
    /**
     * Sets who approved the request.
     * 
     * @param approvedBy the approver name
     */
    public void setApprovedBy(String approvedBy) {
        this.approvedBy = approvedBy;
    }
    
    /**
     * Gets the rejection reason.
     * 
     * @return the rejection reason
     */
    public String getRejectionReason() {
        return rejectionReason;
    }
    
    /**
     * Sets the rejection reason.
     * 
     * @param rejectionReason the rejection reason
     */
    public void setRejectionReason(String rejectionReason) {
        this.rejectionReason = rejectionReason;
    }
    
    /**
     * Gets the request timestamp.
     * 
     * @return the timestamp in milliseconds
     */
    public long getTimestamp() {
        return timestamp;
    }
    
    /**
     * Calculates the discounted price if approved.
     * 
     * @return the discounted price
     */
    public double getDiscountedPrice() {
        if (approved) {
            return material.getPrice() * (1.0 - requestedDiscount);
        }
        return material.getPrice();
    }
    
    /**
     * Calculates the savings amount if approved.
     * 
     * @return the savings amount
     */
    public double getSavingsAmount() {
        if (approved) {
            return material.getPrice() * requestedDiscount;
        }
        return 0.0;
    }
    
    /**
     * Gets a summary of the discount request.
     * 
     * @return the request summary
     */
    public String getSummary() {
        return String.format("Discount Request: %s for %s (%.1f%%) - %s",
            material.getTitle(), customerId, getRequestedDiscountPercentage(), reason);
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        
        DiscountRequest that = (DiscountRequest) obj;
        return Double.compare(that.requestedDiscount, requestedDiscount) == 0 &&
               approved == that.approved &&
               timestamp == that.timestamp &&
               Objects.equals(material, that.material) &&
               Objects.equals(customerId, that.customerId) &&
               Objects.equals(reason, that.reason) &&
               Objects.equals(approvedBy, that.approvedBy) &&
               Objects.equals(rejectionReason, that.rejectionReason);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(material, requestedDiscount, customerId, reason, 
                          approved, approvedBy, rejectionReason, timestamp);
    }
    
    @Override
    public String toString() {
        return String.format("DiscountRequest[%s, %.1f%%, %s, %s, Approved=%s]",
            material.getTitle(), getRequestedDiscountPercentage(), customerId, reason, approved);
    }
}