/*
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.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.List;
import org.apache.log4j.Logger;
import javax.sql.rowset.CachedRowSet;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PRAcroForm;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.SimpleBookmark;
import com.sapienter.jbilling.common.SessionInternalError;
import com.sapienter.jbilling.common.Util;
import com.sapienter.jbilling.server.process.db.PaperInvoiceBatchDTO;
import com.sapienter.jbilling.server.invoice.db.InvoiceDTO;
import com.sapienter.jbilling.server.notification.NotificationBL;
import com.sapienter.jbilling.server.process.BillingProcessBL;
import com.sapienter.jbilling.server.process.db.PaperInvoiceBatchDAS;
import com.sapienter.jbilling.server.util.Constants;
import com.sapienter.jbilling.server.util.PreferenceBL;
import com.sapienter.jbilling.server.util.audit.EventLogger;
/**
* @author Emil
*/
public class PaperInvoiceBatchBL {
private PaperInvoiceBatchDTO batch = null;
private static final Logger LOG = Logger.getLogger(PaperInvoiceBatchBL.class);
private EventLogger eLogger = null;
private PaperInvoiceBatchDAS batchHome = null;
public PaperInvoiceBatchBL(Integer batchId) {
init();
set(batchId);
}
public PaperInvoiceBatchBL(PaperInvoiceBatchDTO batch) {
init();
this.batch = batch;
}
public PaperInvoiceBatchBL() {
init();
}
private void init() {
eLogger = EventLogger.getInstance();
batchHome = new PaperInvoiceBatchDAS();
}
public PaperInvoiceBatchDTO getEntity() {
return batch;
}
public void set(Integer id) {
batch = batchHome.find(id);
}
/**
* This method will create a record if there's none for the given
* process id, otherwise it will return the existing one
* @param processId
* @return
*/
public PaperInvoiceBatchDTO createGet(Integer processId) {
BillingProcessBL process = new BillingProcessBL(processId);
batch = process.getEntity().getPaperInvoiceBatch();
if (batch == null) {
PreferenceBL preference = new PreferenceBL();
preference.set(process.getEntity().getEntity().getId(),
Constants.PREFERENCE_PAPER_SELF_DELIVERY);
batch = batchHome.create(new Integer(0), preference.getEntity().getIntValue());
process.getEntity().setPaperInvoiceBatch(batch);
}
return batch;
}
/**
* Will take all the files generated by the process and 'paste' them
* into a big one, deleting the originals.
* This then will facilitate the printing of a batch.
*/
public void compileInvoiceFilesForProcess(Integer entityId)
throws DocumentException, IOException {
String filePrefix = Util.getSysProp("base_dir") + "invoices/" +
entityId + "-";
// now go through each of the invoices
// first - sort them
List invoices = new ArrayList(batch.getInvoices());
Collections.sort(invoices, new InvoiceEntityComparator());
Integer[] invoicesIds = new Integer[invoices.size()];
for (int f = 0; f < invoices.size(); f++) {
InvoiceDTO invoice = (InvoiceDTO) invoices.get(f);
invoicesIds[f] = invoice.getId();
}
compileInvoiceFiles(filePrefix, new Integer(batch.getId()).toString(), entityId,
invoicesIds);
}
/**
* Takes a list of invoices and replaces the individual PDF files for one
* single PDF in the destination directory.
* @param destination
* @param prefix
* @param entityId
* @param invoices
* @throws PdfFormatException
* @throws IOException
*/
public void compileInvoiceFiles(String destination, String prefix,
Integer entityId, Integer[] invoices)
throws DocumentException, IOException {
String filePrefix = Util.getSysProp("base_dir") + "invoices/"
+ entityId + "-";
String outFile = destination + prefix + "-batch.pdf";
int pageOffset = 0;
ArrayList master = new ArrayList();
Document document = null;
PdfCopy writer = null;
for(int f = 0; f < invoices.length ; f++) {
// we create a reader for a certain document
PdfReader reader = new PdfReader(filePrefix + invoices[f] + "-invoice.pdf");
reader.consolidateNamedDestinations();
// we retrieve the total number of pages
int numberOfPages = reader.getNumberOfPages();
List bookmarks = SimpleBookmark.getBookmark(reader);
if (bookmarks != null) {
if (pageOffset != 0)
SimpleBookmark.shiftPageNumbers(bookmarks, pageOffset, null);
master.addAll(bookmarks);
}
pageOffset += numberOfPages;
if (f == 0) {
// step 1: creation of a document-object
document = new Document(reader.getPageSizeWithRotation(1));
// step 2: we create a writer that listens to the document
writer = new PdfCopy(document, new FileOutputStream(outFile));
// step 3: we open the document
document.open();
}
// step 4: we add content
PdfImportedPage page;
for (int i = 0; i < numberOfPages; ) {
++i;
page = writer.getImportedPage(reader, i);
writer.addPage(page);
}
PRAcroForm form = reader.getAcroForm();
if (form != null)
writer.copyAcroForm(reader);
//release and delete
writer.freeReader(reader);
reader.close();
File file = new File(filePrefix + invoices[f] + "-invoice.pdf");
file.delete();
}
if (!master.isEmpty())
writer.setOutlines(master);
// step 5: we close the document
if (document != null) {
document.close();
} else {
LOG.warn("document == null");
}
LOG.debug("PDF batch file is ready " + outFile);
}
public void sendEmail() {
Integer entityId = batch.getProcess().getEntity().getId();
PreferenceBL prefBL = new PreferenceBL();
prefBL.set(entityId, Constants.PREFERENCE_PAPER_SELF_DELIVERY);
Boolean selfDelivery = new Boolean(prefBL.getInt() == 1);
// If the entity doesn't want to delivery the invoices, then
// sapienter has to. Entity 1 is always sapienter.
Integer pritingEntity;
if (!selfDelivery.booleanValue()) {
pritingEntity = new Integer(1);
} else {
pritingEntity = entityId;
}
try {
NotificationBL.sendSapienterEmail(pritingEntity, "invoice_batch",
Util.getSysProp("base_dir") + "invoices/" + entityId +
"-" + batch.getId() + "-batch.pdf", null);
} catch (Exception e) {
LOG.error("Could no send the email with the paper invoices " +
"for entity " + entityId, e);
}
}
public String generateFile(CachedRowSet cachedRowSet, Integer entityId,
String realPath) throws SQLException,
SessionInternalError, DocumentException,
IOException {
NotificationBL notif = new NotificationBL();
List invoices = new ArrayList();
int generated = 0;
while (cachedRowSet.next()) {
Integer invoiceId = new Integer(cachedRowSet.getInt(1));
InvoiceBL invoice = new InvoiceBL(invoiceId);
LOG.debug("Generating paper invoice " + invoiceId);
notif.generatePaperInvoiceAsFile(invoice.getEntity());
invoices.add(invoiceId);
// no more than 1000 invoices at a time, please
generated++;
if (generated >= 1000) break;
}
if (generated > 0) {
// merge all these files into a single one
String hash = String.valueOf(System.currentTimeMillis());
Integer[] invoicesIds = new Integer[invoices.size()];
invoices.toArray(invoicesIds);
compileInvoiceFiles(realPath.substring(0,
realPath.indexOf("_FILE_NAME_")) + "/",
entityId + "-" + hash, entityId, invoicesIds);
return entityId + "-" + hash + "-batch.pdf";
} else {
// there was no rows in that query ...
return null;
}
}
}