ProductStockSale.java

package com.tradecloud.domain.model.requestforquote;

import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.base.utils.DateUtils;
import com.tradecloud.domain.item.Product;
import com.tradecloud.domain.place.FinalDestination;
import com.tradecloud.domain.place.NamedPlace;
import org.hibernate.annotations.Where;

import javax.persistence.*;
import java.util.*;

@Entity
@Table(name = "product_stock_sale",
        uniqueConstraints = {
                @UniqueConstraint(columnNames = {"lineItemCode", "namedplace_code"}, name = "uk_product_place")
        })
public class ProductStockSale extends PersistenceBase {
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "product_id", nullable = false)
    private Product product;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "namedPlace_code", nullable = true)
    private NamedPlace namedPlace;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "finalDestination_code", nullable = true)
    private FinalDestination finalDestination;

    @Column(name = "lineItemCode", nullable = false)
    private String lineItemCode;

    @OneToMany(mappedBy = "productStockSale", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
    @Where(clause = "type = 'SALE'")
    private List<SaleStockPeriod> salePeriods = new ArrayList<>();


    @OneToMany(mappedBy = "productStockSale", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
    @Where(clause = "type = 'STOCK'")
    private List<SaleStockPeriod> stockPeriods = new ArrayList<>();
    private int stockCount=0;
    private String client;
    private String state;


    public ProductStockSale() {
    }

    public ProductStockSale(Product product, NamedPlace namedPlace,FinalDestination  finalDestination) {
        this.product = product;
        this.namedPlace = namedPlace;
        this.finalDestination=finalDestination;
        if (product != null) {
            this.lineItemCode = product.getCode();
        }
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
        if (product != null) {
            this.lineItemCode = product.getCode(); // Keep in sync
        }
    }

    public NamedPlace getNamedPlace() {
        return namedPlace;
    }

    public void setNamedPlace(NamedPlace namedPlace) {
        this.namedPlace = namedPlace;
    }

    public String getLineItemCode() {
        return lineItemCode;
    }

    public void setLineItemCode(String lineItemCode) {
        this.lineItemCode = lineItemCode;
    }

    public List<SaleStockPeriod> getSalePeriods() {
        return salePeriods;
    }

    public void setSalePeriods(List<SaleStockPeriod> salePeriods) {
        this.salePeriods = salePeriods;
    }

    public void addSalePeriod(SaleStockPeriod salePeriod) {
        salePeriods.add(salePeriod);
        salePeriod.setType(ProductStockSaleType.SALE);
        salePeriod.setProductStockSale(this);
    }

    public void removeSalePeriod(SaleStockPeriod salePeriod) {
        salePeriods.remove(salePeriod);
        salePeriod.setProductStockSale(null);
    }

    public void addStockPeriod(SaleStockPeriod salePeriod) {
        stockPeriods.add(salePeriod);
        salePeriod.setType(ProductStockSaleType.STOCK);
        salePeriod.setProductStockSale(this);
    }

    public List<SaleStockPeriod> getStockPeriods() {
        return stockPeriods;
    }

    public void setStockPeriods(List<SaleStockPeriod> stockPeriods) {
        this.stockPeriods = stockPeriods;
    }

    public FinalDestination getFinalDestination() {
        return finalDestination;
    }

    public void setFinalDestination(FinalDestination finalDestination) {
        this.finalDestination = finalDestination;
    }

    public int getStockCount() {
        return stockCount;
    }

    public void setStockCount(int stockCount) {
        this.stockCount = stockCount;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        ProductStockSale that = (ProductStockSale) o;
        return Objects.equals(namedPlace, that.namedPlace) && Objects.equals(lineItemCode, that.lineItemCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), namedPlace, lineItemCode);
    }

    @Override
    public String toString() {
        return "ProductStockSale{" +
                "lineItemCode='" + lineItemCode + '\'' +
                '}';
    }

    public void addOrUpdateStockPeriod(Date period, int quantity) {
        Optional<SaleStockPeriod> existingPeriodOpt = this.stockPeriods.stream()
                .filter(p -> DateUtils.getStartOfDay(p.getPeriod()).equals(DateUtils.getStartOfDay(period)))
                .findFirst();

        existingPeriodOpt.ifPresentOrElse(
                existingPeriod -> {
                    existingPeriod.setState("PENDING");
                    existingPeriod.setQuantity(quantity);
                },
                () -> {
                    SaleStockPeriod newStockPeriod = new SaleStockPeriod(this, period, quantity, ProductStockSaleType.STOCK);
                    newStockPeriod.setState("PENDING");
                    this.stockPeriods.add(newStockPeriod);
                }
        );
    }

    public void addOrUpdateSalePeriod(Date period, int quantity) {
        Optional<SaleStockPeriod> existingPeriodOpt = this.salePeriods.stream()
                .filter(p -> DateUtils.getStartOfDay(p.getPeriod()).equals(DateUtils.getStartOfDay(period)))
                .findFirst();

        existingPeriodOpt.ifPresentOrElse(
                existingPeriod -> {
                    existingPeriod.setState("PENDING");
                    existingPeriod.setQuantity(quantity);
                },
                () -> {
                    SaleStockPeriod newSalePeriod = new SaleStockPeriod(this, period, quantity,ProductStockSaleType.SALE);
                    newSalePeriod.setState("PENDING");
                    this.salePeriods.add(newSalePeriod);
                }
        );
    }

    public String getClient() {
        return client;
    }

    public void setClient(String client) {
        this.client = client;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}