hotfix: invoice excel and pdf

pull/8040/head
Gauthier LO 2025-02-21 11:14:08 +01:00
parent 6baf1d4d9b
commit 1093c50c80
6 changed files with 262 additions and 17 deletions

View File

@ -1231,4 +1231,56 @@ public class InvoiceController {
}
}
}
@PostMapping("/makeShippingTest")
public Result<?> createShippingTestInvoice(@RequestBody int nbOfLines) throws UserException {
InvoiceMetaData metaData;
if(nbOfLines < 5)
throw new UserException("Number of lines must be at least 5");
try {
metaData = shippingInvoiceService.makeShippingInvoiceTest(nbOfLines);
return Result.OK(metaData);
} catch (UserException e) {
return Result.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
return Result.error("Sorry, server error, please try later");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@PostMapping("/makePurchaseTest")
public Result<?> createPurchaseTestInvoice(@RequestBody int nbOfLines) throws UserException {
InvoiceMetaData metaData;
if(nbOfLines < 5)
throw new UserException("Number of lines must be at least 5");
try {
metaData = purchaseOrderService.makeInvoiceTest(nbOfLines);
return Result.OK(metaData);
} catch (UserException e) {
return Result.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
return Result.error("Sorry, server error, please try later");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
@PostMapping("/makeCompleteTest")
public Result<?> createCompleteTestInvoice(@RequestBody int nbOfLines) throws UserException {
InvoiceMetaData metaData;
if(nbOfLines < 5)
throw new UserException("Number of lines must be at least 5");
try {
metaData = shippingInvoiceService.makeCompleteInvoiceTest(nbOfLines);
return Result.OK(metaData);
} catch (UserException e) {
return Result.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
return Result.error("Sorry, server error, please try later");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -161,6 +161,14 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
org.apache.poi.ss.usermodel.Row sourceRow = sheet.getRow(FIRST_ROW);
int footerRow = TOTAL_ROW + 1; // la ligne à laquelle le footer commence (1 ligne avant le total)
int imgShift = additionalRowNum; // le nombre de ligne qu'on va décaler les images (signatures et tampon)
/**
* 1 : data.size() <= dataRowNumber + 1 -> only a few lines of data
* 2 : data fits in one page but not enough space for footer
* 3 : data fits in one page and enough space for footer
* 4 : data doesn't fit in one page and not enough space for footer
* 5 : data doesn't fit in one page and enough space for footer
*/
int situation = 1;
if(data.size() > dataRowNumber + 1)
{
int startRow = LAST_ROW+1;
@ -174,33 +182,37 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
if(TOTAL_ROW > LAST_ROW + 3) { // s'il ne reste pas assez de place pour le footer
// on shift le footer à la page suivante (total + signature etc..)
sheet.shiftRows(startRow, fileLastRow, PAGE_ROW_MAX - LAST_ROW - 1, true, false);
footerRow = PAGE_ROW_MAX - LAST_ROW + 1;
imgShift = PAGE_ROW_MAX - LAST_ROW + 1;
TOTAL_ROW = PAGE_ROW_MAX;
footerRow = TOTAL_ROW + 1;
situation = 2;
}
else {
sheet.shiftRows(startRow, fileLastRow, additionalRowNum, true, false);
footerRow = additionalRowNum + 1;
TOTAL_ROW = LAST_ROW + additionalRowNum+1;
footerRow = TOTAL_ROW + 1;
situation = 3;
}
}
else {// on dépasse forcément le format A4 d'un PDF
if(((TOTAL_ROW - 44) % 63) < 13) {
// Not enough space for footer
sheet.shiftRows(startRow, fileLastRow, TOTAL_ROW - LAST_ROW + ((TOTAL_ROW-44)%63), true, false);
footerRow = additionalRowNum + ((TOTAL_ROW-44)%63) + 1;
imgShift = TOTAL_ROW-44 + ((TOTAL_ROW-44)%63) -1;
TOTAL_ROW += ((TOTAL_ROW-44)%63) + 1;
footerRow = TOTAL_ROW+1;
situation = 4;
}
else {
// Enough space for footer
sheet.shiftRows(startRow, fileLastRow, TOTAL_ROW - LAST_ROW, true, false);
footerRow = TOTAL_ROW - LAST_ROW +1;
TOTAL_ROW = LAST_ROW + additionalRowNum + 1;
footerRow = TOTAL_ROW + 1;
situation = 5;
}
}
// inserting new rows after row 42
for(int i = 0; i < footerRow; i++) {
for(int i = 0; i < footerRow - startRow; i++) {
sheet.createRow(startRow-1 + i);
org.apache.poi.ss.usermodel.Row newRow = sheet.getRow(startRow-1 + i);
newRow.setHeight(sourceRow.getHeight());
@ -211,7 +223,7 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
Cell cell = newRow.createCell(j);
CellStyle cellStyle = factory.getWorkbook().createCellStyle();
CellStyle middleCellStyle = factory.getWorkbook().createCellStyle();
if (j == 1 || j == 9) {
if (j == 1 || j == 9) { // double bordure de la premiere et derniere colonne
cellStyle.setBorderLeft(BorderStyle.DOUBLE);
cell.setCellStyle(cellStyle);
}
@ -256,11 +268,7 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
if(data.size() > dataRowNumber)
{
org.apache.poi.ss.usermodel.Row totalRow;
// Si ça pète c'est surement ici
if(additionalRowNum%PAGE_ROW_MAX <= 13)
totalRow = sheet.getRow(TOTAL_ROW-1);
else
totalRow = sheet.getRow(TOTAL_ROW);
totalRow = sheet.getRow(TOTAL_ROW - 1);
totalRow.setHeight(sourceRow.getHeight());
totalRow.setRowStyle(null);
totalRow.setRowStyle(sourceRow.getRowStyle());
@ -310,11 +318,11 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
if(i==2)
cell.setCellValue("Total");
if(i==5)
cell.setCellFormula("SUM(F"+FIRST_ROW+":F"+(TOTAL_ROW-1)+")");
cell.setCellFormula("SUM(F" + FIRST_ROW + ":F" + (TOTAL_ROW - 1) + ")");
if(i==6)
cell.setCellFormula("SUM(G"+FIRST_ROW+":G"+(TOTAL_ROW-1)+")");
cell.setCellFormula("SUM(G" + FIRST_ROW + ":G" + (TOTAL_ROW - 1) + ")");
if(i==7)
cell.setCellFormula("SUM(H"+FIRST_ROW+":H"+(TOTAL_ROW-1)+")");
cell.setCellFormula("SUM(H" + FIRST_ROW + ":H" + (TOTAL_ROW - 1) + ")");
}
//Total due
@ -328,7 +336,7 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
// Si ça pète c'est pas là
totalDueRow = sheet.getRow( totalRow.getRowNum() + 2);
Cell totalDueCell = totalDueRow.createCell(7);
totalDueCell.setCellFormula("H" + (totalRow.getRowNum() + 1) + "-G" + (totalRow.getRowNum()) + 1);
totalDueCell.setCellFormula("H" + (totalRow.getRowNum() + 1) + "-G" + (totalRow.getRowNum() + 1));
totalDueCell.setCellStyle(totalDueCellStyle);
}
@ -359,7 +367,6 @@ public abstract class AbstractInvoice<E, F, G, H, I> {
}
}
/**
* A shortcut to configure a cell of a sheet with a value and a style by global writer.
*

View File

@ -107,6 +107,7 @@ public interface IPurchaseOrderService extends IService<PurchaseOrder> {
* @throws IOException IO error while reading the file.
*/
InvoiceMetaData makeInvoice(String purchaseID) throws IOException, URISyntaxException, UserException;
InvoiceMetaData makeInvoiceTest(int nbOfLines) throws IOException, URISyntaxException, UserException;
byte[] getInvoiceByte(String invoiceCode) throws IOException;

View File

@ -8,6 +8,7 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.business.controller.UserException;
import org.jeecg.modules.business.domain.excel.SheetManager;
import org.jeecg.modules.business.domain.purchase.invoice.PurchaseInvoice;
import org.jeecg.modules.business.domain.purchase.invoice.PurchaseInvoiceEntry;
import org.jeecg.modules.business.domain.shippingInvoice.CompleteInvoice;
import org.jeecg.modules.business.domain.shippingInvoice.ShippingInvoice;
import org.jeecg.modules.business.domain.shippingInvoice.ShippingInvoiceFactory;
@ -119,9 +120,13 @@ public class PlatformOrderShippingInvoiceService {
@Value("${jeecg.path.shippingInvoiceDir}")
private String INVOICE_DIR;
@Value("${jeecg.path.shippingInvoiceTestDir}")
private String INVOICE_TEST_DIR;
@Value("${jeecg.path.purchaseInvoiceDir}")
private String PURCHASE_INVOICE_DIR;
@Value("${jeecg.path.purchaseInvoiceTestDir}")
private String PURCHASE_INVOICE_TEST_DIR;
@Value("${jeecg.path.purchaseInventoryDir}")
private String PURCHASE_INVENTORY_DIR;
@ -930,4 +935,157 @@ public class PlatformOrderShippingInvoiceService {
}
return Collections.singletonList(out);
}
@Transactional
public InvoiceMetaData makeShippingInvoiceTest(int nbOfLines) throws Exception {
// Creates invoice by factory
Client client = clientService.getClientBySku("TEST");
Map<PlatformOrder, List<PlatformOrderContent>> ordersToContent = new HashMap<>();
List<SavRefundWithDetail> savRefunds = new ArrayList<>();
List<ExtraFeeResult> extraFees = new ArrayList<>();
BigDecimal exchangeRate = BigDecimal.ONE;
String invoiceCode = "SI-TEST-2" + nbOfLines;
List<PlatformOrderContent> poc = new ArrayList<>();
PlatformOrderContent content = new PlatformOrderContent();
content.setSkuId("TEST");
content.setErpStatus("3");
content.setQuantity(1);
content.setVat(BigDecimal.ZERO);
content.setShippingFee(BigDecimal.ZERO);
content.setPickingFee(BigDecimal.ZERO);
content.setShippingFee(BigDecimal.ZERO);
content.setServiceFee(BigDecimal.ONE);
poc.add(content);
for(int i = 0; i < nbOfLines - 4; i++) {
PlatformOrder po = new PlatformOrder();
po.setCountry("Country" + i);
po.setPickingFee(BigDecimal.ZERO);
po.setOrderServiceFee(BigDecimal.ZERO);
po.setPackagingMaterialFee(BigDecimal.ZERO);
po.setFretFee(BigDecimal.ZERO);
po.setPlatformOrderId("TEST" + i);
poc.get(0).setPlatformOrderId("TEST" + i);
ordersToContent.put(po, poc);
}
ShippingInvoice invoice = new ShippingInvoice(client, invoiceCode, "Test subject", ordersToContent, savRefunds, extraFees, exchangeRate);
Path src;
src = Paths.get(SHIPPING_INVOICE_TEMPLATE_US);
// src = Paths.get(SHIPPING_INVOICE_TEMPLATE_EU);
// Writes invoice content to a new excel file
String filename = "Invoice N°" + invoice.code() + " (" + invoice.client().getInvoiceEntity() + ")_" + nbOfLines +".xlsx";
Path out = Paths.get(INVOICE_TEST_DIR, filename);
Files.copy(src, out, StandardCopyOption.REPLACE_EXISTING);
invoice.toExcelFile(out);
convertToPdfTest(invoiceCode, "invoice");
return new InvoiceMetaData(filename, invoice.code(), invoice.client().getInternalCode(), invoice.client().getInvoiceEntity(), "");
}
@Transactional
public InvoiceMetaData makeCompleteInvoiceTest(int nbOfLines) throws Exception {
// Creates invoice by factory
Client client = clientService.getClientBySku("TEST");
Map<PlatformOrder, List<PlatformOrderContent>> ordersToContent = new HashMap<>();
List<SavRefundWithDetail> savRefunds = new ArrayList<>();
List<ExtraFeeResult> extraFees = new ArrayList<>();
List<PromotionDetail> promotionDetails = new ArrayList<>();
List<PurchaseInvoiceEntry> purchaseInvoiceEntries = new ArrayList<>();
BigDecimal exchangeRate = BigDecimal.ONE;
String invoiceCode = "CI-TEST-7-" + nbOfLines;
List<PlatformOrderContent> poc = new ArrayList<>();
PlatformOrderContent content = new PlatformOrderContent();
content.setSkuId("TEST");
content.setErpStatus("3");
content.setQuantity(1);
content.setVat(BigDecimal.ZERO);
content.setShippingFee(BigDecimal.ZERO);
content.setPickingFee(BigDecimal.ZERO);
content.setShippingFee(BigDecimal.ZERO);
content.setServiceFee(BigDecimal.ONE);
poc.add(content);
PlatformOrder po = new PlatformOrder();
po.setCountry("Country");
po.setPickingFee(BigDecimal.ZERO);
po.setOrderServiceFee(BigDecimal.ZERO);
po.setPackagingMaterialFee(BigDecimal.ZERO);
po.setFretFee(BigDecimal.ZERO);
po.setPlatformOrderId("TEST");
poc.get(0).setPlatformOrderId("TEST");
ordersToContent.put(po, poc);
for(int i = 0; i < nbOfLines - 5; i++) {
PurchaseInvoiceEntry entry = new PurchaseInvoiceEntry("SKU" + i, "Product" + i, 1, BigDecimal.ONE);
purchaseInvoiceEntries.add(entry);
}
CompleteInvoice invoice = new CompleteInvoice(client, invoiceCode, "Test subject", ordersToContent, savRefunds, extraFees, purchaseInvoiceEntries, promotionDetails, exchangeRate);
Path src;
// src = Paths.get(COMPLETE_INVOICE_TEMPLATE_US);
src = Paths.get(COMPLETE_INVOICE_TEMPLATE_EU);
// Writes invoice content to a new excel file
String filename = "Complete invoice N°" + invoice.code() + " (" + invoice.client().getInvoiceEntity() + ") _" + nbOfLines + ".xlsx";
Path out = Paths.get(INVOICE_TEST_DIR, filename);
Files.copy(src, out, StandardCopyOption.REPLACE_EXISTING);
invoice.toExcelFile(out);
convertToPdfTest(invoiceCode, "invoice");
return new InvoiceMetaData(filename, invoice.code(), invoice.client().getInternalCode(), invoice.client().getInvoiceEntity(), "");
}
public void convertToPdfTest(String invoiceNumber, String fileType) throws Exception {
String excelFilePath = getInvoiceListTest(invoiceNumber, fileType);// (C:\PATH\filename.xlsx)
if(!excelFilePath.equals("ERROR")) {
String pdfFilePath= INVOICE_PDF_DIR + "/" + invoiceNumber + ".pdf";
pdfFilePath = INVOICE_PDF_DIR + "/Invoice N°" + invoiceNumber + ".pdf";
Pattern p = Pattern.compile("^(.*)[\\/\\\\](.*)(\\.[a-z]+)"); //group(1): "C:\PATH" , group(2) : "filename", group(3): ".xlsx"
Matcher m = p.matcher(excelFilePath);
if (m.matches()) {
pdfFilePath = INVOICE_PDF_DIR + "/" + m.group(2) + ".pdf";
}
// Créé un classeur pour charger le fichier Excel
PdfSaveOptions saveOptions = new PdfSaveOptions();
saveOptions.setDefaultFont("Arial");
saveOptions.setCheckWorkbookDefaultFont(false);
Workbook workbook = new Workbook(excelFilePath);
Worksheet sheet = workbook.getWorksheets().get(0);
// get number of lines
Cells cells = sheet.getCells();
int maxRow = cells.getMaxDataRow();
PageSetup pageSetup = sheet.getPageSetup();
// Setting the number of pages to which the length of the worksheet will
if(maxRow < 63) {
// be spanned
pageSetup.setFitToPagesTall(1);
// Setting the number of pages to which the width of the worksheet will be spanned
pageSetup.setFitToPagesWide(1);
}
// On enregistre le document au format PDF
workbook.save(pdfFilePath, saveOptions);
}
}
public String getInvoiceListTest(String invoiceNumber, String filetype) throws UserException, IOException {
log.info("Invoice number : " + invoiceNumber);
List<Path> pathList = new ArrayList<>();
log.info("File asked is of type invoice");
if(Invoice.getType(invoiceNumber).equalsIgnoreCase(PURCHASE.name()))
pathList = getPath(PURCHASE_INVOICE_TEST_DIR, invoiceNumber);
else
pathList = getPath(INVOICE_TEST_DIR, invoiceNumber);
if(pathList.isEmpty()) {
log.error("NO INVOICE FILE FOUND : " + invoiceNumber);
return "ERROR";
}
for (Path path : pathList) {
log.info(path.toString());
}
return pathList.get(0).toString();
}
}

View File

@ -79,6 +79,8 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
@Value("${jeecg.path.purchaseInvoiceDir}")
private String INVOICE_DIR;
@Value("${jeecg.path.purchaseInvoiceTestDir}")
private String INVOICE_TEST_DIR;
@Value("${jeecg.path.shippingInvoiceDetailDir}")
private String INVOICE_DETAIL_DIR;
@Value("${jeecg.path.shippingInvoicePdfDir}")
@ -556,6 +558,29 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
pv.toExcelFile(newInvoice);
return new InvoiceMetaData(filename,invoiceCode, pv.client().getInternalCode(), pv.client().getInvoiceEntity(), "");
}
@Override
public InvoiceMetaData makeInvoiceTest(int nbOfLines) throws IOException, UserException {
Client client = clientService.getClientBySku("test");
List<PurchaseInvoiceEntry> purchaseOrderSkuList = new ArrayList<>();
// -5 because we have at least 5 lines of promotions
for (int i = 0; i < nbOfLines - 5; i++) {
purchaseOrderSkuList.add(new PurchaseInvoiceEntry("SKU" + i, "SKU" + i, 1, BigDecimal.ONE));
}
List<PromotionDetail> promotionDetails = new ArrayList<>();
for(int i = 0; i < 5; i++) {
promotionDetails.add(new PromotionDetail(1, BigDecimal.valueOf(0.5), "Test Promotion " + i));
}
String invoiceCode = "P-TEST-CODE-" + nbOfLines;
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
String filename = "Invoice N°" + invoiceCode + " (" + client.getInvoiceEntity() + ")_" + nbOfLines + ".xlsx";
Path template = Paths.get(INVOICE_TEMPLATE);
Path newInvoice = Paths.get(INVOICE_TEST_DIR, filename);
Files.copy(template, newInvoice, StandardCopyOption.REPLACE_EXISTING);
PurchaseInvoice pv = new PurchaseInvoice(client, invoiceCode, "Purchase Invoice", purchaseOrderSkuList, promotionDetails, eurToUsd);
pv.toExcelFile(newInvoice);
return new InvoiceMetaData(filename,invoiceCode, pv.client().getInternalCode(), pv.client().getInvoiceEntity(), "");
}
@Override
public byte[] getInvoiceByte(String invoiceCode) throws IOException {

View File

@ -224,6 +224,7 @@ jeecg:
purchaseTemplatePath: /wia/files/Purchase_Invoice_Template.xlsx
# where to store generated file
purchaseInvoiceDir: /wia/invoices/purchase
purchaseInvoiceTestDir: /wia/invoices/test/purchase
purchaseInventoryDir: /wia/invoices/inventory
# shipping invoice template
@ -235,6 +236,7 @@ jeecg:
completeTemplatePath_US: /wia/files/Complete_Invoice_Template_US.xlsx
# where to store generated file
shippingInvoiceDir: /wia/invoices/shipping
shippingInvoiceTestDir: /wia/invoices/test/shipping
shippingInvoiceDetailDir: /wia/invoices/shippingDetail
shippingInvoicePdfDir: /wia/invoices/pdf/shipping
shippingInvoiceDetailPdfDir: /wia/invoices/pdf/shippingDetail