diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java index de815f4bc..f33223d13 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java @@ -121,6 +121,8 @@ public class InvoiceController { @Value("${jeecg.path.shippingInvoiceDetailDir}") private String INVOICE_DETAIL_DIR; + @Value("${jeecg.path.shippingInvoicePdfDir}") + private String INVOICE_PDF_DIR; private final String SECTION_START = "
"; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java index 4807cb3e6..8282a4353 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java @@ -1,7 +1,5 @@ package org.jeecg.modules.business.controller.admin.shippingInvoice; -import com.aspose.cells.SaveFormat; -import com.aspose.cells.Workbook; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -49,8 +47,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -77,6 +73,8 @@ public class ShippingInvoiceController { @Autowired private IPurchaseOrderService purchaseOrderService; @Autowired + private PlatformOrderShippingInvoiceService platformOrderShippingInvoiceService; + @Autowired private ISavRefundService savRefundService; @Autowired private IShippingInvoiceService shippingInvoiceService; @@ -88,10 +86,6 @@ public class ShippingInvoiceController { private String INVOICE_LOCATION; @Value("${jeecg.path.shippingInvoiceDetailDir}") private String INVOICE_DETAIL_LOCATION; - @Value("${jeecg.path.shippingInvoicePdfDir}") - private String INVOICE_PDF_LOCATION; - @Value("${jeecg.path.shippingInvoiceDetailPdfDir}") - private String INVOICE_DETAIL_PDF_LOCAION; @Autowired Environment env; @@ -280,8 +274,6 @@ public class ShippingInvoiceController { return Result.OK("文件导入失败!"); } - - /** * Downloads the invoice and returns it in form of bytearray * @param invoiceNumber the invoice we want to download @@ -354,7 +346,7 @@ public class ShippingInvoiceController { */ @GetMapping(value = "/downloadPdf") public ResponseEntity downloadPdf(@RequestParam("invoiceNumber") String invoiceNumber) throws Exception { - String pdfFilePath = convertToPdf(invoiceNumber, "invoice"); + String pdfFilePath = platformOrderShippingInvoiceService.convertToPdf(invoiceNumber, "invoice"); if(!pdfFilePath.equals("ERROR")) { File file = new File(pdfFilePath); HttpHeaders header = new HttpHeaders(); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/hualei/HLRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/hualei/HLRequest.java index 55651f820..a8611da9d 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/hualei/HLRequest.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/hualei/HLRequest.java @@ -21,12 +21,13 @@ import java.util.List; */ @Slf4j public class HLRequest { - private final static String URL = "http://www.antugj.com:8082/selectTrack.htm"; private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().build(); + private final String url; private final List billCodes; - public HLRequest(List billCodes) { + public HLRequest(String url, List billCodes) { + this.url = url; this.billCodes = billCodes; } @@ -40,7 +41,7 @@ public class HLRequest { while (attempts++ < 5) { try { HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(REQUEST_CONFIG).build(); - HttpPost request = new HttpPost(URL); + HttpPost request = new HttpPost(url); // adding the form data request.setEntity(new UrlEncodedFormEntity(generateFormData(), "UTF-8")); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java index a1403011d..d87a18e20 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java @@ -126,14 +126,14 @@ public class Order { private String phone1; public void setTrackingNumber(String trackingNumber) { - if (trackingNumber != null && trackingNumber.length() == 0) { + if (trackingNumber != null && trackingNumber.isEmpty()) { this.trackingNumber = null; } else this.trackingNumber = trackingNumber; } public void setTrackingNumber1(String trackingNumber) { - if (trackingNumber != null && trackingNumber.length() == 0) { + if (trackingNumber != null && trackingNumber.isEmpty()) { this.trackingNumber1 = null; } else this.trackingNumber1 = trackingNumber; @@ -164,7 +164,7 @@ public class Order { } public void setShippingTime(String shippingTime) { - if (shippingTime != null && shippingTime.length() == 0) { + if (shippingTime != null && shippingTime.isEmpty()) { this.shippingTime = null; } else this.shippingTime = shippingTime; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java index 4f84ccfce..771fc776c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java @@ -34,6 +34,9 @@ public class OrderItem { private String productAvailable; + @JSONField(name = "specifics") + private String specifics; + /** * Status : * 2 = Normal diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/AbstractInvoice.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/AbstractInvoice.java index ffb1540e4..6b4be84f5 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/AbstractInvoice.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/AbstractInvoice.java @@ -156,28 +156,49 @@ public abstract class AbstractInvoice { // if the number of rows of data is greater than the available space in the default template // we shift down the rows after the table and we clone the row in the table int dataRowNumber = LAST_ROW - FIRST_ROW; - int additionalRowNum = data.size() - dataRowNumber - 1; - TOTAL_ROW = LAST_ROW+additionalRowNum; - + int additionalRowNum = Math.max(data.size() - dataRowNumber - 1, 0); + TOTAL_ROW = LAST_ROW + additionalRowNum; Sheet sheet = factory.getWorkbook().getSheetAt(0); org.apache.poi.ss.usermodel.Row sourceRow = sheet.getRow(FIRST_ROW); - if(data.size() > dataRowNumber) + 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) + if(data.size() > dataRowNumber + 1) { int startRow = LAST_ROW+1; int fileLastRow = sheet.getLastRowNum(); // shifting the footer of the file, to X rows below // making sure the whole footer is in the same page (13 lines) and we fill the end of page with blank data lines - if(additionalRowNum%PAGE_ROW_MAX <= 13) { - TOTAL_ROW = PAGE_ROW_MAX-2; - sheet.shiftRows(startRow, fileLastRow, PAGE_ROW_MAX - LAST_ROW, true, false); + + // si le nombre de lignes de data rentre dans 1 page A4 + if(data.size() < 44) { + 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; + } + else { + sheet.shiftRows(startRow, fileLastRow, additionalRowNum, true, false); + footerRow = additionalRowNum + 1; + TOTAL_ROW = LAST_ROW + additionalRowNum+1; + } } - else { - // +6 because if we use US template there's one more row - sheet.shiftRows(startRow, fileLastRow, additionalRowNum, true, false); + else {// on dépasse forcément le format A4 d'un PDF + if(((TOTAL_ROW - 44) % 63) < 13) { + 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; + } + else { + sheet.shiftRows(startRow, fileLastRow, TOTAL_ROW - LAST_ROW, true, false); + footerRow = TOTAL_ROW - LAST_ROW +1; + } } // inserting new rows after row 42 - for(int i = 0; i < (data.size() - dataRowNumber - 1 <= 13 ? PAGE_ROW_MAX-LAST_ROW+1 : additionalRowNum+1); i++) { + for(int i = 0; i < footerRow; i++) { sheet.createRow(startRow-1 + i); org.apache.poi.ss.usermodel.Row newRow = sheet.getRow(startRow-1 + i); newRow.setHeight(sourceRow.getHeight()); @@ -192,7 +213,7 @@ public abstract class AbstractInvoice { cellStyle.setBorderLeft(BorderStyle.DOUBLE); cell.setCellStyle(cellStyle); } - if(startRow + i < PAGE_ROW_MAX-2) { + if((startRow + i <= TOTAL_ROW && data.size() >= 44) || (startRow + i <= PAGE_ROW_MAX - 1 && data.size() < 44)) { if (j >= 2 && j <= 7) { middleCellStyle.setBorderLeft(BorderStyle.THIN); middleCellStyle.setBorderRight(BorderStyle.THIN); @@ -209,11 +230,14 @@ public abstract class AbstractInvoice { XSSFPicture picture = (XSSFPicture)shape; XSSFClientAnchor anchor = picture.getClientAnchor(); - anchor.setRow1(data.size() - dataRowNumber - 1 <= 13 ? anchor.getRow1() + PAGE_ROW_MAX-LAST_ROW : anchor.getRow1() + additionalRowNum); - anchor.setRow2(data.size() - dataRowNumber - 1 <= 13 ? anchor.getRow2() + PAGE_ROW_MAX-LAST_ROW : anchor.getRow2() + additionalRowNum); + anchor.setRow1(anchor.getRow1() + imgShift); + anchor.setRow2(anchor.getRow2() + imgShift); } } } + else { + TOTAL_ROW = LAST_ROW + additionalRowNum + 1; + } // table section for (int i = 0; i < data.size(); i++) { lineNum = i + FIRST_ROW; @@ -298,16 +322,16 @@ public abstract class AbstractInvoice { totalDueCellStyle.setBorderTop(BorderStyle.THIN); totalDueCellStyle.setFont(arialBold); - if(additionalRowNum%PAGE_ROW_MAX <= 13) { - totalDueRow = sheet.getRow(PAGE_ROW_MAX + 2); + if(((LAST_ROW+additionalRowNum - 44) % 63) < 13 && ((LAST_ROW+additionalRowNum - 44) % 63) > 0) { + totalDueRow = sheet.getRow( data.size() < 44 ? PAGE_ROW_MAX + 1 : TOTAL_ROW + 1); Cell totalDueCell = totalDueRow.createCell(7); - totalDueCell.setCellFormula("H" + (PAGE_ROW_MAX - 2) + "-G" + (PAGE_ROW_MAX - 2)); + totalDueCell.setCellFormula("H" + (TOTAL_ROW) + "-G" + (TOTAL_ROW)); totalDueCell.setCellStyle(totalDueCellStyle); } else { - totalDueRow = sheet.getRow(TOTAL_ROW + 2); + totalDueRow = sheet.getRow(data.size() < 44 ? TOTAL_ROW + 1 : TOTAL_ROW + 2); Cell totalDueCell = totalDueRow.createCell(7); - totalDueCell.setCellFormula("H" + (TOTAL_ROW+1) + "-G" + (TOTAL_ROW+1)); + totalDueCell.setCellFormula("H" + (data.size() < 44 ? TOTAL_ROW : TOTAL_ROW + 1) + "-G" + (data.size() < 44 ? TOTAL_ROW : TOTAL_ROW + 1)); totalDueCell.setCellStyle(totalDueCellStyle); } } @@ -315,13 +339,13 @@ public abstract class AbstractInvoice { if (targetClient.getCurrency().equals("USD")) { org.apache.poi.ss.usermodel.Row dollarRow; String formula; - if (additionalRowNum % PAGE_ROW_MAX <= 13) { - dollarRow = sheet.getRow(TOTAL_ROW + 5); - formula = "H"+ (TOTAL_ROW+5) +" *" + exchangeRate; + if ((((LAST_ROW + additionalRowNum - 44) % 63) < 13) && ((LAST_ROW + additionalRowNum - 44) % 63) > 0) { + dollarRow = sheet.getRow(TOTAL_ROW + 2); + formula = "H"+ (TOTAL_ROW + 2) +" *" + exchangeRate; } else { - dollarRow = sheet.getRow(TOTAL_ROW + 3); - formula = "H" + (TOTAL_ROW + 3) + " *" + exchangeRate; + dollarRow = sheet.getRow(data.size() >= 44 ? TOTAL_ROW + 3 : TOTAL_ROW + 2); + formula = "H" + (data.size() >= 44 ? TOTAL_ROW + 3 : TOTAL_ROW + 2) + " *" + exchangeRate; } Cell dollarCell = dollarRow.createCell(7); // column H CellStyle cellStyle = factory.getWorkbook().createCellStyle(); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java index 725b28d3e..95ee6fba1 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java @@ -35,14 +35,16 @@ public class AddPortraitTubeJob implements Job { private static final List DEFAULT_SHOPS = Arrays.asList("JCH3", "JCH4", "JCH5"); private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + private static final String TUBE_30_SKU_SINGLE_DOUBLE = "PJ95310032-WIA"; private static final String TUBE_40_SKU_SINGLE = "PJ95430032-WIA"; private static final String TUBE_40_SKU_MULTIPLE = "PJ95430040-WIA"; private static final String TUBE_50_SKU_SINGLE = "PJ95530032-WIA"; private static final String TUBE_50_SKU_MULTIPLE = "PJ95530040-WIA"; - private static final List TUBE_SKUS = Arrays.asList(TUBE_50_SKU_MULTIPLE, TUBE_50_SKU_SINGLE, - TUBE_40_SKU_MULTIPLE, TUBE_40_SKU_SINGLE); + private static final List TUBE_SKUS = Arrays.asList(TUBE_30_SKU_SINGLE_DOUBLE, TUBE_50_SKU_MULTIPLE, + TUBE_50_SKU_SINGLE, TUBE_40_SKU_MULTIPLE, TUBE_40_SKU_SINGLE); private static final String PREFIX_50_CANVAS = "JJ2501"; private static final String PREFIX_40_CANVAS = "JJ2500"; + private static final String PREFIX_30_CANVAS = "JJ2502"; @Autowired private IPlatformOrderService platformOrderService; @@ -153,6 +155,7 @@ public class AddPortraitTubeJob implements Job { * @return Set of pairs */ private Pair>, HashSet>> findCurrentAndAdequateTubes(List orderItems) { + int canvas30Count = 0; int canvas40Count = 0; int canvas50Count = 0; HashSet> currentTubes = new HashSet<>(); @@ -166,31 +169,75 @@ public class AddPortraitTubeJob implements Job { canvas50Count += quantity; } else if (sku.startsWith(PREFIX_40_CANVAS)) { canvas40Count += quantity; + } else if (sku.startsWith(PREFIX_30_CANVAS)) { + canvas30Count += quantity; } } + int canvas30RemainderCount = canvas30Count % MAXIMUM_CANVAS_IN_TUBE.intValue(); int canvas40RemainderCount = canvas40Count % MAXIMUM_CANVAS_IN_TUBE.intValue(); int canvas50RemainderCount = canvas50Count % MAXIMUM_CANVAS_IN_TUBE.intValue(); + int totalRemainderCount = canvas30RemainderCount + canvas40RemainderCount + canvas50RemainderCount; int tube50SingleCount = 0; int tube50MultipleCount = (int) Math.floor(canvas50Count / MAXIMUM_CANVAS_IN_TUBE); int tube40SingleCount = 0; int tube40MultipleCount = (int) Math.floor(canvas40Count / MAXIMUM_CANVAS_IN_TUBE); - if (canvas50RemainderCount > 0 && canvas40RemainderCount > 0) { - tube50MultipleCount++; - if (canvas50RemainderCount == 2 && canvas40RemainderCount == 2) { - tube50SingleCount++; + int tube30SingleDoubleCount = 0; + // 3 canvas of 30cm also go into 40 multiple tubes + tube40MultipleCount += (int) Math.floor(canvas30Count / MAXIMUM_CANVAS_IN_TUBE); + // When remaining 1 to 3 canvases + if (totalRemainderCount > 0 && totalRemainderCount < 4) { + if (canvas50RemainderCount > 0) { + // It only takes one 50cm canvas with any other canvas to impose the use of 50cm multiple tube + if (totalRemainderCount > 1) { + tube50MultipleCount++; + } else { + tube50SingleCount++; + } + } else { + if (totalRemainderCount > 1) { + if (canvas40RemainderCount > 0) { + tube40MultipleCount++; + } else { + tube30SingleDoubleCount++; + } + } else { + if (canvas40RemainderCount > 0) { + tube40SingleCount++; + } else if (canvas30RemainderCount > 0){ + tube30SingleDoubleCount++; + } + } } - } else { - if (canvas40RemainderCount == 1) { - tube40SingleCount++; - } else if (canvas40RemainderCount == 2) { - tube40MultipleCount++; - } else if (canvas50RemainderCount == 1) { - tube50SingleCount++; - } else if (canvas50RemainderCount == 2) { + } else if (totalRemainderCount >= 4) { + // When remaining 4 to 6 canvases, one 50cm canvas imposes one 50cm multiple tube + if (canvas50RemainderCount > 0) { tube50MultipleCount++; + if (canvas50RemainderCount > 1) { + // If we have two 50cm canvases and a total of 5 of 6 canvases + if (totalRemainderCount > 4) { + if (canvas40RemainderCount > 1) { + tube40MultipleCount++; + } else { + tube30SingleDoubleCount++; + } + } else { + if (canvas40RemainderCount > 1) { + tube40SingleCount++; + } else { + tube30SingleDoubleCount++; + } + } + } else { + tube30SingleDoubleCount++; + } + } else { + // No 50cm canvases means only one combination possible: two 40cm canvases and two 30cm canvases + tube40MultipleCount++; + tube30SingleDoubleCount++; } } + if (tube50SingleCount > 0) { adequateTubes.add(Pair.of(TUBE_50_SKU_SINGLE, tube50SingleCount)); } @@ -203,6 +250,9 @@ public class AddPortraitTubeJob implements Job { if (tube40MultipleCount > 0) { adequateTubes.add(Pair.of(TUBE_40_SKU_MULTIPLE, tube40MultipleCount)); } + if (tube30SingleDoubleCount > 0) { + adequateTubes.add(Pair.of(TUBE_30_SKU_SINGLE_DOUBLE, tube30SingleDoubleCount)); + } return Pair.of(currentTubes, adequateTubes); } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java index 982b54fe3..89e9485b8 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @@ -31,6 +32,7 @@ public class ArchiveOrderJob implements Job { private static final List DEFAULT_EXCLUDED_SHOPS = Arrays.asList("JCH3", "JCH4", "JCH5", "FB2"); private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + private static final Integer MABANG_API_RATE_LIMIT_PER_MINUTE = 300; @Autowired private IPlatformOrderService platformOrderService; @@ -76,7 +78,8 @@ public class ArchiveOrderJob implements Job { List platformOrderIds = platformOrderService.fetchInvoicedShippedOrdersNotInShops(startDateTime, endDateTime, shops, excludedTrackingNumbersRegex); - ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS); + ExecutorService throttlingExecutorService = ThrottlingExecutorService.createExecutorService(DEFAULT_NUMBER_OF_THREADS, + MABANG_API_RATE_LIMIT_PER_MINUTE, TimeUnit.MINUTES); log.info("Constructing order archiving requests"); List archiveOrderRequestBodies = new ArrayList<>(); @@ -95,7 +98,7 @@ public class ArchiveOrderJob implements Job { log.error("Error communicating with MabangAPI", e); } return success; - }, executor)) + }, throttlingExecutorService)) .collect(Collectors.toList()); List results = changeOrderFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()); long nbSuccesses = results.stream().filter(b -> b).count(); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/CWJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/CWJob.java index 8911991e1..ec3c1e002 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/CWJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/CWJob.java @@ -44,8 +44,8 @@ public class CWJob implements Job { private static final Integer DEFAULT_MAXIMUM_NUMBER_OF_PARCELS_PER_TRANSACTION = 800; private static final List DEFAULT_TRANSPORTERS = Arrays.asList("诚稳法邮普货" , "诚稳法邮膏体"); - private final static String APP_TOKEN = "yhidp1u86us23hx79xx2t8b7h47wa9usv"; - private final static String APP_KEY = "ymk3899nifsjw4d9igkyk58sfl6u48869ahr749axjtnq2kn07n4y6izn1ywcptkh"; + private final static String APP_TOKEN = "y7j1p5o4obncsdhbk1zgasunb2erpyzvh"; + private final static String APP_KEY = "ym27kj0wy5wgx69f58pgd7crm60w07p0l15flj1bacrf5n0e38vqjtrjkkvosd61p"; @Override public void execute(JobExecutionContext context) throws JobExecutionException { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/HLJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/HLJob.java index 27e776f7d..3f12dc81b 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/HLJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/HLJob.java @@ -35,6 +35,8 @@ public class HLJob implements Job { @Autowired private IPlatformOrderService platformOrderService; + private final static String URL = "http://www.antugj.com:8082/selectTrack.htm"; + private static final Integer DEFAULT_NUMBER_OF_DAYS = 15; private static final Integer DEFAULT_MAXIMUM_NUMBER_OF_PARCELS_PER_TRANSACTION = 800; private static final List DEFAULT_TRANSPORTERS = Arrays.asList("法国专线普货"); @@ -91,7 +93,7 @@ public class HLJob implements Job { List parcelTraces = new ArrayList<>(); List hlRequests = new ArrayList<>(); billCodeLists.forEach(billcodeList -> { - HLRequest hlRequest = new HLRequest(billcodeList); + HLRequest hlRequest = new HLRequest(URL, billcodeList); hlRequests.add(hlRequest); }); List results = new ArrayList<>(); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/IntervalWindow.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/IntervalWindow.java new file mode 100644 index 000000000..778e87ea7 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/IntervalWindow.java @@ -0,0 +1,205 @@ +package org.jeecg.modules.business.domain.job; + +import java.util.LinkedHashMap; +import java.util.Map; +/** + * Extends {@code LinkedHashMap} into a fixed sized ordered cache + * for allocating and tracking limited resources in intervals. It also + * tracks the allocation rate as a moving average. + *

+ * The {@code IntervalWindow} is created with a cache that consists of the + * present interval and at least one past interval. + * As the number of cached intervals exceed the windows size, they are + * removed and the moving average updated. The allocation method is + * thread-safe to ensure over allocation is avoided. + * + * @author martinb + * @since 2015-08-17 + */ +public class IntervalWindow extends LinkedHashMap +{ + /** + * Serial + */ + private static final long serialVersionUID = 201508171315L; + + /** + * The upper execution limit per interval + */ + private final int INTERVAL_LIMIT; + + /** + * Number of intervals to track + */ + private final int INTERVAL_WINDOW_SIZE; + + /** + * The current interval being filled. + */ + private long currentInterval = 0; + + /** + * The moving total of slots used in the window + */ + private int slotsUsedInWindow = 0; + + /** + * The minimum interval index that can be considered. + */ + private long minimumInterval = 0; + + + /** + * Returns the value in the map, or a default. + * Implemented in JSE8 + * + * @param key + * @param defaultValue + * @return the value + */ + private final int getOrDefault(Long key, + Integer defaultValue) + { + if (get(key) != null) + { + return get(key); + } + return defaultValue; + } + + + /** + * Decreases the running total by the number of slots used in the + * interval leaving the moving window. + *

+ * The value in map is the number of free slots left in the interval. + * + * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) + */ + protected boolean removeEldestEntry(Map.Entry eldest) + { + if (INTERVAL_WINDOW_SIZE < size()) + { + slotsUsedInWindow -= (INTERVAL_LIMIT - eldest.getValue()); + minimumInterval = eldest.getKey(); + return true; + } + return false; + } + + + /** + * Tries to allocate a slot in the given interval within the rate limit. + * + * @param interval + * the interval + * @return true is a slot was allocated in the interval + */ + public boolean allocateSlot(long interval) + { + boolean isSlotAllocated = false; + int freeSlots = 0; // Free slots in the interval + + if (interval > minimumInterval) + /* + * Cheap range check is OK + */ + { + synchronized (this) + /* + * Synchronize allocate on this object to ensure that cache is consistent + */ + { + if ((freeSlots = getOrDefault(interval, + INTERVAL_LIMIT)) > 0) + /* + * There are free slots in this interval to execute this thread + * Break out of the loop and return. + */ + { + if (currentInterval > 0 && currentInterval != interval) + /* + * Update the running total of slots used in window + * with past values only once past the first interval. + */ + { + slotsUsedInWindow += + INTERVAL_LIMIT + - getOrDefault(currentInterval, + 0); + } + + put(currentInterval = interval, freeSlots - 1); // Maximum is RATE_LIMIT - 1 + isSlotAllocated = true; + } // if + } // synchronized + } // if + + return isSlotAllocated; + } + + + /** + * Returns the moving average number of slots allocated for work during + * the present window but excluding the currently filling interval + * + * @return the average number of slots used + */ + public float getAverageSlotUsed() + { + return slotsUsedInWindow / (INTERVAL_WINDOW_SIZE - 1); + } + + + /** + * Check window size parameters for range. + * + * @param intervalWindowSize + * the proposed window size + * @return the window size + */ + private static int checkWindowSize(int intervalWindowSize) + { + if (intervalWindowSize < 2) + { + throw new IllegalArgumentException( + "Interval Window Size cannot be smaller than 2"); + } + return intervalWindowSize; + + } + + + /** + * Creates an {@code IntervalWindow} of a window size of two that limits the + * number of successful allocations in each interval. + * + * @param intervalLimit + * the maximum number of allocations per interval. + */ + public IntervalWindow(int intervalLimit) + { + super(2, 1); + INTERVAL_WINDOW_SIZE = 2; + INTERVAL_LIMIT = intervalLimit; + } + + + /** + * Creates an {@code IntervalWindow} of a given window size that limits the + * number of successful allocations in each interval. + * + * @param intervalLimit + * the maximum number of allocations per interval. + * @param intervalWindow + * the number if intervals to track, must be at least two + */ + public IntervalWindow(int intervalLimit, int intervalWindow) + { + super(checkWindowSize(intervalWindow), + 1); + INTERVAL_WINDOW_SIZE = intervalWindow; + INTERVAL_LIMIT = intervalLimit; + } + +} \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ThrottlingExecutorService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ThrottlingExecutorService.java new file mode 100644 index 000000000..b30e37511 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ThrottlingExecutorService.java @@ -0,0 +1,166 @@ +package org.jeecg.modules.business.domain.job; + +import static java.lang.Integer.MAX_VALUE; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * A {@code ExecutorService} that throttles the amount of work released + * for execution per time period. + * + * @author martinb + * @since 2015-08-17 + */ +public class ThrottlingExecutorService extends ThreadPoolExecutor { + /** + * The interval window cache + */ + private final IntervalWindow INTERVAL_WINDOW; + + /** + * The rate limit interval in milliseconds + */ + private final long RATE_INTERVAL_MILLISECONDS; + + + /** + * Caching, dynamic rate limiting {@code ExecutorService} + * + * @param rateLimit + * the rate limit + * @param unit + * the rate limit time unit + */ + private ThrottlingExecutorService( + int rateLimit, + TimeUnit unit) + { + /* + * Create a CACHING ExecutorService + */ + super(0, MAX_VALUE, + 60L, SECONDS, + new SynchronousQueue()); + + INTERVAL_WINDOW = new IntervalWindow(rateLimit); + RATE_INTERVAL_MILLISECONDS = unit.toMillis(1); + } + + + /** + * Fixed size rate limiting {@code ExecutorService} + * + * @param parallelism + * @param rateLimit + * @param unit + */ + private ThrottlingExecutorService(int parallelism, + int rateLimit, + TimeUnit unit) + { + /* + * Create a FIXED ExecutorService + */ + super(parallelism, parallelism, 0, MILLISECONDS, + new LinkedBlockingQueue()); + + INTERVAL_WINDOW = new IntervalWindow(rateLimit); + RATE_INTERVAL_MILLISECONDS = unit.toMillis(1); + } + + + /** + * Produces a throttling ExecutorService + *

+ * Evaluates the parameters and generates an appropriate ExecutorService + * + * @param parallelism + * how many threads + * @param rateLimit + * work per time unit + * @param unit + * the time unit + * @return the ExecutorService + */ + public static ExecutorService createExecutorService(int parallelism, + int rateLimit, + TimeUnit unit) + { + if (parallelism > 0) + /* + * Fixed ExecutorService + */ + { + return new ThrottlingExecutorService(parallelism, + rateLimit > 0 ? rateLimit : MAX_VALUE, + unit); + } + else + /* + * Caching ExecutorService + */ + { + return new ThrottlingExecutorService( + rateLimit > 0 ? rateLimit : MAX_VALUE, + unit); + } + } + + + /** + * Throttles the execution before executing the task to achieve the desired + * rate. + * + * @see java.util.concurrent.ThreadPoolExecutor#execute(java.lang.Runnable) + */ + @Override + public void execute(final Runnable task) + { + throttle(); + super.execute(task); + } + + + /** + * Throttles if the thread can not be allocated in the current time + * interval, + * forcing it to wait to the next interval. + */ + private void throttle() + { + long interval = 0; // The interval index + long milliTime = System.currentTimeMillis(); // The current time + long offset = milliTime % RATE_INTERVAL_MILLISECONDS; // Interval offset + + while (!INTERVAL_WINDOW.allocateSlot( + (interval = (milliTime + offset) / RATE_INTERVAL_MILLISECONDS))) + /* + * Cannot allocate free slots in this interval. + * Calculate the required pause to get to the next interval and sleep + */ + { + int pause = (int) (((interval + 1) + * RATE_INTERVAL_MILLISECONDS) + - milliTime + offset); + try + /* + * Try to sleep the thread for a pause of nanoseconds + */ + { + Thread.sleep(pause); + } + catch (InterruptedException e) + { + } + + milliTime = System.currentTimeMillis(); + + } // while + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/YPJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/YPJob.java new file mode 100644 index 000000000..0871cbb25 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/YPJob.java @@ -0,0 +1,126 @@ +package org.jeecg.modules.business.domain.job; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.util.EntityUtils; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.jeecg.modules.business.domain.api.hualei.HLRequest; +import org.jeecg.modules.business.domain.api.hualei.HLResponse; +import org.jeecg.modules.business.domain.api.hualei.HLResponseItem; +import org.jeecg.modules.business.service.IParcelService; +import org.jeecg.modules.business.service.IPlatformOrderService; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; +import java.sql.Date; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class YPJob implements Job { + + @Autowired + private IParcelService parcelService; + @Autowired + private IPlatformOrderService platformOrderService; + + private final static String URL = "http://www.yuanpeng56.com:8082/selectTrack.htm"; + + private static final Integer DEFAULT_NUMBER_OF_DAYS = 15; + private static final Integer DEFAULT_MAXIMUM_NUMBER_OF_PARCELS_PER_TRANSACTION = 800; + private static final List DEFAULT_TRANSPORTERS = Arrays.asList("法国普货小包专线"); + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + LocalDate endDate = LocalDate.now(); + LocalDate startDate = endDate.minusDays(DEFAULT_NUMBER_OF_DAYS); + List transporters = DEFAULT_TRANSPORTERS; + boolean overrideRestriction = false; + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + JobDataMap jobDataMap = context.getMergedJobDataMap(); + String parameter = ((String) jobDataMap.get("parameter")); + if (parameter != null) { + try { + JSONObject jsonObject = new JSONObject(parameter); + if (!jsonObject.isNull("startDate")) { + String startDateStr = jsonObject.getString("startDate"); + startDate = LocalDate.parse(startDateStr); + } + if (!jsonObject.isNull("endDate")) { + String endDateStr = jsonObject.getString("endDate"); + endDate = LocalDate.parse(endDateStr); + } + if (!jsonObject.isNull("transporters")) { + JSONArray transporterArray = jsonObject.getJSONArray("transporters"); + List transporterList = new ArrayList<>(); + for (int i = 0; i < transporterArray.length(); i++) { + transporterList.add(transporterArray.getString(i)); + } + transporters = transporterList; + } + if (!jsonObject.isNull("override")) { + overrideRestriction = jsonObject.getBoolean("override"); + } + } catch (JSONException e) { + log.error("Error while parsing parameter as JSON, falling back to default parameters."); + } + } + + if (!endDate.isAfter(startDate)) { + throw new RuntimeException("EndDate must be strictly greater than StartDate !"); + } else if (endDate.minusDays(30).isAfter(startDate) && !overrideRestriction) { + throw new RuntimeException("No more than 30 days can separate startDate and endDate !"); + } + + log.info("Starting to retrieve parcel traces of {} from {} to {}", transporters, startDate, endDate); + List billCodes = platformOrderService.fetchBillCodesOfParcelsWithoutTrace( + Date.valueOf(startDate), Date.valueOf(endDate), transporters); + log.info("{} parcels without trace in total", billCodes.size()); + List> billCodeLists = Lists.partition(billCodes, 40); + log.info("Requests will be divided in to {} parts", billCodeLists.size()); + List parcelTraces = new ArrayList<>(); + List hlRequests = new ArrayList<>(); + billCodeLists.forEach(billcodeList -> { + HLRequest hlRequest = new HLRequest(URL, billcodeList); + hlRequests.add(hlRequest); + }); + List results = new ArrayList<>(); + for (HLRequest request : hlRequests) { + boolean success = false; + HttpEntity entity = request.send().getEntity(); + try { + // String of the response + String responseString = EntityUtils.toString(entity, "UTF-8"); + // Geniuses at HL decided to put the sole response object in an array.... + HLResponse[] hlResponseArray = mapper.readValue(responseString, HLResponse[].class); + parcelTraces.addAll(hlResponseArray[0].getResponseItems()); + success = true; + } catch (IOException e) { + log.error("Error while parsing response into String", e); + } finally { + results.add(success); + } + log.info("{} parcel added to the queue to be inserted into DB.", parcelTraces.size()); + } + long nbSuccesses = results.stream().filter(b -> b).count(); + log.info("{}/{} lots of 40 parcel traces have been retrieved.", nbSuccesses, hlRequests.size()); + + List> parcelTraceList = Lists.partition(parcelTraces, DEFAULT_MAXIMUM_NUMBER_OF_PARCELS_PER_TRANSACTION); + for (List parcelTracesPerTransaction : parcelTraceList) { + parcelService.saveHLParcelAndTraces(parcelTracesPerTransaction); + } + } + +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java index a143e23b2..ece603025 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java @@ -19,9 +19,9 @@ import java.util.Objects; * @Description: 平台订单内容 * @Author: jeecg-boot * @Date: 2023-11-28 - * @Version: V1.4 + * @Version: V1.5 */ -@ApiModel(value = "platform_order对象", description = "平台订单表") +@ApiModel(value = "platform_order_content对象", description = "平台订单内容") @Data @TableName("platform_order_content") public class PlatformOrderContent implements Serializable { @@ -133,6 +133,13 @@ public class PlatformOrderContent implements Serializable { @Excel(name = "海外仓操作费", width = 15) @ApiModelProperty(value = "海外仓操作费") private java.math.BigDecimal pickingFee; + /** + * 商品多属性 + */ + @Excel(name = "商品多属性", width = 15) + @ApiModelProperty(value = "商品多属性") + private java.lang.String customizationData; + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml index 684b8c313..351832dff 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml @@ -189,14 +189,14 @@ INSERT INTO platform_order_content( id, create_by, create_time, update_by, update_time, platform_order_id, - sku_id, quantity, erp_status, product_available) + sku_id, quantity, erp_status, product_available, customization_data) VALUES ( UUID(), 'Mabang API', NOW(), 'Mabang API', NOW(), #{item.platformOrderId}, skuErpToId(#{item.erpCode}), #{item.quantity}, #{item.erpStatus}, - #{item.productAvailable}) + #{item.productAvailable}, #{item.specifics}) diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java index f97b2abb5..0c8fe4820 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java @@ -1,5 +1,7 @@ package org.jeecg.modules.business.service; +import com.aspose.cells.SaveFormat; +import com.aspose.cells.Workbook; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; @@ -34,7 +36,10 @@ import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -106,6 +111,11 @@ public class PlatformOrderShippingInvoiceService { @Value("${jeecg.path.shippingInvoiceDetailDir}") private String INVOICE_DETAIL_DIR; + @Value("${jeecg.path.shippingInvoicePdfDir}") + private String INVOICE_PDF_DIR; + @Value("${jeecg.path.shippingInvoiceDetailPdfDir}") + private String INVOICE_DETAIL_PDF_DIR; + private static final String EXTENSION = ".xlsx"; private final static String[] DETAILS_TITLES = { "Boutique", @@ -563,6 +573,107 @@ public class PlatformOrderShippingInvoiceService { return invoiceList; } + + /** Finds the absolute path of invoice file by recursively walking the directory and it's subdirectories + * + * @param dirPath + * @param invoiceNumber + * @return List of paths for the file but should only find one result + */ + public List getPath(String dirPath, String invoiceNumber) { + List pathList = new ArrayList<>(); + //Recursively list all files + //The walk() method returns a Stream by walking the file tree beginning with a given starting file/directory in a depth-first manner. + try (Stream stream = Files.walk(Paths.get(dirPath))) { + pathList = stream.map(Path::normalize) + .filter(Files::isRegularFile) // directories, hidden files and files without extension are not included + .filter(path -> path.getFileName().toString().contains(invoiceNumber)) + .filter(path -> path.getFileName().toString().endsWith(EXTENSION)) + .collect(Collectors.toList()); + } + catch(IOException e) { + e.printStackTrace(); + } + return pathList; + } + + /** Finds the absolute path of invoice file by recursively walking the directory and it's subdirectories + * + * @param dirPath + * @param invoiceNumber + * @return List of paths for the file but should only find one result + */ + public List getPath(String dirPath, String invoiceNumber, String invoiceEntity) { + List pathList = new ArrayList<>(); + //Recursively list all files + //The walk() method returns a Stream by walking the file tree beginning with a given starting file/directory in a depth-first manner. + try (Stream stream = Files.walk(Paths.get(dirPath))) { + pathList = stream.map(Path::normalize) + .filter(Files::isRegularFile) // directories, hidden files and files without extension are not included + .filter(path -> path.getFileName().toString().contains(invoiceNumber)) + .filter(path -> path.getFileName().toString().contains(invoiceEntity)) + .filter(path -> path.getFileName().toString().endsWith(EXTENSION)) + .collect(Collectors.toList()); + } + catch(IOException e) { + e.printStackTrace(); + } + return pathList; + } + + /** + * Finds the absolute path of invoice file and return the path + * @param invoiceNumber + * @param filetype if it's an invoice or invoice detail + * @return String returns the path of the invoice file + */ + public String getInvoiceList(String invoiceNumber, String filetype) { + log.info("Invoice number : " + invoiceNumber); + List pathList = new ArrayList<>(); + if(filetype.equals("invoice")) { + log.info("File asked is of type invoice"); + pathList = getPath(INVOICE_DIR, invoiceNumber); + } + if(filetype.equals("detail")) { + log.info("File asked is of type invoice detail"); + pathList = getPath(INVOICE_DETAIL_DIR, invoiceNumber); + } + if(pathList.isEmpty()) { + log.error("NO INVOICE FILE FOUND : " + invoiceNumber); + return "ERROR"; + } + else { + for (Path path : pathList) { + log.info(path.toString()); + } + return pathList.get(0).toString(); + } + } + public String convertToPdf(String invoiceNumber, String fileType) throws Exception { + String excelFilePath = getInvoiceList(invoiceNumber, fileType);// (C:\PATH\filename.xlsx) + + if(!excelFilePath.equals("ERROR")) { + String pdfFilePath= INVOICE_PDF_DIR + "/" + invoiceNumber + ".pdf"; + if(fileType.equals("invoice")){ + pdfFilePath = INVOICE_PDF_DIR + "/Invoice N°" + invoiceNumber + ".pdf"; + } + if(fileType.equals("detail")) { + pdfFilePath = INVOICE_DETAIL_PDF_DIR + "/Détail_calcul_de_facture_" + 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 + Workbook workbook = new Workbook(excelFilePath); + // On enregistre le document au format PDF + workbook.save(pdfFilePath, SaveFormat.PDF); + return pdfFilePath; + } + return "ERROR"; + } @Transactional public String zipInvoices(List invoiceList) throws IOException { log.info("Zipping Invoices ..."); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java index 6af2ec090..f29ab4e43 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java @@ -1,5 +1,6 @@ package org.jeecg.modules.business.service.impl; +import freemarker.cache.ClassTemplateLoader; import freemarker.cache.FileTemplateLoader; import freemarker.cache.TemplateLoader; import freemarker.template.Configuration; @@ -118,11 +119,9 @@ public class EmailServiceImpl implements EmailService { } @Override @Transactional - public FreeMarkerConfigurer freemarkerClassLoaderConfig() throws IOException { + public FreeMarkerConfigurer freemarkerClassLoaderConfig() { Configuration configuration = new Configuration(Configuration.VERSION_2_3_31); - TemplateLoader templateLoader = new FileTemplateLoader(new File(env.getProperty("jeecg.path.emailTemplateDir"))) { - }; - configuration.setTemplateLoader(templateLoader); + configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), "/templates")); FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer(); freeMarkerConfigurer.setConfiguration(configuration); return freeMarkerConfigurer; diff --git a/pom.xml b/pom.xml index 9bfd92c41..c42e2d69b 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.jeecgframework.boot jeecg-boot-parent - 1.6.0 + 1.8.1 pom WIA APP ${project.version}