BaseServiceProviderInvoice.java
package com.tradecloud.domain.document.invoice;
import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.configuration.SPICostlineCurrency;
import com.tradecloud.domain.costing.clean.CostLineNames;
import com.tradecloud.domain.costing.clean.Costed;
import com.tradecloud.domain.costing.clean.CostingVisitor;
import com.tradecloud.domain.document.CreditNote;
import com.tradecloud.domain.document.DocumentType;
import com.tradecloud.domain.document.SettleableDocument;
import com.tradecloud.domain.duties.CustomsDutyCaptureLevel;
import com.tradecloud.domain.party.ServiceProvider;
import com.tradecloud.domain.settlement.*;
import com.tradecloud.domain.supplier.Creditor;
import org.apache.commons.collections4.keyvalue.MultiKey;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.log4j.Logger;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlTransient;
import java.math.BigDecimal;
import java.util.*;
/**
* Created by ds on 2015/12/10.
*/
@MappedSuperclass
public abstract class BaseServiceProviderInvoice extends CostsInvoice implements SettleableDocument {
@Transient
@XmlTransient
private Logger log = Logger.getLogger(BaseServiceProviderInvoice.class);
private static final long serialVersionUID = 1L;
private BigDecimal forwardRate;
@NotNull(message = "SPI serviceProvider is required")
@ManyToOne
@XmlElement(name = "ServiceProvider")
private ServiceProvider serviceProvider;
@NotNull(message = "SPI nettValue is required")
@XmlAttribute
private BigDecimal nettValue;
@XmlAttribute
private BigDecimal taxValue = BigDecimal.ZERO;
@NotNull(message = "SPI customsDutyCaptureLevel is required")
@XmlAttribute(required = true)
@Enumerated(EnumType.STRING)
private CustomsDutyCaptureLevel customsDutyCaptureLevel = CustomsDutyCaptureLevel.INVOICE;
@NotNull(message = "SPI settlementDateCalculationType is required")
@XmlAttribute(required = true)
@Enumerated(EnumType.STRING)
private SettlementDateCalculationType settlementDateCalculationType;
/*
* Internal use only
*/
@OneToMany(cascade = CascadeType.ALL)
@XmlElementWrapper(name = "Payments")
@XmlElement(name = "Payment")
private Set<Payment> payments = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL)
@XmlElementWrapper(name = "IndirectCostAllocations")
@XmlElement(name = "IndirectCostAllocation")
private Set<IndirectCostAllocation> indirectCostsAllocations = new TreeSet<>();
@OneToMany(cascade = CascadeType.ALL)
@XmlElementWrapper(name = "CreditNotes")
@XmlElement(name = "CreditNote")
private Set<CreditNote> creditNotes = new HashSet<>();
@OneToMany
@XmlElementWrapper(name = "PlannedSettlements")
@XmlElement(name = "PlannedSettlement")
private Set<PlannedSettlement> plannedSettlements;
@Enumerated(value = EnumType.STRING)
@XmlAttribute
@NotNull(message = "SPI spiCostlineCurrency is required")
private SPICostlineCurrency spiCostlineCurrency = SPICostlineCurrency.FROM_COST_DEFINITION;
private BigDecimal weightedAverageForwardRateOfExchange;
public ServiceProvider getServiceProvider() {
return serviceProvider;
}
public void setServiceProvider(ServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public BigDecimal getNettValue() {
return nettValue;
}
public void setNettValue(BigDecimal nettValue) {
this.nettValue = nettValue;
}
public BigDecimal getTaxValue() {
return taxValue;
}
public void setTaxValue(BigDecimal taxValue) {
this.taxValue = taxValue;
}
public Set<Payment> getPayments() {
return payments;
}
public void setPayments(Set<Payment> payments) {
this.payments = payments;
}
public Set<IndirectCostAllocation> getIndirectCostsAllocations() {
return indirectCostsAllocations;
}
public void setIndirectCostsAllocations(Set<IndirectCostAllocation> indirectCostsAllocations) {
this.indirectCostsAllocations = indirectCostsAllocations;
}
public Set<CreditNote> getCreditNotes() {
return creditNotes;
}
public void setCreditNotes(Set<CreditNote> creditNotes) {
this.creditNotes = creditNotes;
}
public SettlementDateCalculationType getSettlementDateCalculationType() {
return settlementDateCalculationType;
}
public void setSettlementDateCalculationType(SettlementDateCalculationType settlementDateCalculationType) {
this.settlementDateCalculationType = settlementDateCalculationType;
}
@Override
public String getTypeDesc() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean hasPlannedSettlements() {
// TODO Auto-generated method stub
return false;
}
@Override
public void addPlannedSettlement(PlannedSettlement settlement) {
// TODO Auto-generated method stub
}
@Override
public Date resolveRateDate(RateDateSource source) {
// TODO Auto-generated method stub
return null;
}
@Override
public DocumentType getDocumentType() {
return DocumentType.SERVICE_PROVIDER_INVOICE;
}
@Override
public Creditor getCreditor() {
return serviceProvider;
}
@Override
public Set<PlannedSettlement> getPlannedSettlements() {
return plannedSettlements;
}
@Override
public void setPlannedSettlements(Set<PlannedSettlement> plannedSettlements) {
this.plannedSettlements = plannedSettlements;
}
public CustomsDutyCaptureLevel getCustomsDutyCaptureLevel() {
return customsDutyCaptureLevel;
}
public void setCustomsDutyCaptureLevel(CustomsDutyCaptureLevel customsDutyCaptureLevel) {
this.customsDutyCaptureLevel = customsDutyCaptureLevel;
}
@Override
public void accept(CostingVisitor costingVisitor) {
for (ActualConsignment actualConsignment : getActualConsignments()) {
actualConsignment.accept(costingVisitor);
}
if (costingVisitor != null) {
costingVisitor.visit(this);
} else {
log.error("Null CostingVisitor passed to ActualConsignment: " + getId() + ", " + getReference());
}
}
@Override
public void acceptVisitParentFirst(CostingVisitor costingVisitor) {
costingVisitor.visit(this);
for (ActualConsignment actualConsignment : getActualConsignments()) {
actualConsignment.acceptVisitParentFirst(costingVisitor);
}
}
@Override
public List<Costed> getCostedChildren() {
return new ArrayList<Costed>(getActualConsignments());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
// Do not use class.equals. This can return false for proxy objects
if (!HibernateUtils.proxyClassEquals(this, obj)) {
return false;
}
BaseServiceProviderInvoice other = (BaseServiceProviderInvoice) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(serviceProvider, other.getServiceProvider())
.append(reference, other.getReference())
.append(shipment, other.getShipment())
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.appendSuper(super.hashCode())
.append(serviceProvider)
.append(reference)
.append(shipment)
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this).appendSuper(super.toString()).append(nettValue).append(taxValue).append(customsDutyCaptureLevel).append
(serviceProvider != null ? serviceProvider.getName() : null).append(settlementDateCalculationType).toString();
}
@Override
public Object getTraversalKey() {
return new MultiKey(ServiceProviderInvoice.class, reference);
}
@Override
public BigDecimal getWeightedAverageForwardRateOfExchange() {
if (weightedAverageForwardRateOfExchange == null) {
weightedAverageForwardRateOfExchange = calculateAvgFwdRate(null);
}
return weightedAverageForwardRateOfExchange;
}
public BigDecimal calculateAvgFwdRate(Currency costingCurrency) {
if (costingCurrency != null && getSpiCostlineCurrency() != SPICostlineCurrency.MIXED_CURRENCIES
&& this.getCurrency().equals(costingCurrency)) {
return BigDecimal.ONE;
} else {
List<ActualOrder> actualOrders = getActualOrders();
BigDecimal costingCurrencyTotal = BigDecimal.ZERO;
BigDecimal currencyTotal = BigDecimal.ZERO;
for (ActualOrder actualOrder : actualOrders) {
for (CostLineCostingCell costLineCostingCell : actualOrder.getCostLineCosting().getCostLineCostingCellsList()) {
if (costLineCostingCell.getTransactionAmount() != null && costLineCostingCell.getForwardRate() != null) {
costingCurrencyTotal = costingCurrencyTotal.add(costLineCostingCell.getTransactionAmount().multiply(costLineCostingCell.
getForwardRate()));
currencyTotal = currencyTotal.add(costLineCostingCell.getTransactionAmount());
}
}
}
return MathUtils.safeDivide(costingCurrencyTotal, currencyTotal);
}
}
public BigDecimal getWeightedAverageForwardRateOfExchange(Currency costingCurrency) {
if (getSpiCostlineCurrency() != SPICostlineCurrency.MIXED_CURRENCIES && this.getCurrency().equals(costingCurrency)) {
return BigDecimal.ONE;
} else {
return getWeightedAverageForwardRateOfExchange();
}
}
@Override
public BigDecimal getWeightedAverageSpotRateOfExchange() {
throw new NotImplementedException("getWeightedAverageSpotRateOfExchange not implemented for base Service provider invoice");
}
@Override
public BigDecimal getCostingCurrencyTotalValue() {
if (BigDecimal.ZERO.compareTo(costingCurrencyTotalValue) == 0) {
// calculate the costing currency total
setCostingCurrencyTotalValue(calculateCostingCurrencyTotalValue());
}
return costingCurrencyTotalValue;
}
/**
* Internal method to set the costingCurrencyTotalValue of this invoice.
*
* @return
*/
public BigDecimal calculateCostingCurrencyTotalValue() {
BigDecimal costingCurrencyTotal = BigDecimal.ZERO;
// need to total all the cost lines at this level and use the associated forward rate
List<ActualOrder> actualOrders = getActualOrders();
for (ActualOrder actualOrder : actualOrders) {
for (CostLineCostingCell costLineCostingCell : actualOrder.getCostLineCosting().getCostLineCostingCellsList()) {
if (costLineCostingCell.getTransactionAmount() != null && costLineCostingCell.getForwardRate() != null) {
costingCurrencyTotal = costingCurrencyTotal.add(costLineCostingCell.getTransactionAmount().multiply(costLineCostingCell.
getForwardRate()));
}
}
}
return costingCurrencyTotal;
}
public BigDecimal getForwardRate() {
return forwardRate;
}
public void setForwardRate(BigDecimal forwardRate) {
this.forwardRate = forwardRate;
}
public BigDecimal calculateVat() {
List<ActualOrder> actualOrders = getActualOrders();
return calculateVat(actualOrders, false);
}
private BigDecimal calculateVat(List<? extends Actual> actuals, boolean integrateVat) {
BigDecimal vat = BigDecimal.ZERO;
for (Actual actual : actuals) {
List<CostLineCostingCell> costLineCostingCells = actual.getCostLineCosting().getCostLineCostingCells();
for (CostLineCostingCell costLineCostingCell : costLineCostingCells) {
BigDecimal cellVat = integrateVat ? costLineCostingCell.getIntegratedVat() : costLineCostingCell.getVat();
vat = vat.add(ObjectUtils.firstNonNull(cellVat, BigDecimal.ZERO));
}
}
return vat;
}
public BigDecimal getNetLocalCustomsVat() {
CostingCell costingCell = getCostLineCosting().getCostingCell(CostLineNames.CUSTOMS_VAT);
if (costingCell != null) {
return costingCell.getTransactionAmount();
}
return BigDecimal.ZERO;
}
public abstract BigDecimal getNetLocalVatable();
public abstract BigDecimal getNetLocalNonVatable();
public BigDecimal calculateIntegratedVat() {
return calculateVat(Collections.singletonList(this), true);
}
public abstract String getSplitInvoiceReference();
public SPICostlineCurrency getSpiCostlineCurrency() {
return spiCostlineCurrency;
}
public void setSpiCostlineCurrency(SPICostlineCurrency spiCostlineCurrency) {
this.spiCostlineCurrency = spiCostlineCurrency;
}
public List<PlannedSettlement> getPlannedSettlementList() {
return new ArrayList<>(plannedSettlements);
}
public InvoiceType getInvoiceType() {
return InvoiceType.OTHER;
}
public boolean isGenerated() {
return false;
}
}