From c21a8b50fe2de5e793731935ec593e224d3414d6 Mon Sep 17 00:00:00 2001 From: Qiuyi LI Date: Wed, 13 Sep 2023 16:40:40 +0200 Subject: [PATCH 1/6] Update project version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9bfd92c41..5bac8b14e 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.jeecgframework.boot jeecg-boot-parent - 1.6.0 + 1.6.1 pom WIA APP ${project.version} From bcf57915cc76f6c79e73968367acdb40d598d31a Mon Sep 17 00:00:00 2001 From: Qiuyi LI Date: Thu, 14 Sep 2023 16:12:40 +0200 Subject: [PATCH 2/6] Add thread executor service with throttling --- .../business/domain/job/IntervalWindow.java | 205 ++++++++++++++++++ .../domain/job/ThrottlingExecutorService.java | 166 ++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/IntervalWindow.java create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ThrottlingExecutorService.java 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 + } +} From a0db23999404bbbde2139f820f3da56b77e876d4 Mon Sep 17 00:00:00 2001 From: Qiuyi LI Date: Thu, 14 Sep 2023 16:13:48 +0200 Subject: [PATCH 3/6] Use ThrottlingExecutorService in ArchiveOrderJob as MabangAPI has a 300 requests per minute limit --- .../jeecg/modules/business/domain/job/ArchiveOrderJob.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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(); From 0561f8a87059d7040be46f03c71f2c6b10d1c5d2 Mon Sep 17 00:00:00 2001 From: Gauthier LO Date: Fri, 15 Sep 2023 11:02:50 +0200 Subject: [PATCH 4/6] fix: Excel display bug in invoices --- .../domain/invoice/AbstractInvoice.java | 79 +++++++++++++------ .../domain/invoice/InvoiceStyleFactory.java | 2 +- 2 files changed, 55 insertions(+), 26 deletions(-) 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..091904698 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,53 @@ 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; + System.out.println("initial TOTAL_ROW : " + TOTAL_ROW); 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(); + int fileLastRow = sheet.getLastRowNum(); //62 // 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); + System.out.println("additionalRowNum : " + additionalRowNum); + System.out.println("PAGE_ROW_MAX : " + PAGE_ROW_MAX); + System.out.println("additionalRowNum%PAGE_ROW_MAX : " + additionalRowNum%PAGE_ROW_MAX); + + // 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 +217,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 +234,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 +326,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 +343,14 @@ 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; + System.out.println(((LAST_ROW + additionalRowNum - 44) % 63)); + 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/invoice/InvoiceStyleFactory.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/InvoiceStyleFactory.java index cdb61645d..64f07119a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/InvoiceStyleFactory.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/invoice/InvoiceStyleFactory.java @@ -92,7 +92,7 @@ public class InvoiceStyleFactory { rightSideDecimalStyle.setVerticalAlignment(VerticalAlignment.CENTER); // decimal // DataFormat format =workbook.createDataFormat(); - leftSideStyle.setDataFormat(creationHelper.createDataFormat().getFormat("#,##0.00")); + rightSideDecimalStyle.setDataFormat(creationHelper.createDataFormat().getFormat("#,##0.00")); // font Font font = workbook.createFont(); font.setFontName("Arial"); From abada459bb59c8e281a18c277c24ad62c010c722 Mon Sep 17 00:00:00 2001 From: Qiuyi LI Date: Fri, 15 Sep 2023 11:20:28 +0200 Subject: [PATCH 5/6] Update AbstractInvoice.java Delete system.out.println --- .../modules/business/domain/invoice/AbstractInvoice.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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 091904698..da1086e6a 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 @@ -158,7 +158,6 @@ public abstract class AbstractInvoice { int dataRowNumber = LAST_ROW - FIRST_ROW; int additionalRowNum = Math.max(data.size() - dataRowNumber - 1, 0); TOTAL_ROW = LAST_ROW + additionalRowNum; - System.out.println("initial TOTAL_ROW : " + TOTAL_ROW); Sheet sheet = factory.getWorkbook().getSheetAt(0); 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) @@ -169,10 +168,7 @@ public abstract class AbstractInvoice { int fileLastRow = sheet.getLastRowNum(); //62 // 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 - System.out.println("additionalRowNum : " + additionalRowNum); - System.out.println("PAGE_ROW_MAX : " + PAGE_ROW_MAX); - System.out.println("additionalRowNum%PAGE_ROW_MAX : " + additionalRowNum%PAGE_ROW_MAX); - + // 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 @@ -343,7 +339,6 @@ public abstract class AbstractInvoice { if (targetClient.getCurrency().equals("USD")) { org.apache.poi.ss.usermodel.Row dollarRow; String formula; - System.out.println(((LAST_ROW + additionalRowNum - 44) % 63)); 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; From 8228862f3996373a6362f01964e38d2216a0d8e1 Mon Sep 17 00:00:00 2001 From: Qiuyi LI Date: Fri, 15 Sep 2023 11:21:37 +0200 Subject: [PATCH 6/6] Update AbstractInvoice.java Cleanup comments --- .../jeecg/modules/business/domain/invoice/AbstractInvoice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 da1086e6a..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 @@ -165,7 +165,7 @@ public abstract class AbstractInvoice { if(data.size() > dataRowNumber + 1) { int startRow = LAST_ROW+1; - int fileLastRow = sheet.getLastRowNum(); //62 + 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