/*
jBilling - The Enterprise Open Source Billing System
Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
This file is part of jbilling.
jbilling is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jbilling is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with jbilling. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sapienter.jbilling.server.order.db;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Transient;
import javax.persistence.Version;
import com.sapienter.jbilling.server.invoice.db.InvoiceLineDTO;
import com.sapienter.jbilling.server.util.csv.Exportable;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CollectionOfElements;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.OrderBy;
import com.sapienter.jbilling.common.SessionInternalError;
import com.sapienter.jbilling.server.invoice.InvoiceBL;
import com.sapienter.jbilling.server.invoice.db.InvoiceDTO;
import com.sapienter.jbilling.server.item.PricingField;
import com.sapienter.jbilling.server.process.db.BillingProcessDTO;
import com.sapienter.jbilling.server.user.db.UserDTO;
import com.sapienter.jbilling.server.util.Constants;
import com.sapienter.jbilling.server.util.Util;
import com.sapienter.jbilling.server.util.db.CurrencyDTO;
import java.util.ArrayList;
@Entity
@TableGenerator(
name="purchase_order_GEN",
table="jbilling_seqs",
pkColumnName = "name",
valueColumnName = "next_id",
pkColumnValue="purchase_order",
allocationSize = 100
)
@Table(name="purchase_order")
// No cache, mutable and critical
public class OrderDTO implements Serializable, Exportable {
private static Logger LOG = Logger.getLogger(OrderDTO.class);
private Integer id;
private UserDTO baseUserByUserId;
private UserDTO baseUserByCreatedBy;
private CurrencyDTO currencyDTO;
private OrderStatusDTO orderStatusDTO;
private OrderPeriodDTO orderPeriodDTO;
private OrderBillingTypeDTO orderBillingTypeDTO;
private Date activeSince;
private Date activeUntil;
private Date cycleStarts;
private Date createDate;
private Date nextBillableDay;
private int deleted;
private Integer notify;
private Date lastNotified;
private Integer notificationStep;
private Integer dueDateUnitId;
private Integer dueDateValue;
private Integer dfFm;
private Integer anticipatePeriods;
private Integer ownInvoice;
private String notes;
private Integer notesInInvoice;
private Set<OrderProcessDTO> orderProcesses = new HashSet<OrderProcessDTO>(0);
private List<OrderLineDTO> lines = new ArrayList<OrderLineDTO>(0);
private Integer isCurrent;
private Integer versionNum;
// other non-persitent fields
private Collection<OrderProcessDTO> nonReviewPeriods = new ArrayList<OrderProcessDTO>(0);
private Collection<InvoiceDTO> invoices = new ArrayList<InvoiceDTO>(0);
private Collection<BillingProcessDTO> billingProcesses = new ArrayList<BillingProcessDTO>(0);
private String periodStr = null;
private String billingTypeStr = null;
private String statusStr = null;
private String timeUnitStr = null;
private String currencySymbol = null;
private String currencyName = null;
private BigDecimal total = null;
private List<PricingField> pricingFields = null;
public OrderDTO() {
}
public OrderDTO(OrderDTO other) {
init(other);
}
public void init(OrderDTO other) {
this.id = other.getId();
this.baseUserByUserId = other.getBaseUserByUserId();
this.baseUserByCreatedBy = other.getBaseUserByCreatedBy();
this.currencyDTO = other.getCurrency();
this.orderStatusDTO = other.getOrderStatus();
this.orderPeriodDTO = other.getOrderPeriod();
this.orderBillingTypeDTO = other.getOrderBillingType();
this.activeSince = other.getActiveSince();
this.activeUntil = other.getActiveUntil();
this.createDate = other.getCreateDate();
this.nextBillableDay = other.getNextBillableDay();
this.deleted = other.getDeleted();
this.notify = other.getNotify();
this.lastNotified = other.getLastNotified();
this.notificationStep = other.getNotificationStep();
this.dueDateUnitId = other.getDueDateUnitId();
this.dueDateValue = other.getDueDateValue();
this.dfFm = other.getDfFm();
this.anticipatePeriods = other.getAnticipatePeriods();
this.ownInvoice = other.getOwnInvoice();
this.notes = other.getNotes();
this.notesInInvoice = other.getNotesInInvoice();
this.orderProcesses.addAll(other.getOrderProcesses());
for (OrderLineDTO line: other.getLines()) {
this.lines.add(new OrderLineDTO(line));
}
this.isCurrent = other.getIsCurrent();
this.versionNum = other.getVersionNum();
this.cycleStarts = other.getCycleStarts();
this.pricingFields = other.getPricingFields();
}
public OrderDTO(int id, UserDTO baseUserByCreatedBy, CurrencyDTO currencyDTO, OrderStatusDTO orderStatusDTO, OrderBillingTypeDTO orderBillingTypeDTO, Date createDatetime, Integer deleted) {
this.id = id;
this.baseUserByCreatedBy = baseUserByCreatedBy;
this.currencyDTO = currencyDTO;
this.orderStatusDTO = orderStatusDTO;
this.orderBillingTypeDTO = orderBillingTypeDTO;
this.createDate = createDatetime;
this.deleted = deleted;
}
public OrderDTO(int id, UserDTO baseUserByUserId, UserDTO baseUserByCreatedBy, CurrencyDTO currencyDTO,
OrderStatusDTO orderStatusDTO, OrderPeriodDTO orderPeriodDTO,
OrderBillingTypeDTO orderBillingTypeDTO, Date activeSince, Date activeUntil, Date createDatetime,
Date nextBillableDay, Integer deleted, Integer notify, Date lastNotified, Integer notificationStep,
Integer dueDateUnitId, Integer dueDateValue, Integer dfFm, Integer anticipatePeriods,
Integer ownInvoice, String notes, Integer notesInInvoice, Set<OrderProcessDTO> orderProcesses,
List<OrderLineDTO> orderLineDTOs, Integer isCurrent) {
this.id = id;
this.baseUserByUserId = baseUserByUserId;
this.baseUserByCreatedBy = baseUserByCreatedBy;
this.currencyDTO = currencyDTO;
this.orderStatusDTO = orderStatusDTO;
this.orderPeriodDTO = orderPeriodDTO;
this.orderBillingTypeDTO = orderBillingTypeDTO;
this.activeSince = activeSince;
this.activeUntil = activeUntil;
this.createDate = createDatetime;
this.nextBillableDay = nextBillableDay;
this.deleted = deleted;
this.notify = notify;
this.lastNotified = lastNotified;
this.notificationStep = notificationStep;
this.dueDateUnitId = dueDateUnitId;
this.dueDateValue = dueDateValue;
this.dfFm = dfFm;
this.anticipatePeriods = anticipatePeriods;
this.ownInvoice = ownInvoice;
this.notes = notes;
this.notesInInvoice = notesInInvoice;
this.orderProcesses = orderProcesses;
this.lines = orderLineDTOs;
this.isCurrent = isCurrent;
}
@Id @GeneratedValue(strategy=GenerationType.TABLE, generator="purchase_order_GEN")
@Column(name="id", unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id", nullable=false)
public UserDTO getBaseUserByUserId() {
return this.baseUserByUserId;
}
public void setBaseUserByUserId(UserDTO baseUserByUserId) {
this.baseUserByUserId = baseUserByUserId;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="created_by")
public UserDTO getBaseUserByCreatedBy() {
return this.baseUserByCreatedBy;
}
public void setBaseUserByCreatedBy(UserDTO baseUserByCreatedBy) {
this.baseUserByCreatedBy = baseUserByCreatedBy;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="currency_id", nullable=false)
public CurrencyDTO getCurrency() {
return this.currencyDTO;
}
public void setCurrency(CurrencyDTO currencyDTO) {
this.currencyDTO = currencyDTO;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="status_id", nullable=false)
public OrderStatusDTO getOrderStatus() {
return this.orderStatusDTO;
}
public void setOrderStatus(OrderStatusDTO orderStatusDTO) {
this.orderStatusDTO = orderStatusDTO;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="period_id")
public OrderPeriodDTO getOrderPeriod() {
return this.orderPeriodDTO;
}
public void setOrderPeriod(OrderPeriodDTO orderPeriodDTO) {
this.orderPeriodDTO = orderPeriodDTO;
}
public void setOrderPeriodId(Integer id) {
if (id != null) {
setOrderPeriod(new OrderPeriodDAS().find(id));
} else {
setOrderPeriod(null);
}
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="billing_type_id", nullable=false)
public OrderBillingTypeDTO getOrderBillingType() {
return this.orderBillingTypeDTO;
}
public void setOrderBillingType(OrderBillingTypeDTO orderBillingTypeDTO) {
this.orderBillingTypeDTO = orderBillingTypeDTO;
}
@Column(name="active_since", length=13)
public Date getActiveSince() {
return this.activeSince;
}
public void setActiveSince(Date activeSince) {
this.activeSince = activeSince;
}
@Column(name="cycle_start")
public Date getCycleStarts() {
return cycleStarts;
}
public void setCycleStarts(Date cycleStarts) {
this.cycleStarts = cycleStarts;
}
@Column(name="active_until", length=13)
public Date getActiveUntil() {
return this.activeUntil;
}
public void setActiveUntil(Date activeUntil) {
this.activeUntil = activeUntil;
}
@Column(name="create_datetime", nullable=false, length=29)
public Date getCreateDate() {
return this.createDate;
}
public void setCreateDate(Date createDatetime) {
this.createDate = createDatetime;
}
@Column(name="next_billable_day", length=29)
public Date getNextBillableDay() {
return this.nextBillableDay;
}
public void setNextBillableDay(Date nextBillableDay) {
this.nextBillableDay = nextBillableDay;
}
@Column(name="deleted", nullable=false)
public int getDeleted() {
return this.deleted;
}
public void setDeleted(int deleted) {
this.deleted = deleted;
}
@Column(name="notify")
public Integer getNotify() {
return this.notify;
}
public void setNotify(Integer notify) {
this.notify = notify;
}
@Column(name="last_notified", length=29)
public Date getLastNotified() {
return this.lastNotified;
}
public void setLastNotified(Date lastNotified) {
this.lastNotified = lastNotified;
}
@Column(name="notification_step")
public Integer getNotificationStep() {
return this.notificationStep;
}
public void setNotificationStep(Integer notificationStep) {
this.notificationStep = notificationStep;
}
@Column(name="due_date_unit_id")
public Integer getDueDateUnitId() {
return this.dueDateUnitId;
}
public void setDueDateUnitId(Integer dueDateUnitId) {
this.dueDateUnitId = dueDateUnitId;
}
@Column(name="due_date_value")
public Integer getDueDateValue() {
return this.dueDateValue;
}
public void setDueDateValue(Integer dueDateValue) {
this.dueDateValue = dueDateValue;
}
@Column(name="df_fm")
public Integer getDfFm() {
return this.dfFm;
}
public void setDfFm(Integer dfFm) {
this.dfFm = dfFm;
}
@Column(name="anticipate_periods")
public Integer getAnticipatePeriods() {
return this.anticipatePeriods;
}
public void setAnticipatePeriods(Integer anticipatePeriods) {
this.anticipatePeriods = anticipatePeriods;
}
@Column(name="own_invoice")
public Integer getOwnInvoice() {
return this.ownInvoice;
}
public void setOwnInvoice(Integer ownInvoice) {
this.ownInvoice = ownInvoice;
}
@Column(name="notes", length=200)
public String getNotes() {
return this.notes;
}
public void setNotes(String notes) {
// make sure this is fits in the DB
if (notes == null || notes.length() <= 200) {
this.notes = notes;
} else {
this.notes = notes.substring(0, 200);
LOG.warn("Trimming notes to 200 lenght: from " + notes + " to " + this.notes);
}
}
@Column(name="notes_in_invoice")
public Integer getNotesInInvoice() {
return this.notesInInvoice;
}
public void setNotesInInvoice(Integer notesInInvoice) {
this.notesInInvoice = notesInInvoice;
}
/*
* There might potentially hundreds of process records, but they are not read by the app.
* They are only taken for display, and then all are needed
*/
@CollectionOfElements
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="purchaseOrder")
@Fetch ( FetchMode.SUBSELECT)
@OrderBy (
clause = "id desc"
)
public Set<OrderProcessDTO> getOrderProcesses() {
return this.orderProcesses;
}
public void setOrderProcesses(Set<OrderProcessDTO> orderProcesses) {
this.orderProcesses = orderProcesses;
}
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="purchaseOrder")
@Fetch (FetchMode.SUBSELECT)
@OrderBy(clause="id")
public List<OrderLineDTO> getLines() {
return this.lines;
}
public void setLines(List<OrderLineDTO> orderLineDTOs) {
this.lines = orderLineDTOs;
}
@Column(name="is_current")
public Integer getIsCurrent() {
return isCurrent;
}
public void setIsCurrent(Integer isCurrent) {
this.isCurrent = isCurrent;
}
@Version
@Column(name="OPTLOCK")
public Integer getVersionNum() {
return versionNum;
}
public void setVersionNum(Integer versionNum) {
this.versionNum = versionNum;
}
/*
* Conveniant methods to ease migration from entity beans
*/
@Transient
public Integer getBillingTypeId() {
return getOrderBillingType() == null ? null : getOrderBillingType().getId();
}
/*
public void setBillingTypeId(Integer typeId) {
if (orderBillingTypeDTO == null) {
OrderBillingTypeDTO dto = new OrderBillingTypeDTO();
dto.setId(typeId);
setOrderBillingType(dto);
} else {
orderBillingTypeDTO.setId(id)
}
}
*/
@Transient
public Integer getStatusId() {
return getOrderStatus() == null ? null : getOrderStatus().getId();
}
public void setStatusId(Integer statusId) {
if (statusId == null) {
setOrderStatus(null);
return;
}
OrderStatusDTO dto = new OrderStatusDTO();
dto.setId(statusId);
setOrderStatus(dto);
}
@Transient
public Integer getCurrencyId() {
return getCurrency().getId();
}
public void setCurrencyId(Integer currencyId) {
if (currencyId == null) {
setCurrency(null);
} else {
CurrencyDTO currency = new CurrencyDTO(currencyId);
setCurrency(currency);
}
}
@Transient
public UserDTO getUser() {
return getBaseUserByUserId();
}
@Transient
public BigDecimal getTotal() {
if (total != null) {
return total;
}
BigDecimal result = new BigDecimal(0);
for (OrderLineDTO line: lines) {
if (line.getDeleted() == 0 && line.getAmount() != null) {
result = result.add(line.getAmount());
}
}
return result;
}
public void setTotal(BigDecimal total) {
this.total = total;
}
@Transient
// all the periods, but excluding those from process reviews
public Collection<OrderProcessDTO> getPeriods() {
return nonReviewPeriods;
}
@Transient
public Collection<InvoiceDTO> getInvoices() {
return invoices;
}
@Transient
public String getPeriodStr() {
return periodStr;
}
public void setPeriodStr(String str) {
periodStr = str;
}
@Transient
public String getBillingTypeStr() {
return billingTypeStr;
}
public void setBillingTypeStr(String str) {
this.billingTypeStr = str;
}
@Transient
public String getStatusStr() {
return statusStr;
}
@Transient
public String getTimeUnitStr() {
return timeUnitStr;
}
@Transient
public String getCurrencyName() {
return currencyName;
}
@Transient
public String getCurrencySymbol() {
return currencySymbol;
}
public void addExtraFields(Integer languageId) {
invoices = new ArrayList<InvoiceDTO>();
billingProcesses = new ArrayList<BillingProcessDTO>();
nonReviewPeriods = new ArrayList<OrderProcessDTO>();
for (OrderProcessDTO process: getOrderProcesses()) {
if (process.getIsReview() == 1) continue;
nonReviewPeriods.add(process);
try {
InvoiceBL invoiceBl = new InvoiceBL(process.getInvoice().getId());
invoices.add(invoiceBl.getDTO());
} catch (Exception e) {
throw new SessionInternalError(e);
}
billingProcesses.add(process.getBillingProcess());
}
periodStr = getOrderPeriod().getDescription(languageId);
billingTypeStr = getOrderBillingType().getDescription(languageId);
statusStr = getOrderStatus().getDescription(languageId);
timeUnitStr = Util.getPeriodUnitStr(
getDueDateUnitId(), languageId);
currencySymbol = getCurrency().getSymbol();
currencyName = getCurrency().getDescription(languageId);
for (OrderLineDTO line : getLines()) {
line.addExtraFields(languageId);
}
}
@Transient
public Integer getPeriodId() {
return getOrderPeriod().getId();
}
@Transient
public Integer getUserId() {
return (getBaseUserByUserId() == null) ? null : getBaseUserByUserId().getId();
}
@Transient
public Integer getCreatedBy() {
return (getBaseUserByCreatedBy() == null) ? null : getBaseUserByCreatedBy().getId();
}
@Transient
public OrderLineDTO getLine(Integer itemId) {
for (OrderLineDTO line : lines) {
if (line.getDeleted() == 0 && line.getItem() != null && line.getItem().getId() == itemId) {
return line;
}
}
return null;
}
@Transient
public void removeLine(Integer itemId) {
OrderLineDTO line = getLine(itemId);
if (line != null) {
lines.remove(line);
}
}
@Transient
public boolean isEmpty() {
return lines.isEmpty();
}
@Transient
public int getNumberOfLines() {
int count = 0;
for (OrderLineDTO line: getLines()) {
if (line.getDeleted() == 0) {
count++;
}
}
return count;
}
@Transient
public List<PricingField> getPricingFields() {
return this.pricingFields;
}
public void setPricingFields(List<PricingField> fields) {
this.pricingFields = fields;
}
// default values
@Transient
public void setDefaults() {
if (getCreateDate() == null) {
setCreateDate(Calendar.getInstance().getTime());
setDeleted(0);
}
if (getOrderStatus() == null) {
setOrderStatus(new OrderStatusDAS().find(
Constants.ORDER_STATUS_ACTIVE));
}
for (OrderLineDTO line : lines) {
line.setDefaults();
}
}
/**
* Makes sure that all the proxies are loaded, so no session is needed to
* use the pojo
*/
public void touch() {
getActiveSince();
if (getBaseUserByUserId() != null)
getBaseUserByUserId().getCreateDatetime();
if (getBaseUserByCreatedBy() != null)
getBaseUserByCreatedBy().getCreateDatetime();
for (OrderLineDTO line: getLines()) {
line.touch();
}
for (InvoiceDTO invoice: getInvoices()) {
invoice.getCreateDatetime();
}
for (OrderProcessDTO process: getOrderProcesses()) {
process.getPeriodStart();
}
if (getOrderBillingType() != null)
getOrderBillingType().getId();
if (getOrderPeriod() != null)
getOrderPeriod().getId();
if (getOrderStatus() != null)
getOrderStatus().getId();
}
@Override
public String toString() {
StringBuffer str = new StringBuffer("Order = " +
"id=" + id + "," +
"baseUserByUserId=" + ((baseUserByUserId == null) ? null : baseUserByUserId.getId()) + "," +
"baseUserByCreatedBy=" + ((baseUserByCreatedBy== null) ? null : baseUserByCreatedBy.getId()) + "," +
"currencyDTO=" + currencyDTO + "," +
"orderStatusDTO=" + ((orderStatusDTO == null) ? null : orderStatusDTO) + "," +
"orderPeriodDTO=" + ((orderPeriodDTO == null) ? null : orderPeriodDTO) + "," +
"orderBillingTypeDTO=" + ((orderBillingTypeDTO == null) ? null : orderBillingTypeDTO) + "," +
"activeSince=" + activeSince + "," +
"activeUntil=" + activeUntil + "," +
"createDate=" + createDate + "," +
"nextBillableDay=" + nextBillableDay + "," +
"deleted=" + deleted + "," +
"notify=" + notify + "," +
"lastNotified=" + lastNotified + "," +
"notificationStep=" + notificationStep + "," +
"dueDateUnitId=" + dueDateUnitId + "," +
"dueDateValue=" + dueDateValue + "," +
"dfFm=" + dfFm + "," +
"anticipatePeriods=" + anticipatePeriods + "," +
"ownInvoice=" + ownInvoice + "," +
"notes=" + notes + "," +
"notesInInvoice=" + notesInInvoice + "," +
"orderProcesses=" + orderProcesses + "," +
"isCurrent=" + isCurrent + "," +
"versionNum=" + versionNum +
" lines:[");
for (OrderLineDTO line: getLines()) {
str.append(line.toString() + "-");
}
str.append("]");
return str.toString();
}
@Transient
public String[] getFieldNames() {
return new String[] {
"id",
"userId",
"userName",
"status",
"period",
"billingType",
"currency",
"total",
"activeSince",
"activeUntil",
"cycleStart",
"createdDate",
"nextBillableDay",
"isMainSubscription",
"notes",
// order lines
"lineItemId",
"lineProductCode",
"lineQuantity",
"linePrice",
"lineAmount",
"lineDescription"
};
}
@Transient
public Object[][] getFieldValues() {
List<Object[]> values = new ArrayList<Object[]>();
// main invoice row
values.add(
new Object[] {
id,
(baseUserByUserId != null ? baseUserByUserId.getId() : null),
(baseUserByUserId != null ? baseUserByUserId.getUserName() : null),
(orderStatusDTO != null ? orderStatusDTO.getDescription() : null),
(orderPeriodDTO != null ? orderPeriodDTO.getDescription() : null),
(orderBillingTypeDTO != null ? orderBillingTypeDTO.getDescription() : null),
(currencyDTO != null ? currencyDTO.getDescription() : null),
getTotal(),
activeSince,
activeUntil,
cycleStarts,
createDate,
nextBillableDay,
isCurrent,
notes
}
);
// indented row for each order line
for (OrderLineDTO line : lines) {
if (line.getDeleted() == 0) {
values.add(
new Object[] {
// padding for the main invoice columns
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
// order line
line.getItem().getId(),
line.getItem().getInternalNumber(),
line.getQuantity(),
line.getPrice(),
line.getAmount(),
line.getDescription()
}
);
}
}
return values.toArray(new Object[values.size()][]);
}
}