/*
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.invoice;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.MathContext;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.List;
import org.apache.log4j.Logger;
import javax.sql.rowset.CachedRowSet;
import com.sapienter.jbilling.common.SessionInternalError;
import com.sapienter.jbilling.server.invoice.db.InvoiceDAS;
import com.sapienter.jbilling.server.invoice.db.InvoiceDTO;
import com.sapienter.jbilling.server.invoice.db.InvoiceLineDAS;
import com.sapienter.jbilling.server.invoice.db.InvoiceLineDTO;
import com.sapienter.jbilling.server.item.CurrencyBL;
import com.sapienter.jbilling.server.item.ItemBL;
import com.sapienter.jbilling.server.list.ResultList;
import com.sapienter.jbilling.server.notification.INotificationSessionBean;
import com.sapienter.jbilling.server.notification.MessageDTO;
import com.sapienter.jbilling.server.notification.NotificationBL;
import com.sapienter.jbilling.server.notification.NotificationNotFoundException;
import com.sapienter.jbilling.server.order.OrderBL;
import com.sapienter.jbilling.server.order.db.OrderDTO;
import com.sapienter.jbilling.server.order.db.OrderProcessDAS;
import com.sapienter.jbilling.server.order.db.OrderProcessDTO;
import com.sapienter.jbilling.server.payment.PaymentBL;
import com.sapienter.jbilling.server.payment.db.PaymentInvoiceMapDAS;
import com.sapienter.jbilling.server.payment.db.PaymentInvoiceMapDTO;
import com.sapienter.jbilling.server.process.db.BillingProcessDTO;
import com.sapienter.jbilling.server.system.event.EventManager;
import com.sapienter.jbilling.server.user.ContactBL;
import com.sapienter.jbilling.server.user.EntityBL;
import com.sapienter.jbilling.server.user.UserBL;
import com.sapienter.jbilling.server.user.db.CompanyDAS;
import com.sapienter.jbilling.server.user.db.CompanyDTO;
import com.sapienter.jbilling.server.util.Constants;
import com.sapienter.jbilling.server.util.Context;
import com.sapienter.jbilling.server.util.PreferenceBL;
import com.sapienter.jbilling.server.util.Util;
import com.sapienter.jbilling.server.util.audit.EventLogger;
import java.util.ArrayList;
import org.springframework.dao.EmptyResultDataAccessException;
public class InvoiceBL extends ResultList implements Serializable, InvoiceSQL {
private InvoiceDAS invoiceDas = null;
private InvoiceDTO invoice = null;
private static final Logger LOG = Logger.getLogger(InvoiceBL.class);
private EventLogger eLogger = null;
public InvoiceBL(Integer invoiceId) {
init();
set(invoiceId);
}
public InvoiceBL() {
init();
}
public InvoiceBL(InvoiceDTO invoice) {
init();
set(invoice.getId());
}
private void init() {
eLogger = EventLogger.getInstance();
invoiceDas = new InvoiceDAS();
}
public InvoiceDTO getEntity() {
return invoice;
}
public InvoiceDAS getHome() {
return invoiceDas;
}
public void set(Integer id) {
invoice = invoiceDas.find(id);
}
public void set(InvoiceDTO invoice) {
this.invoice = invoice;
}
/**
*
* @param userId
* @param newInvoice
* @param process
* It can be null.
*/
public void create(Integer userId, NewInvoiceDTO newInvoice,
BillingProcessDTO process) {
// find out the entity id
PreferenceBL pref = new PreferenceBL();
UserBL user = null;
Integer entityId;
if (process != null) {
entityId = process.getEntity().getId();
} else {
// this is a manual invoice, there's no billing process
user = new UserBL(userId);
entityId = user.getEntityId(userId);
}
// verify if this entity is using the 'continuous invoice date'
// preference
try {
pref.set(entityId, Constants.PREFERENCE_CONTINUOUS_DATE);
Date lastDate = com.sapienter.jbilling.common.Util.parseDate(pref.getString());
if (lastDate.after(newInvoice.getBillingDate())) {
newInvoice.setBillingDate(lastDate);
} else {
// update the lastest date only if this is not a review
if (newInvoice.getIsReview() == null || newInvoice.getIsReview().intValue() == 0) {
pref.createUpdateForEntity(entityId,
Constants.PREFERENCE_CONTINUOUS_DATE,
com.sapienter.jbilling.common.Util.parseDate(newInvoice.getBillingDate()));
}
}
} catch (EmptyResultDataAccessException e) {
// not interested, ignore
}
// in any case, ensure that the due date is => that invoice date
if (newInvoice.getDueDate().before(newInvoice.getBillingDate())) {
newInvoice.setDueDate(newInvoice.getBillingDate());
}
// ensure that there are only two decimals in the invoice
if (newInvoice.getTotal() != null) {
newInvoice.setTotal(newInvoice.getTotal().setScale(Constants.BIGDECIMAL_SCALE, Constants.BIGDECIMAL_ROUND));
}
if (newInvoice.getBalance() != null) {
newInvoice.setBalance(newInvoice.getBalance().setScale(Constants.BIGDECIMAL_SCALE, Constants.BIGDECIMAL_ROUND));
}
// create the invoice row
invoice = invoiceDas.create(userId, newInvoice, process);
// add delegated/included invoice links
if (newInvoice.getIsReview() == 0) {
for (InvoiceDTO dto : newInvoice.getInvoices()) {
dto.setInvoice(invoice);
}
}
// add the customer notes if it applies
try {
pref.set(entityId, Constants.PREFERENCE_SHOW_NOTE_IN_INVOICE);
} catch (EmptyResultDataAccessException e) {
// use the default then
}
if (pref.getInt() == 1) {
if (user == null) {
user = new UserBL(userId);
}
if (user.getEntity().getCustomer() != null && user.getEntity().getCustomer().getNotes() != null) {
// append the notes if there's some text already there
newInvoice.setCustomerNotes((newInvoice.getCustomerNotes() == null) ? user.getEntity().getCustomer().getNotes()
: newInvoice.getCustomerNotes() + " " + user.getEntity().getCustomer().getNotes());
}
}
// notes might come from the customer, the orders, or both
if (newInvoice.getCustomerNotes() != null && newInvoice.getCustomerNotes().length() > 0) {
invoice.setCustomerNotes(newInvoice.getCustomerNotes());
}
// calculate/compose the number
String numberStr = null;
if (newInvoice.getIsReview() != null && newInvoice.getIsReview().intValue() == 1) {
// invoices for review will be seen by the entity employees
// so the entity locale will be used
EntityBL entity = new EntityBL(entityId);
ResourceBundle bundle = ResourceBundle.getBundle(
"entityNotifications", entity.getLocale());
numberStr = bundle.getString("invoice.review.number");
} else if (newInvoice.getPublicNumber() == null || newInvoice.getPublicNumber().length() == 0) {
String prefix;
try {
pref.set(entityId, Constants.PREFERENCE_INVOICE_PREFIX);
prefix = pref.getString();
if (prefix == null) {
prefix = "";
}
} catch (EmptyResultDataAccessException e) {
prefix = "";
}
int number;
try {
pref.set(entityId, Constants.PREFERENCE_INVOICE_NUMBER);
number = pref.getInt();
} catch (EmptyResultDataAccessException e1) {
number = 1;
}
numberStr = prefix + number;
// update for the next time
number++;
pref.createUpdateForEntity(entityId, Constants.PREFERENCE_INVOICE_NUMBER, number);
} else { // for upload of legacy invoices
numberStr = newInvoice.getPublicNumber();
}
invoice.setPublicNumber(numberStr);
// set the invoice's contact info with the current user's primary
ContactBL contact = new ContactBL();
contact.set(userId);
contact.createForInvoice(contact.getDTO(), invoice.getId());
// add a log row for convenience
eLogger.auditBySystem(entityId, userId, Constants.TABLE_INVOICE,
invoice.getId(), EventLogger.MODULE_INVOICE_MAINTENANCE,
EventLogger.ROW_CREATED, null, null, null);
}
public void createLines(NewInvoiceDTO newInvoice) {
Collection invoiceLines = invoice.getInvoiceLines();
// Now create all the invoice lines, from the lines in the DTO
// put there by the invoice composition pluggable tasks
InvoiceLineDAS invoiceLineDas = new InvoiceLineDAS();
// get the result DTO lines
Iterator dueInvoiceLines = newInvoice.getResultLines().iterator();
// go over the DTO lines, creating one invoice line for each
while (dueInvoiceLines.hasNext()) {
InvoiceLineDTO lineToAdd = (InvoiceLineDTO) dueInvoiceLines.next();
// define if the line is a percentage or not
lineToAdd.setIsPercentage(new Integer(0));
if (lineToAdd.getItem() != null) {
try {
ItemBL item = new ItemBL(lineToAdd.getItem());
if (item.getEntity().getPercentage() != null) {
lineToAdd.setIsPercentage(new Integer(1));
}
} catch (SessionInternalError e) {
LOG.error("Could not find item to create invoice line " + lineToAdd.getItem().getId());
}
}
// create the database row
InvoiceLineDTO newLine = invoiceLineDas.create(lineToAdd.getDescription(), lineToAdd.getAmount(), lineToAdd.getQuantity(), lineToAdd.getPrice(),
lineToAdd.getTypeId(), lineToAdd.getItem(), lineToAdd.getSourceUserId(), lineToAdd.getIsPercentage());
// update the invoice-lines relationship
newLine.setInvoice(invoice);
invoiceLines.add(newLine);
}
getHome().save(invoice);
EventManager.process(new NewInvoiceEvent(invoice));
}
/**
* This will remove all the records (sql delete, not just flag them). It
* will also update the related orders if applicable
*/
public void delete(Integer executorId) throws SessionInternalError {
if (invoice == null) {
throw new SessionInternalError("An invoice has to be set before " + "delete");
}
// start by updating purchase_order.next_billable_day if applicatble
// for each of the orders included in this invoice
for (OrderProcessDTO orderProcess : (Collection<OrderProcessDTO>) invoice.getOrderProcesses()) {
OrderDTO order = orderProcess.getPurchaseOrder();
if (order.getNextBillableDay() == null) {
// the next billable day doesn't need updating
if (order.getStatusId().equals(Constants.ORDER_STATUS_FINISHED)) {
OrderBL orderBL = new OrderBL(order);
orderBL.setStatus(null, Constants.ORDER_STATUS_ACTIVE);
}
continue;
}
// only if this invoice is the responsible for the order's
// next billable day
if (order.getNextBillableDay().equals(orderProcess.getPeriodEnd())) {
order.setNextBillableDay(orderProcess.getPeriodStart());
if (order.getStatusId().equals(Constants.ORDER_STATUS_FINISHED)) {
OrderBL orderBL = new OrderBL(order);
orderBL.setStatus(null, Constants.ORDER_STATUS_ACTIVE);
}
}
}
// go over the order process records again just to delete them
// we are done with this order, delete the process row
for (OrderProcessDTO orderProcess : (Collection<OrderProcessDTO>) invoice.getOrderProcesses()) {
OrderDTO order = orderProcess.getPurchaseOrder();
OrderProcessDAS das = new OrderProcessDAS();
order.getOrderProcesses().remove(orderProcess);
das.delete(orderProcess);
}
invoice.getOrderProcesses().clear();
// get rid of the contact associated with this invoice
try {
ContactBL contact = new ContactBL();
if (contact.setInvoice(invoice.getId())) {
contact.delete();
}
} catch (Exception e1) {
LOG.error("Exception deleting the contact of an invoice", e1);
}
// remove the payment link/s
PaymentBL payment = new PaymentBL();
Iterator<PaymentInvoiceMapDTO> it = invoice.getPaymentMap().iterator();
while (it.hasNext()) {
PaymentInvoiceMapDTO map = it.next();
payment.removeInvoiceLink(map.getId());
invoice.getPaymentMap().remove(map);
// needed because the collection has changed
it = invoice.getPaymentMap().iterator();
}
// log that this was deleted, otherwise there will be no trace
if (executorId != null) {
eLogger.audit(executorId, invoice.getBaseUser().getId(),
Constants.TABLE_INVOICE, invoice.getId(),
EventLogger.MODULE_INVOICE_MAINTENANCE,
EventLogger.ROW_DELETED, null, null, null);
}
// before delete the invoice most delete the reference in table
// PAYMENT_INVOICE
new PaymentInvoiceMapDAS().deleteAllWithInvoice(invoice);
// now delete the invoice itself
getHome().delete(invoice);
getHome().flush();
}
public void update(NewInvoiceDTO addition) {
// add the lines to the invoice first
createLines(addition);
// update the inoice record considering the new lines
invoice.setTotal(calculateTotal()); // new total
// adjust the balance
addition.calculateTotal();
BigDecimal balance = invoice.getBalance();
balance = balance.add(addition.getTotal());
invoice.setBalance(balance);
//? if (invoice.getBalance().floatValue() <= 0.001F) {
if (invoice.getBalance().compareTo(BigDecimal.ZERO) == 0) {
invoice.setToProcess(new Integer(0));
}
}
private BigDecimal calculateTotal() {
BigDecimal total = new BigDecimal(0);
for (Iterator it = invoice.getInvoiceLines().iterator(); it.hasNext();) {
InvoiceLineDTO line = (InvoiceLineDTO) it.next();
total = total.add(line.getAmount());
}
return total;
}
public CachedRowSet getPayableInvoicesByUser(Integer userId)
throws SQLException, Exception {
prepareStatement(InvoiceSQL.payableByUser);
cachedResults.setInt(1, userId.intValue());
execute();
conn.close();
return cachedResults;
}
public BigDecimal getTotalPaid() {
BigDecimal retValue = new BigDecimal(0);
for (Iterator<PaymentInvoiceMapDTO> it = invoice.getPaymentMap().iterator(); it.hasNext();) {
PaymentInvoiceMapDTO paymentMap = it.next();
retValue = retValue.add(paymentMap.getAmount());
}
return retValue;
}
public CachedRowSet getList(Integer orderId) throws SQLException, Exception {
prepareStatement(InvoiceSQL.customerList);
// find out the user from the order
Integer userId;
OrderBL order = new OrderBL(orderId);
if (order.getEntity().getUser().getCustomer().getParent() == null) {
userId = order.getEntity().getUser().getUserId();
} else {
userId = order.getEntity().getUser().getCustomer().getParent().getBaseUser().getUserId();
}
cachedResults.setInt(1, userId.intValue());
execute();
conn.close();
return cachedResults;
}
public CachedRowSet getList(Integer entityId, Integer userRole,
Integer userId) throws SQLException, Exception {
if (userRole.equals(Constants.TYPE_INTERNAL)) {
prepareStatement(InvoiceSQL.internalList);
} else if (userRole.equals(Constants.TYPE_ROOT) || userRole.equals(Constants.TYPE_CLERK)) {
prepareStatement(InvoiceSQL.rootClerkList);
cachedResults.setInt(1, entityId.intValue());
} else if (userRole.equals(Constants.TYPE_PARTNER)) {
prepareStatement(InvoiceSQL.partnerList);
cachedResults.setInt(1, entityId.intValue());
cachedResults.setInt(2, userId.intValue());
} else if (userRole.equals(Constants.TYPE_CUSTOMER)) {
prepareStatement(InvoiceSQL.customerList);
cachedResults.setInt(1, userId.intValue());
} else {
throw new Exception("The invoice list for the type " + userRole + " is not supported");
}
execute();
conn.close();
return cachedResults;
}
public CachedRowSet getInvoicesByProcessId(Integer processId)
throws SQLException, Exception {
prepareStatement(InvoiceSQL.processList);
cachedResults.setInt(1, processId.intValue());
execute();
conn.close();
return cachedResults;
}
public CachedRowSet getInvoicesToPrintByProcessId(Integer processId)
throws SQLException, Exception {
prepareStatement(InvoiceSQL.processPrintableList);
cachedResults.setInt(1, processId.intValue());
execute();
conn.close();
return cachedResults;
}
public CachedRowSet getInvoicesByUserId(Integer userId)
throws SQLException, Exception {
prepareStatement(InvoiceSQL.custList);
cachedResults.setInt(1, userId.intValue());
execute();
conn.close();
return cachedResults;
}
public CachedRowSet getInvoicesByIdRange(Integer from, Integer to,
Integer entityId) throws SQLException, Exception {
prepareStatement(InvoiceSQL.rangeList);
cachedResults.setInt(1, from.intValue());
cachedResults.setInt(2, to.intValue());
cachedResults.setInt(3, entityId.intValue());
execute();
conn.close();
return cachedResults;
}
public Integer[] getInvoicesByCreateDateArray(Integer entityId, Date since,
Date until) throws SQLException, Exception {
cachedResults = getInvoicesByCreateDate(entityId, since, until);
// get ids for return
List ids = new ArrayList();
while (cachedResults.next()) {
ids.add(new Integer(cachedResults.getInt(1)));
}
Integer[] retValue = new Integer[ids.size()];
if (retValue.length > 0) {
ids.toArray(retValue);
}
return retValue;
}
public CachedRowSet getInvoicesByCreateDate(Integer entityId, Date since,
Date until) throws SQLException, Exception {
prepareStatement(InvoiceSQL.getByDate);
cachedResults.setInt(1, entityId.intValue());
cachedResults.setDate(2, new java.sql.Date(since.getTime()));
// add a day to include the until date
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(until);
cal.add(GregorianCalendar.DAY_OF_MONTH, 1);
cachedResults.setDate(3, new java.sql.Date(cal.getTime().getTime()));
execute();
conn.close();
return cachedResults;
}
public Integer convertNumberToID(Integer entityId, String number)
throws SQLException, Exception {
prepareStatement(InvoiceSQL.getIDfromNumber);
cachedResults.setInt(1, entityId.intValue());
cachedResults.setString(2, number);
execute();
conn.close();
if (cachedResults.wasNull()) {
return null;
} else {
cachedResults.next();
return new Integer(cachedResults.getInt(1));
}
}
public Integer getLastByUser(Integer userId) throws SQLException {
Integer retValue = null;
if (userId == null) {
return null;
}
prepareStatement(InvoiceSQL.lastIdbyUser);
cachedResults.setInt(1, userId.intValue());
execute();
if (cachedResults.next()) {
int value = cachedResults.getInt(1);
if (!cachedResults.wasNull()) {
retValue = new Integer(value);
}
}
conn.close();
return retValue;
}
public Integer getLastByUserAndItemType(Integer userId, Integer itemTypeId)
throws SQLException {
Integer retValue = null;
if (userId == null) {
return null;
}
prepareStatement(InvoiceSQL.lastIdbyUserAndItemType);
cachedResults.setInt(1, userId.intValue());
cachedResults.setInt(2, itemTypeId.intValue());
execute();
if (cachedResults.next()) {
int value = cachedResults.getInt(1);
if (!cachedResults.wasNull()) {
retValue = new Integer(value);
}
}
cachedResults.close();
conn.close();
return retValue;
}
public Boolean isUserWithOverdueInvoices(Integer userId, Date today,
Integer excludeInvoiceId) throws SQLException {
Boolean retValue;
prepareStatement(InvoiceSQL.getOverdueForAgeing);
cachedResults.setDate(1, new java.sql.Date(today.getTime()));
cachedResults.setInt(2, userId.intValue());
if (excludeInvoiceId != null) {
cachedResults.setInt(3, excludeInvoiceId.intValue());
} else {
// nothing to exclude, use an imposible ID (zero)
cachedResults.setInt(3, 0);
}
execute();
if (cachedResults.next()) {
retValue = new Boolean(true);
LOG.debug("user with invoice:" + cachedResults.getInt(1));
} else {
retValue = new Boolean(false);
}
conn.close();
LOG.debug("user with overdue: " + retValue);
return retValue;
}
public Integer[] getUsersOverdueInvoices(Integer userId, Date date) {
List<Integer> result = new InvoiceDAS().findIdsOverdueForUser(userId, date);
return result.toArray(new Integer[result.size()]);
}
public Integer[] getUserInvoicesByDate(Integer userId, Date since,
Date until) {
// add a day to include the until date
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(until);
cal.add(GregorianCalendar.DAY_OF_MONTH, 1);
until = cal.getTime();
List<Integer> result = new InvoiceDAS().findIdsByUserAndDate(
userId, since, until);
return result.toArray(new Integer[result.size()]);
}
public Integer[] getManyWS(Integer userId, Integer number)
throws SessionInternalError {
List<Integer> result = new InvoiceDAS().findIdsByUserLatestFirst(
userId, number);
return result.toArray(new Integer[result.size()]);
}
public Integer[] getManyByItemTypeWS(Integer userId, Integer itemTypeId, Integer number)
throws SessionInternalError {
List<Integer> result = new InvoiceDAS().findIdsByUserAndItemTypeLatestFirst(userId, itemTypeId, number);
return result.toArray(new Integer[result.size()]);
}
public InvoiceWS[] DTOtoWS(List dtos) {
InvoiceWS retValue[] = new InvoiceWS[dtos.size()];
for (int f = 0; f < retValue.length; f++) {
retValue[f] = InvoiceBL.getWS((InvoiceDTO) dtos.get(f));
}
LOG.debug("converstion " + retValue.length);
return retValue;
}
public void sendReminders(Date today) throws SQLException,
SessionInternalError {
GregorianCalendar cal = new GregorianCalendar();
for (Iterator it = new CompanyDAS().findEntities().iterator(); it.hasNext();) {
CompanyDTO thisEntity = (CompanyDTO) it.next();
Integer entityId = thisEntity.getId();
PreferenceBL pref = new PreferenceBL();
try {
pref.set(entityId, Constants.PREFERENCE_USE_INVOICE_REMINDERS);
} catch (EmptyResultDataAccessException e1) {
// let it use the defaults
}
if (pref.getInt() == 1) {
prepareStatement(InvoiceSQL.toRemind);
cachedResults.setDate(1, new java.sql.Date(today.getTime()));
cal.setTime(today);
pref.set(entityId, Constants.PREFERENCE_FIRST_REMINDER);
cal.add(GregorianCalendar.DAY_OF_MONTH, -pref.getInt());
cachedResults.setDate(2, new java.sql.Date(cal.getTimeInMillis()));
cal.setTime(today);
pref.set(entityId, Constants.PREFERENCE_NEXT_REMINDER);
cal.add(GregorianCalendar.DAY_OF_MONTH, -pref.getInt());
cachedResults.setDate(3, new java.sql.Date(cal.getTimeInMillis()));
cachedResults.setInt(4, entityId.intValue());
execute();
while (cachedResults.next()) {
int invoiceId = cachedResults.getInt(1);
set(new Integer(invoiceId));
NotificationBL notif = new NotificationBL();
long mils = invoice.getDueDate().getTime() - today.getTime();
int days = Math.round(mils / 1000 / 60 / 60 / 24);
try {
MessageDTO message = notif.getInvoiceRemainderMessage(
entityId, invoice.getBaseUser().getUserId(),
new Integer(days), invoice.getDueDate(),
invoice.getPublicNumber(), invoice.getTotal(),
invoice.getCreateDatetime(), invoice.getCurrency().getId());
INotificationSessionBean notificationSess =
(INotificationSessionBean) Context.getBean(
Context.Name.NOTIFICATION_SESSION);
notificationSess.notify(invoice.getBaseUser(), message);
invoice.setLastReminder(today);
} catch (NotificationNotFoundException e) {
LOG.warn("There are invoice to send reminders, but " + "the notification message is missing for " + "entity " + entityId);
}
}
}
}
if (conn != null) { // only if somthing run
conn.close();
}
}
public InvoiceWS getWS() {
return getWS(invoice);
}
public static InvoiceWS getWS(InvoiceDTO i) {
if (i == null) {
return null;
}
InvoiceWS retValue = new InvoiceWS();
retValue.setId(i.getId());
retValue.setCreateDateTime(i.getCreateDatetime());
retValue.setCreateTimeStamp(i.getCreateTimestamp());
retValue.setLastReminder(i.getLastReminder());
retValue.setDueDate(i.getDueDate());
retValue.setTotal(i.getTotal());
retValue.setToProcess(i.getToProcess());
retValue.setStatusId(i.getInvoiceStatus().getId());
retValue.setBalance(i.getBalance());
retValue.setCarriedBalance(i.getCarriedBalance());
retValue.setInProcessPayment(i.getInProcessPayment());
retValue.setDeleted(i.getDeleted());
retValue.setPaymentAttempts(i.getPaymentAttempts());
retValue.setIsReview(i.getIsReview());
retValue.setCurrencyId(i.getCurrency().getId());
retValue.setCustomerNotes(i.getCustomerNotes());
retValue.setNumber(i.getPublicNumber());
retValue.setOverdueStep(i.getOverdueStep());
retValue.setUserId(i.getBaseUser().getId());
Integer delegatedInvoiceId = i.getInvoice() == null ? null : i.getInvoice().getId();
Integer userId = i.getBaseUser().getId();
Integer payments[] = new Integer[i.getPaymentMap().size()];
com.sapienter.jbilling.server.entity.InvoiceLineDTO invoiceLines[] =
new com.sapienter.jbilling.server.entity.InvoiceLineDTO[i.getInvoiceLines().size()];
Integer orders[] = new Integer[i.getOrderProcesses().size()];
int f;
f = 0;
for (PaymentInvoiceMapDTO p : i.getPaymentMap()) {
payments[f++] = p.getPayment().getId();
}
f = 0;
for (OrderProcessDTO orderP : i.getOrderProcesses()) {
orders[f++] = orderP.getPurchaseOrder().getId();
}
f = 0;
for (InvoiceLineDTO line : i.getInvoiceLines()) {
invoiceLines[f++] = new com.sapienter.jbilling.server.entity.InvoiceLineDTO(line.getId(),
line.getDescription(), line.getAmount(), line.getPrice(), line.getQuantity(),
line.getDeleted(), line.getItem() == null ? null : line.getItem().getId(),
line.getSourceUserId(), line.getIsPercentage());
}
retValue.setDelegatedInvoiceId(delegatedInvoiceId);
retValue.setUserId(userId);
retValue.setPayments(payments);
retValue.setInvoiceLines(invoiceLines);
retValue.setOrders(orders);
return retValue;
}
public InvoiceDTO getDTOEx(Integer languageId, boolean forDisplay) {
if (!forDisplay) {
return invoice;
}
InvoiceDTO invoiceDTO = new InvoiceDTO(invoice);
// make sure that the lines are properly ordered
List<InvoiceLineDTO> orderdLines = new ArrayList<InvoiceLineDTO>(invoiceDTO.getInvoiceLines());
Collections.sort(orderdLines, new InvoiceLineComparator());
invoiceDTO.setInvoiceLines(orderdLines);
UserBL userBl = new UserBL(invoice.getBaseUser());
Locale locale = userBl.getLocale();
ResourceBundle bundle = ResourceBundle.getBundle("entityNotifications", locale);
// now add headres and footers if this invoices has subaccount
// lines
if (invoiceDTO.hasSubAccounts()) {
addHeadersFooters(orderdLines, bundle);
}
// add a grand total final line
InvoiceLineDTO total = new InvoiceLineDTO();
total.setDescription(bundle.getString("invoice.line.total"));
total.setAmount(invoice.getTotal());
total.setIsPercentage(0);
invoiceDTO.getInvoiceLines().add(total);
// add some currency info for the human
CurrencyBL currency = new CurrencyBL(invoice.getCurrency().getId());
if (languageId != null) {
invoiceDTO.setCurrencyName(currency.getEntity().getDescription(
languageId));
}
invoiceDTO.setCurrencySymbol(currency.getEntity().getSymbol());
return invoiceDTO;
}
/**
* Will add lines with headers and footers to make an invoice with
* subaccounts more readable. The lines have to be already sorted.
*
* @param lines
*/
private void addHeadersFooters(List<InvoiceLineDTO> lines, ResourceBundle bundle) {
Integer nowProcessing = new Integer(-1);
BigDecimal total = null;
int totalLines = lines.size();
int subaccountNumber = 0;
LOG.debug("adding headers & footers." + totalLines);
for (int idx = 0; idx < totalLines; idx++) {
InvoiceLineDTO line = (InvoiceLineDTO) lines.get(idx);
if (line.getTypeId() == Constants.INVOICE_LINE_TYPE_SUB_ACCOUNT && !line.getSourceUserId().equals(nowProcessing)) {
// line break
nowProcessing = line.getSourceUserId();
subaccountNumber++;
// put the total first
if (total != null) { // it could be the first subaccount
InvoiceLineDTO totalLine = new InvoiceLineDTO();
totalLine.setDescription(bundle.getString("invoice.line.subAccount.footer"));
totalLine.setAmount(total);
lines.add(idx, totalLine);
idx++;
totalLines++;
}
total = BigDecimal.ZERO;
// now the header anouncing a new subaccout
InvoiceLineDTO headerLine = new InvoiceLineDTO();
try {
ContactBL contact = new ContactBL();
contact.set(nowProcessing);
StringBuffer text = new StringBuffer();
text.append(subaccountNumber + " - ");
text.append(bundle.getString("invoice.line.subAccount.header1"));
text.append(" " + bundle.getString("invoice.line.subAccount.header2") + " " + nowProcessing);
if (contact.getEntity().getFirstName() != null) {
text.append(" " + contact.getEntity().getFirstName());
}
if (contact.getEntity().getLastName() != null) {
text.append(" " + contact.getEntity().getLastName());
}
headerLine.setDescription(text.toString());
lines.add(idx, headerLine);
idx++;
totalLines++;
} catch (Exception e) {
LOG.error("Exception", e);
return;
}
}
// update the total
if (total != null) {
// there had been at least one sub-account processed
if (line.getTypeId() ==
Constants.INVOICE_LINE_TYPE_SUB_ACCOUNT) {
total = total.add(line.getAmount());
} else {
// this is the last total to display, from now on the
// lines are not of subaccounts
InvoiceLineDTO totalLine = new InvoiceLineDTO();
totalLine.setDescription(bundle.getString("invoice.line.subAccount.footer"));
totalLine.setAmount(total);
lines.add(idx, totalLine);
total = null; // to avoid repeating
}
}
}
// if there are no lines after the last subaccount, we need
// a total for it
if (total != null) { // only if it wasn't added before
InvoiceLineDTO totalLine = new InvoiceLineDTO();
totalLine.setDescription(bundle.getString("invoice.line.subAccount.footer"));
totalLine.setAmount(total);
lines.add(totalLine);
}
LOG.debug("done " + lines.size());
}
public InvoiceDTO getDTO() {
return invoice;
}
// given the current invoice, it will 'rewind' to the previous one
public void setPrevious() throws SQLException,
EmptyResultDataAccessException {
prepareStatement(InvoiceSQL.previous);
cachedResults.setInt(1, invoice.getBaseUser().getUserId().intValue());
cachedResults.setInt(2, invoice.getId());
boolean found = false;
execute();
if (cachedResults.next()) {
int value = cachedResults.getInt(1);
if (!cachedResults.wasNull()) {
set(new Integer(value));
found = true;
}
}
conn.close();
if (!found) {
throw new EmptyResultDataAccessException("No previous invoice found", 1);
}
}
/*
public static InvoiceWS getWS(InvoiceDTO dto) {
InvoiceWS ret = new InvoiceWS();
ret.setBalance(dto.getBalance());
ret.setCarriedBalance(dto.getCarriedBalance());
ret.setCreateDateTime(dto.getCreateDatetime());
ret.setCreateTimeStamp(dto.getCreateTimestamp());
ret.setCurrencyId(dto.getCurrency().getId());
ret.setCustomerNotes(dto.getCustomerNotes());
ret.setDelegatedInvoiceId(dto.getDelegatedInvoiceId());
ret.setDeleted(dto.getDeleted());
ret.setDueDate(dto.getDueDate());
ret.setInProcessPayment(dto.getInProcessPayment());
ret.setUserId(dto.getUserId());
ret.setIsReview(dto.getIsReview());
ret.setLastReminder(dto.getLastReminder());
ret.setNumber(dto.getPublicNumber());
ret.setOverdueStep(dto.getOverdueStep());
ret.setPaymentAttempts(dto.getOverdueStep());
ret.setToProcess(dto.getToProcess());
ret.setTotal(dto.getTotal());
ret.setUserId(dto.getUserId());
Integer payments[] = new Integer[dto.getPaymentMap().size()];
Integer orders[] = new Integer[dto.getOrders().size()];
int f;
for (f = 0; f < dto.getPaymentMap().size(); f++) {
PaymentInvoiceMapDTOEx map = (PaymentInvoiceMapDTOEx) dto.getPaymentMap().get(f);
payments[f] = map.getPaymentId();
}
ret.setPayments(payments);
for (f = 0; f < dto.getOrders().size(); f++) {
OrderDTO order = (OrderDTO) dto.getOrders().get(f);
orders[f] = order.getId();
}
ret.setOrders(orders);
com.sapienter.jbilling.server.entity.InvoiceLineDTO lines[] =
new com.sapienter.jbilling.server.entity.InvoiceLineDTO[dto.getInvoiceLines().size()];
f=0;
for (InvoiceLineDTO line : dto.getInvoiceLines()) {
lines[f++] = new com.sapienter.jbilling.server.entity.InvoiceLineDTO(line.getId(),
line.getDescription(), line.getAmount(), line.getPrice(), line.getQuantity(),
line.getDeleted(), line.getItem() == null ? null : line.getItem().getId(),
line.getSourceUserId(), line.getIsPercentage());
}
return ret;
}
* */
}