diff --git a/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfMergeService.java b/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfMergeService.java new file mode 100644 index 0000000..d4dfb93 --- /dev/null +++ b/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfMergeService.java @@ -0,0 +1,144 @@ +package com.ffii.lioner.modules.lioner.pdf.service; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; + +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.springframework.stereotype.Service; + +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.utils.PdfMerger; + +@Service +public class PdfMergeService { + + public void mergePdfs() throws IOException { + // Load PDF A and PDF B + String filePathA = "C:\\dev\\pdf\\pdfA.pdf"; + File fileA = new File(filePathA); + + String filePathB = "C:\\dev\\pdf\\pdfB.pdf"; + File fileB = new File(filePathB); + + String outputPath = "C:\\dev\\pdf\\pdfOut.pdf"; + + try ( + PDDocument pdfA = Loader.loadPDF(fileA); + PDDocument pdfB = Loader.loadPDF(fileB); + + PDDocument mergedPdf = new PDDocument()) { + + for (int i = 0; i < pdfB.getNumberOfPages(); i++) { + PDPage page = pdfB.getPage(i); + mergedPdf.addPage(page); + } + + //this is for remove the password and copy the whole pdf + //pdfB.setAllSecurityToBeRemoved(true); + //pdfB.save(new File(outputPath)); + + // Save the merged PDF + mergedPdf.save(new File(outputPath)); + } + } + + public byte[] mergePdfsItext7(String formCode, byte[] pdfABytes, byte[] pdfBBytes) throws IOException { + + // Defined constants for clarity + final int IDA_SIG_PAGE = 11; // Page to skip for IDA + final int FNA_SIG_PAGE = 7; // Page to skip for FNA + final int HSBC_REP_PAGE = 11; // Page to replace for HSBCFIN + + // Use java.io.ByteArrayOutputStream + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + + PdfWriter writer = new PdfWriter(baos); + PdfDocument mergedPdf = new PdfDocument(writer); + PdfMerger merger = new PdfMerger(mergedPdf); + + // 1. Process PDF A (The primary document) + try (PdfReader readerA = new PdfReader(new ByteArrayInputStream(pdfABytes)); + PdfDocument docA = new PdfDocument(readerA)) { + + int totalPagesA = docA.getNumberOfPages(); + + if ("IDA".equals(formCode) && totalPagesA >= IDA_SIG_PAGE) { + // --- IDA: SKIP page 11, then merge rest of A --- + + // Copy pages 1 through 10 (IDA_SIG_PAGE - 1) + if (IDA_SIG_PAGE > 1) { + merger.merge(docA, 1, IDA_SIG_PAGE - 1); + } + // Copy pages 12 through the end (IDA_SIG_PAGE + 1) + if (totalPagesA > IDA_SIG_PAGE) { + merger.merge(docA, IDA_SIG_PAGE + 1, totalPagesA); + } + + } else if ("FNA".equals(formCode) && totalPagesA >= FNA_SIG_PAGE) { + // --- FNA: SKIP page 7, then merge rest of A --- + + // Copy pages 1 through 6 (FNA_SIG_PAGE - 1) + if (FNA_SIG_PAGE > 1) { + merger.merge(docA, 1, FNA_SIG_PAGE - 1); + } + // Copy pages 8 through the end (FNA_SIG_PAGE + 1) + if (totalPagesA > FNA_SIG_PAGE) { + merger.merge(docA, FNA_SIG_PAGE + 1, totalPagesA); + } + + } else if ("HSBCFIN".equals(formCode) && totalPagesA >= HSBC_REP_PAGE) { + // --- HSBCFIN: REPLACE page 11 with PDF B page 1 --- + + // A. Copy pages 1 up to 10 (HSBC_REP_PAGE - 1) + if (HSBC_REP_PAGE > 1) { + merger.merge(docA, 1, HSBC_REP_PAGE - 1); + } + + // B. Insert replacement page from PDF B (if available) + if (pdfBBytes != null && pdfBBytes.length > 0) { + try (PdfReader readerB = new PdfReader(new ByteArrayInputStream(pdfBBytes)); + PdfDocument docB = new PdfDocument(readerB)) { + + // Copy ONLY page 1 from docB + merger.merge(docB, 1, 1); + } + } + + // C. Copy pages 12 through the end (HSBC_REP_PAGE + 1) + if (totalPagesA > HSBC_REP_PAGE) { + merger.merge(docA, HSBC_REP_PAGE + 1, totalPagesA); + } + + } else { + // Default: Copy all pages from docA + merger.merge(docA, 1, totalPagesA); + } + } + + // 2. Process PDF B (Only appended if IDA or FNA, as HSBCFIN already merged it) + if (pdfBBytes != null && pdfBBytes.length > 0) { + if ("IDA".equals(formCode) || "FNA".equals(formCode)){ + try (PdfReader readerB = new PdfReader(new ByteArrayInputStream(pdfBBytes)); + PdfDocument docB = new PdfDocument(readerB)) { + + // Copy ONLY page 1 from docB to append as the last page + merger.merge(docB, 1, 1); + } + } + } + + // 3. Close the merged PDF document + mergedPdf.close(); + + // 4. Return the resulting byte array + return baos.toByteArray(); + + } // baos is closed here + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfService.java b/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfService.java index 20699b6..902d84e 100644 --- a/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfService.java +++ b/src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfService.java @@ -313,18 +313,20 @@ public class PdfService extends AbstractBaseEntityService> list(Map args){ StringBuilder sql = new StringBuilder("SELECT" + " (select concat('V', count(1) + 1) from filled_form where clientId = ff.clientId and templateId = ff.templateId and id < ff.id) as vNum, " + + " (select f.id from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload1' and fr.refId = ff.id order by fr.id desc limit 1) as upload1FileId, " + + " (select f.skey from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload1' and fr.refId = ff.id order by fr.id desc limit 1) as uploadFileSkey, " + + " (select f.id from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload2' and fr.refId = ff.id order by fr.id desc limit 1) as upload2FileId, " + + " (select f.skey from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload2' and fr.refId = ff.id order by fr.id desc limit 1) as upload2FileSkey, " + + " ff.id, " + " ff.templateId, " + " ff.fileId, " @@ -2411,15 +2422,27 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany1_1(fieldValue); case "fill_11_7_1" -> commonField.setInsuranceCompany1_2(fieldValue); - case "fill_11_7_2" -> commonField.setInsuranceCompany1_3(fieldValue); + //case "fill_11_7_2" -> commonField.setInsuranceCompany1_3(fieldValue); case "fill_12_7_1" -> { commonField.getOthers().put("insuranceSumInsured1_1", fieldValue); @@ -2630,7 +2649,7 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany2_1(fieldValue); case "fill_13_7_1" -> commonField.setInsuranceCompany2_2(fieldValue); - case "fill_13_7_2" -> commonField.setInsuranceCompany2_3(fieldValue); + //case "fill_13_7_2" -> commonField.setInsuranceCompany2_3(fieldValue); case "fill_14_7_1" -> { commonField.getOthers().put("insuranceSumInsured2_1", fieldValue); @@ -2662,7 +2681,7 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany3_1(fieldValue); case "fill_15_7_1" -> commonField.setInsuranceCompany3_2(fieldValue); - case "fill_15_7_2" -> commonField.setInsuranceCompany3_3(fieldValue); + //case "fill_15_7_2" -> commonField.setInsuranceCompany3_3(fieldValue); case "fill_16_7_1" -> { commonField.getOthers().put("insuranceSumInsured3_1", fieldValue); @@ -3046,9 +3065,104 @@ public class PdfService extends AbstractBaseEntityService commonField.setFna_c2f_50(fieldValue); /* Page5 End */ + } + } + + private void MLB03S(String fieldName, String fieldValue, CommonField commonField,PDAcroForm acroForm){ + switch (fieldName) { + /* Page1 Start */ + case "SurName1" -> commonField.setFirstName(fieldValue); + case "GivenName1" -> commonField.setGivenName(fieldValue); + case "ChineseName1" -> commonField.setNameChi(fieldValue); + + case "male" -> commonField.setGenderMale(fieldValue); + case "female" -> commonField.setGenderFemale(fieldValue); + + case "DD1" -> commonField.setDdDateOfBirth(fieldValue); + case "MM1" -> commonField.setMmDateOfBirth(fieldValue); + case "YYYY1" -> commonField.setYyyyDateOfBirth(fieldValue); + + case "hk" -> { + if("Yes".equals(fieldValue)) + commonField.setPlaceOfBirth("Hong Kong"); + } + case "macau" -> { + if("Yes".equals(fieldValue)) + commonField.setPlaceOfBirth("Macau"); + } + case "Field_LocationA1" -> commonField.setPlaceOfBirth(fieldValue); + case "Field_LocationB1" -> commonField.setPlaceOfBirth(fieldValue); + + case "ID1" -> commonField.setIdCard(fieldValue); + + case "Nationality1" -> commonField.setCountryOfCitizenship(fieldValue); + case "Company1" -> commonField.setCompanyName(fieldValue); + case "BusinessNature1" -> commonField.setCompanyNature1(fieldValue); + case "BusinessNature2" -> commonField.setCompanyNature2(fieldValue); + case "Occupation1" -> commonField.setOccupation(fieldValue); + case "JobNature1" -> commonField.setOccupationTitle(fieldValue); + //Income1 = IDA commonField.getIncomeSalary() + commonField.getIncomeBonus() ??? beware of it may have , and english P.A. or even USD + case "Room1" -> commonField.getOthers().put("crAddressRoom", fieldValue); + case "Floor1" -> commonField.getOthers().put("crAddressFloor", fieldValue); + case "Block1" -> commonField.getOthers().put("crAddressBlock", fieldValue); + case "Building1" -> commonField.getOthers().put("crAddressBuilding", fieldValue); + case "Street1" -> commonField.getOthers().put("crAddressStreet", fieldValue); + case "City1" -> commonField.getOthers().put("crAddressCity", fieldValue); + case "District1" -> commonField.getOthers().put("crAddressDistrict", fieldValue); + case "Country1" -> commonField.getOthers().put("crAddressCountry", fieldValue); + case "PostalCode1" -> commonField.getOthers().put("crAddressPostalCode", fieldValue); + case "Checkbox_Y" -> commonField.setTobarccoYes(fieldValue); + case "Checkbox_N" -> commonField.setTobarccoNo(fieldValue); + /* Page1 End */ + /* Page2 Start */ + case "Room3" -> commonField.getOthers().put("corAddressRoom", fieldValue); + case "Floor3" -> commonField.getOthers().put("corAddressFloor", fieldValue); + case "Block3" -> commonField.getOthers().put("corAddressBlock", fieldValue); + case "Building3" -> commonField.getOthers().put("corAddressBuilding", fieldValue); + case "Street3" -> commonField.getOthers().put("corAddressStreet", fieldValue); + case "City3" -> commonField.getOthers().put("corAddressCity", fieldValue); + case "District3" -> commonField.getOthers().put("corAddressDistrict", fieldValue); + case "Country3" -> commonField.getOthers().put("corAddressCountry", fieldValue); + case "PostalCode3" -> commonField.getOthers().put("corAddressPostalCode", fieldValue); + case "ContactB1" -> commonField.setContactNo(fieldValue); + case "Email" -> commonField.setEmail(fieldValue); + /* Page2 End */ + /* Page3 Start */ + case "Checkbox_Wealth1" -> commonField.getOthers().put("sourceIncome", fieldValue); + case "Checkbox_Wealth2" -> commonField.getOthers().put("sourceInvestment", fieldValue); + case "Checkbox_Wealth3" -> commonField.getOthers().put("sourceInheritance", fieldValue); + case "Checkbox_Wealth4" -> commonField.getOthers().put("sourceOther", fieldValue); + case "Field_Wealth4" -> commonField.getOthers().put("sourceOtherDesc", fieldValue); + + case "Checkbox_EudcationPri" -> commonField.setEduPri(fieldValue); + case "Checkbox_EudcationSec" -> commonField.setEduSec(fieldValue); + case "Checkbox_EudcationPostSec" -> commonField.setEduPostSec(fieldValue); + case "Checkbox_EudcationTer" -> commonField.setEduUni(fieldValue); + /* Page3 End */ + /* Page7 Start */ + + case "Residency1" -> commonField.setTaxResidency1(fieldValue); + case "Residency2" -> commonField.setTaxResidency2(fieldValue); + case "Residency3" -> commonField.setTaxResidency3(fieldValue); + case "TIN1" -> commonField.setTaxPin1(fieldValue); + case "TIN2" -> commonField.setTaxPin2(fieldValue); + case "TIN3" -> commonField.setTaxPin3(fieldValue); + case "ABC1" -> commonField.setTaxReason1(fieldValue); + case "ABC2" -> commonField.setTaxReason2(fieldValue); + case "ABC3" -> commonField.setTaxReason3(fieldValue); + case "Reason1" -> commonField.setTaxReasonB1(fieldValue); + case "Reason2" -> commonField.setTaxReasonB2(fieldValue); + case "Reason3" -> commonField.setTaxReasonB3(fieldValue); + + /* Page7 End */ + /* Page8 Start */ + case "c_DeclartionYes" -> commonField.setReplaceInsuranceYes(fieldValue); + case "c_DeclartionNo" -> commonField.setReplaceInsuranceNo(fieldValue); + /* Page8 End */ + } } @@ -3372,7 +3486,7 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany1_1(fieldValue); case "4_1_name1_2" -> commonField.setInsuranceCompany1_2(fieldValue); - case "4_1_name1_3" -> commonField.setInsuranceCompany1_3(fieldValue); + //case "4_1_name1_3" -> commonField.setInsuranceCompany1_3(fieldValue); case "4_1_year1" -> commonField.setInsuranceYear1(fieldValue); case "4_1_currency1" -> commonField.setInsuranceCurrency1(fieldValue); case "4_1_sum1_1" -> commonField.getOthers().put("insuranceSumInsured1_1", fieldValue); @@ -3423,7 +3537,7 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany2_1(fieldValue); case "4_1_name2_2" -> commonField.setInsuranceCompany2_2(fieldValue); - case "4_1_name2_3" -> commonField.setInsuranceCompany2_3(fieldValue); + //case "4_1_name2_3" -> commonField.setInsuranceCompany2_3(fieldValue); case "4_1_year2" -> commonField.setInsuranceYear2(fieldValue); case "4_1_currency2" -> commonField.setInsuranceCurrency2(fieldValue); case "4_1_sum2_1" -> commonField.getOthers().put("insuranceSumInsured2_1", fieldValue); @@ -3474,7 +3588,7 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany3_1(fieldValue); case "4_1_name3_2" -> commonField.setInsuranceCompany3_2(fieldValue); - case "4_1_name3_3" -> commonField.setInsuranceCompany3_3(fieldValue); + //case "4_1_name3_3" -> commonField.setInsuranceCompany3_3(fieldValue); case "4_1_year3" -> commonField.setInsuranceYear3(fieldValue); case "4_1_currency3" -> commonField.setInsuranceCurrency3(fieldValue); case "4_1_sum3_1" -> commonField.getOthers().put("insuranceSumInsured3_1", fieldValue); @@ -3664,104 +3778,6 @@ public class PdfService extends AbstractBaseEntityService commonField.setFirstName(fieldValue); - case "GivenName1" -> commonField.setGivenName(fieldValue); - case "ChineseName1" -> commonField.setNameChi(fieldValue); - - case "male" -> commonField.setGenderMale(fieldValue); - case "female" -> commonField.setGenderFemale(fieldValue); - - case "DD1" -> commonField.setDdDateOfBirth(fieldValue); - case "MM1" -> commonField.setMmDateOfBirth(fieldValue); - case "YYYY1" -> commonField.setYyyyDateOfBirth(fieldValue); - - case "hk" -> { - if("Yes".equals(fieldValue)) - commonField.setPlaceOfBirth("Hong Kong"); - } - case "macau" -> { - if("Yes".equals(fieldValue)) - commonField.setPlaceOfBirth("Macau"); - } - case "Field_LocationA1" -> commonField.setPlaceOfBirth(fieldValue); - case "Field_LocationB1" -> commonField.setPlaceOfBirth(fieldValue); - - case "ID1" -> commonField.setIdCard(fieldValue); - - case "Nationality1" -> commonField.setCountryOfCitizenship(fieldValue); - case "Company1" -> commonField.setCompanyName(fieldValue); - case "BusinessNature1" -> commonField.setCompanyNature1(fieldValue); - case "BusinessNature2" -> commonField.setCompanyNature2(fieldValue); - case "Occupation1" -> commonField.setOccupation(fieldValue); - case "JobNature1" -> commonField.setOccupationTitle(fieldValue); - - //Income1 = IDA commonField.getIncomeSalary() + commonField.getIncomeBonus() ??? beware of it may have , and english P.A. or even USD - case "Room1" -> commonField.getOthers().put("crAddressRoom", fieldValue); - case "Floor1" -> commonField.getOthers().put("crAddressFloor", fieldValue); - case "Block1" -> commonField.getOthers().put("crAddressBlock", fieldValue); - case "Building1" -> commonField.getOthers().put("crAddressBuilding", fieldValue); - case "Street1" -> commonField.getOthers().put("crAddressStreet", fieldValue); - case "City1" -> commonField.getOthers().put("crAddressCity", fieldValue); - case "District1" -> commonField.getOthers().put("crAddressDistrict", fieldValue); - case "Country1" -> commonField.getOthers().put("crAddressCountry", fieldValue); - case "PostalCode1" -> commonField.getOthers().put("crAddressPostalCode", fieldValue); - - case "Checkbox_Y" -> commonField.setTobarccoYes(fieldValue); - case "Checkbox_N" -> commonField.setTobarccoNo(fieldValue); - /* Page1 End */ - /* Page2 Start */ - case "Room3" -> commonField.getOthers().put("corAddressRoom", fieldValue); - case "Floor3" -> commonField.getOthers().put("corAddressFloor", fieldValue); - case "Block3" -> commonField.getOthers().put("corAddressBlock", fieldValue); - case "Building3" -> commonField.getOthers().put("corAddressBuilding", fieldValue); - case "Street3" -> commonField.getOthers().put("corAddressStreet", fieldValue); - case "City3" -> commonField.getOthers().put("corAddressCity", fieldValue); - case "District3" -> commonField.getOthers().put("corAddressDistrict", fieldValue); - case "Country3" -> commonField.getOthers().put("corAddressCountry", fieldValue); - case "PostalCode3" -> commonField.getOthers().put("corAddressPostalCode", fieldValue); - - case "ContactB1" -> commonField.setContactNo(fieldValue); - case "Email" -> commonField.setEmail(fieldValue); - /* Page2 End */ - /* Page3 Start */ - case "Checkbox_Wealth1" -> commonField.getOthers().put("sourceIncome", fieldValue); - case "Checkbox_Wealth2" -> commonField.getOthers().put("sourceInvestment", fieldValue); - case "Checkbox_Wealth3" -> commonField.getOthers().put("sourceInheritance", fieldValue); - case "Checkbox_Wealth4" -> commonField.getOthers().put("sourceOther", fieldValue); - case "Field_Wealth4" -> commonField.getOthers().put("sourceOtherDesc", fieldValue); - - case "Checkbox_EudcationPri" -> commonField.setEduPri(fieldValue); - case "Checkbox_EudcationSec" -> commonField.setEduSec(fieldValue); - case "Checkbox_EudcationPostSec" -> commonField.setEduPostSec(fieldValue); - case "Checkbox_EudcationTer" -> commonField.setEduUni(fieldValue); - /* Page3 End */ - /* Page7 Start */ - - case "Residency1" -> commonField.setTaxResidency1(fieldValue); - case "Residency2" -> commonField.setTaxResidency2(fieldValue); - case "Residency3" -> commonField.setTaxResidency3(fieldValue); - case "TIN1" -> commonField.setTaxPin1(fieldValue); - case "TIN2" -> commonField.setTaxPin2(fieldValue); - case "TIN3" -> commonField.setTaxPin3(fieldValue); - case "ABC1" -> commonField.setTaxReason1(fieldValue); - case "ABC2" -> commonField.setTaxReason2(fieldValue); - case "ABC3" -> commonField.setTaxReason3(fieldValue); - case "Reason1" -> commonField.setTaxReasonB1(fieldValue); - case "Reason2" -> commonField.setTaxReasonB2(fieldValue); - case "Reason3" -> commonField.setTaxReasonB3(fieldValue); - - /* Page7 End */ - /* Page8 Start */ - case "c_DeclartionYes" -> commonField.setReplaceInsuranceYes(fieldValue); - case "c_DeclartionNo" -> commonField.setReplaceInsuranceNo(fieldValue); - /* Page8 End */ - - } - } - private void SLGII(String fieldName, String fieldValue, CommonField commonField,PDAcroForm acroForm){ switch (fieldName) { /* Page1 Start */ @@ -3892,13 +3908,13 @@ public class PdfService extends AbstractBaseEntityService commonField.setInsuranceCompany1_1(fieldValue); case "4_1_name1_2" -> commonField.setInsuranceCompany1_2(fieldValue); - case "4_1_name1_3" -> commonField.setInsuranceCompany1_3(fieldValue); + //case "4_1_name1_3" -> commonField.setInsuranceCompany1_3(fieldValue); case "4_1_name2_1" -> commonField.setInsuranceCompany2_1(fieldValue); case "4_1_name2_2" -> commonField.setInsuranceCompany2_2(fieldValue); - case "4_1_name2_3" -> commonField.setInsuranceCompany2_3(fieldValue); + //case "4_1_name2_3" -> commonField.setInsuranceCompany2_3(fieldValue); case "4_1_name3_1" -> commonField.setInsuranceCompany3_1(fieldValue); case "4_1_name3_2" -> commonField.setInsuranceCompany3_2(fieldValue); - case "4_1_name3_3" -> commonField.setInsuranceCompany3_3(fieldValue); + //case "4_1_name3_3" -> commonField.setInsuranceCompany3_3(fieldValue); case "4_1_year1" -> commonField.setInsuranceYear1(fieldValue); case "4_1_year2" -> commonField.setInsuranceYear2(fieldValue); case "4_1_year3" -> commonField.setInsuranceYear3(fieldValue); @@ -4274,4 +4290,27 @@ public class PdfService extends AbstractBaseEntityService getFilledFormPdf(Long id) { + StringBuilder sql = new StringBuilder("SELECT" + + " ff.fileId, " + + " f.skey as fileSkey, " + + + " (select f.id from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload1' and fr.refId = ff.id order by fr.id desc limit 1) as upload1FileId, " + + " (select f.id from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload2' and fr.refId = ff.id order by fr.id desc limit 1) as upload2FileId, " + + + " ff.id, " + + " ff.remarks, " + + " f.filename, " + + " t.remarks AS formCode, " + + " fb.bytes AS blobValue " + + " FROM filled_form ff " + + " LEFT JOIN file f ON f.id = ff.fileId " + + " LEFT JOIN file_blob fb ON f.id = fb.fileId " + + " LEFT JOIN template t ON t.id = ff.templateId " + + " WHERE ff.deleted = FALSE " + + " AND ff.id = :id " + ); + return jdbcDao.queryForMap(sql.toString(), Map.of("id", id)).orElse(null); + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/lioner/modules/lioner/pdf/web/PdfController.java b/src/main/java/com/ffii/lioner/modules/lioner/pdf/web/PdfController.java index 9d2e697..d146472 100644 --- a/src/main/java/com/ffii/lioner/modules/lioner/pdf/web/PdfController.java +++ b/src/main/java/com/ffii/lioner/modules/lioner/pdf/web/PdfController.java @@ -1,18 +1,20 @@ package com.ffii.lioner.modules.lioner.pdf.web; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.UUID; +import java.util.Optional; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; @@ -22,21 +24,18 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import com.ffii.core.response.DataRes; import com.ffii.core.response.RecordsRes; import com.ffii.core.utils.CriteriaArgsBuilder; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.validation.Valid; -import com.ffii.core.exception.NotFoundException; import com.ffii.core.utils.Params; - -import com.ffii.lioner.modules.lioner.pdf.req.UpdatePdfReq; +import com.ffii.lioner.modules.lioner.entity.FileBlob; +import com.ffii.lioner.modules.lioner.pdf.service.PdfMergeService; import com.ffii.lioner.modules.lioner.pdf.service.PdfService; +import com.ffii.lioner.modules.lioner.service.FileService; +import com.itextpdf.io.source.ByteArrayOutputStream; + +import jakarta.servlet.http.HttpServletRequest; @RestController @@ -44,6 +43,13 @@ import com.ffii.lioner.modules.lioner.pdf.service.PdfService; @CrossOrigin(origins = "", allowedHeaders = "") public class PdfController { + protected final Log logger = LogFactory.getLog(getClass()); + + @Autowired + private PdfMergeService pdfMergeService; + + @Autowired + private FileService fileService; private PdfService pdfService; @@ -129,4 +135,169 @@ public class PdfController { response.put("message", "Form data received and processed successfully."); return ResponseEntity.ok(response); } + + @GetMapping("/merge-pdf") + public String mergePdf() { + try { + pdfMergeService.mergePdfs(); + return "PDFs merged successfully"; + } catch (IOException e) { + return "Error merging PDFs: " + e.getMessage(); + } + } + + //this if for upload signiture 1 for PDF form merging later + @PostMapping("/upload1") + public ResponseEntity> upload1(@RequestParam("file") MultipartFile file, @RequestParam Long refId, @RequestParam String refType) { + try { + MultipartFile[] files = new MultipartFile[1]; + files[0] = file; + + fileService.saveOrUpdate(files, refId, refType); + + Map response = new HashMap<>(); + response.put("message", "File uploaded and processed successfully."); + + return ResponseEntity.ok(response); + } catch (Exception ex) { + Map errorBody = new HashMap<>(); + errorBody.put("message", "File upload failed: " + ex.getMessage()); + + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(errorBody); + } + } + + + @GetMapping(value = "/download-ff/{id}", produces = MediaType.APPLICATION_PDF_VALUE) + public ResponseEntity getMergedPdfByFilledFormId(@PathVariable Long id) throws IOException { + logger.info("XXXXXXXXXXXXXXX getMergedPdfByFilledFormId START XXXXXXXXXXXXXX"); + // --- 1. Fetch Data & Set up Variables --- + Map d = pdfService.getFilledFormPdf(id); + String formCode = (String) d.get("formCode"); + String filename = formCode + "-" + id + ".pdf"; + + Long fileId = Optional.ofNullable(d.get("fileId")) + .map(val -> ((Integer) val).longValue()) + .orElse(null); + + Long upload1FileId = Optional.ofNullable(d.get("upload1FileId")) + .map(val -> ((Integer) val).longValue()) + .orElse(null); + + // Safely retrieve byte arrays using Optional chaining (prevents NullPointerExceptions) + byte[] pdfBytes = Optional.ofNullable(fileId) + .flatMap(fileService::findFileBlobByFileId) + .map(FileBlob::getBytes) + .orElse(null); + + // Only fetch upload1 if needed (or if it's generally required) + byte[] pdfUpload1Bytes = Optional.ofNullable(upload1FileId) + .flatMap(fileService::findFileBlobByFileId) + .map(FileBlob::getBytes) + .orElse(null); + + // Check if the primary file is missing + if (pdfBytes == null || pdfBytes.length == 0) { + logger.info("Both null:"); + return ResponseEntity.notFound().build(); + } + + // --- 2. PDF Merging and Processing --- + byte[] finalPdfBytes = new byte[0]; + + logger.info("pdfBytes:" + pdfBytes.length); + logger.info("pdfUpload1Bytes:" + pdfUpload1Bytes.length); + logger.info("formCode:" + formCode); + + finalPdfBytes = pdfMergeService.mergePdfsItext7(formCode, pdfBytes, pdfUpload1Bytes); + + // --- 4. Build ResponseEntity --- + HttpHeaders headers = new HttpHeaders(); + // Use attachment for download, or inline for display in browser + headers.setContentDispositionFormData("attachment", filename); + headers.setContentType(MediaType.APPLICATION_PDF); + headers.setContentLength(finalPdfBytes.length); + + return new ResponseEntity<>(finalPdfBytes, headers, HttpStatus.OK); + } + + /* + + @GetMapping(value = "/download-ff", produces = MediaType.APPLICATION_PDF_VALUE) + public ResponseEntity getMergedPdfByFilledFormId(@PathVariable Long id) throws IOException { + Map d = pdfService.getFilledFormPdf(id); + + //get the filled form id + ; + byte[] pdfBytes = fileService.findFileBlobByFileId((Long)d.get("fileId")).orElse(null).getBytes(); + byte[] pdfUpload1Bytes = fileService.findFileBlobByFileId((Long)d.get("upload1FileId")).orElse(null).getBytes(); + PDDocument outputDoc = new PDDocument(); + + logger.info("formCode:" + d.get("formCode")); + if("IDA".equals(d.get("formCode"))){ + //page 9 is the sig page, so remove page 9 of pdf and merge the upload1 + //PDDocument sourceDoc = Loader.loadPDF(pdfBytes); + try (PDDocument sourceDoc = Loader.loadPDF(pdfBytes)) { + int pageCount = sourceDoc.getNumberOfPages(); + + logger.info("pageCount:" + pageCount); + } catch (IOException e) { + // This ONLY catches standard IO exceptions. It might not catch the S.O.E. + logger.info("IOException:" + e.toString()); + } + + try (PDDocument upload1Doc = Loader.loadPDF(pdfUpload1Bytes)) { + // ... + } catch (IOException e) { + // This ONLY catches standard IO exceptions. It might not catch the S.O.E. + logger.info("IOException:" + e.toString()); + } + + // You can now work with the document, e.g., get the number of pages + + + for (int i = 0; i < sourceDoc.getNumberOfPages(); i++) { + PDPage page = sourceDoc.getPage(i); + outputDoc.addPage(page); + } + + for (int i = 0; i < upload1Doc.getNumberOfPages(); i++) { + PDPage page = upload1Doc.getPage(i); + outputDoc.addPage(page); + } + + } + + HttpHeaders headers = new HttpHeaders(); + headers.setContentDispositionFormData("inline", "form.pdf"); + headers.setContentType(MediaType.APPLICATION_PDF); + return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK); + }*/ + + public byte[] convertPdfDocumentToBytes(PDDocument doc) throws IOException { + + // 1. Create a stream to hold the PDF's bytes in memory + // Use try-with-resources to ensure the stream is automatically closed. + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + + // 2. Save the PDDocument content into the ByteArrayOutputStream + // This process writes the entire PDF structure (objects, XRef, etc.) + doc.save(baos); + + // 3. Convert the content of the stream to a byte array + return baos.toByteArray(); + + } finally { + // 4. Important: Close the PDDocument to release resources + if (doc != null) { + doc.close(); + } + } + } + + + + }