Pārlūkot izejas kodu

no message

master
[email protected] pirms 1 dienas
vecāks
revīzija
956bb6868e
10 mainītis faili ar 222 papildinājumiem un 61 dzēšanām
  1. +1
    -0
      src/main/java/com/ffii/lioner/modules/lioner/client/service/ClientService.java
  2. +9
    -3
      src/main/java/com/ffii/lioner/modules/lioner/client/web/ClientController.java
  3. +0
    -12
      src/main/java/com/ffii/lioner/modules/lioner/pdf/entity/FormSigPage.java
  4. +0
    -12
      src/main/java/com/ffii/lioner/modules/lioner/pdf/req/UpdateFormSigPageReq.java
  5. +18
    -7
      src/main/java/com/ffii/lioner/modules/lioner/pdf/service/FormSigPageService.java
  6. +79
    -18
      src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfMergeService.java
  7. +84
    -2
      src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfService.java
  8. +2
    -3
      src/main/java/com/ffii/lioner/modules/lioner/pdf/web/FormSigPageController.java
  9. +25
    -4
      src/main/java/com/ffii/lioner/modules/lioner/pdf/web/PdfController.java
  10. +4
    -0
      src/main/resources/db/changelog/changes/39_form_sig_page_drop_action/01_drop_form_sig_page_action.sql

+ 1
- 0
src/main/java/com/ffii/lioner/modules/lioner/client/service/ClientService.java Parādīt failu

@@ -189,6 +189,7 @@ public class ClientService extends AbstractBaseEntityService<Client, Long, Clien

if (args.containsKey("fromDate")) sql += " AND c.created >= :fromDate ";
if (args.containsKey("toDate")) sql += " AND c.created < :toDate ";
if (args.containsKey("consultantIds")) sql += " AND c.consultantId IN (:consultantIds) ";
List<Map<String, Object>> data = jdbcDao.queryForList(sql, args);



+ 9
- 3
src/main/java/com/ffii/lioner/modules/lioner/client/web/ClientController.java Parādīt failu

@@ -152,13 +152,19 @@ public class ClientController{
public void exportClientConsultantReport(
@RequestParam("fromDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date fromDate,
@RequestParam("toDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date toDate,
@RequestParam(required = false) List<Long> consultantIds,
HttpServletResponse response) throws IOException {
Map<String, Object> args = new HashMap<>();
if(fromDate != null)
if (fromDate != null) {
args.put("fromDate", fromDate);
if(fromDate != null)
args.put("toDate", DateUtils.addDay(toDate, 1));
}
if (toDate != null) {
args.put("toDate", DateUtils.addDay(toDate, 1));
}
if (consultantIds != null && !consultantIds.isEmpty()) {
args.put("consultantIds", consultantIds);
}

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
String fileName = "Client_Consultant_Report.xlsx";


+ 0
- 12
src/main/java/com/ffii/lioner/modules/lioner/pdf/entity/FormSigPage.java Parādīt failu

@@ -34,10 +34,6 @@ public class FormSigPage extends BaseEntity<Long> {
@Column(name = "pageTo")
private Integer pageTo;

@NotBlank
@Column(name = "action")
private String action;

public String getFormCode() {
return formCode;
}
@@ -77,12 +73,4 @@ public class FormSigPage extends BaseEntity<Long> {
public void setPageTo(Integer pageTo) {
this.pageTo = pageTo;
}

public String getAction() {
return action;
}

public void setAction(String action) {
this.action = action;
}
}

+ 0
- 12
src/main/java/com/ffii/lioner/modules/lioner/pdf/req/UpdateFormSigPageReq.java Parādīt failu

@@ -27,10 +27,6 @@ public class UpdateFormSigPageReq {
@NotNull
private Integer pageTo;

@NotBlank
@Size(max = 30)
private String action;

public Long getId() {
return id;
}
@@ -78,12 +74,4 @@ public class UpdateFormSigPageReq {
public void setPageTo(Integer pageTo) {
this.pageTo = pageTo;
}

public String getAction() {
return action;
}

public void setAction(String action) {
this.action = action;
}
}

+ 18
- 7
src/main/java/com/ffii/lioner/modules/lioner/pdf/service/FormSigPageService.java Parādīt failu

@@ -2,6 +2,7 @@ package com.ffii.lioner.modules.lioner.pdf.service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -20,6 +21,7 @@ public class FormSigPageService {

private static final String UPLOAD1 = "upload1";
private static final String UPLOAD2 = "upload2";
private static final String UPLOAD3 = "upload3";

private final FormSigPageRepository formSigPageRepository;

@@ -54,7 +56,6 @@ public class FormSigPageService {
entity.setSigType(req.getSigType());
entity.setPageFrom(req.getPageFrom());
entity.setPageTo(req.getPageTo());
entity.setAction(req.getAction());
} else {
entity = new FormSigPage();
entity.setFormCode(req.getFormCode());
@@ -62,7 +63,6 @@ public class FormSigPageService {
entity.setSigType(req.getSigType());
entity.setPageFrom(req.getPageFrom());
entity.setPageTo(req.getPageTo());
entity.setAction(req.getAction());
}
return formSigPageRepository.save(entity);
}
@@ -97,6 +97,10 @@ public class FormSigPageService {
return getConfig(formCode, asOfDate, UPLOAD2);
}

public Optional<FormSigPage> getUpload3Config(String formCode, LocalDate asOfDate) {
return getConfig(formCode, asOfDate, UPLOAD3);
}

/**
* Converts LocalDateTime (e.g. filled_form.created) to LocalDate for lookup.
*/
@@ -108,14 +112,19 @@ public class FormSigPageService {
return asOf == null ? Optional.empty() : getUpload2Config(formCode, asOf.toLocalDate());
}

public Optional<FormSigPage> getUpload3Config(String formCode, LocalDateTime asOf) {
return asOf == null ? Optional.empty() : getUpload3Config(formCode, asOf.toLocalDate());
}

/**
* Returns config for both upload1 and upload2 for the given formCode and asOf date.
* Returns config for upload1, upload2, and upload3 for the given formCode and asOf date.
* Used by merge service and by the API for frontend labels.
*/
public Map<String, FormSigPage> getConfigForForm(String formCode, LocalDate asOfDate) {
Map<String, FormSigPage> map = new HashMap<>();
getUpload1Config(formCode, asOfDate).ifPresent(c -> map.put(UPLOAD1, c));
getUpload2Config(formCode, asOfDate).ifPresent(c -> map.put(UPLOAD2, c));
getUpload3Config(formCode, asOfDate).ifPresent(c -> map.put(UPLOAD3, c));
return map;
}

@@ -124,12 +133,14 @@ public class FormSigPageService {
}

/**
* Returns DTOs for API: list of { sigType, pageFrom, pageTo, label }.
* Returns DTOs for API: list of { sigType, pageFrom, pageTo, label } (upload1, upload2, upload3 when present).
*/
public List<Map<String, Object>> getConfigDtosForForm(String formCode, LocalDate asOfDate) {
return getConfigForForm(formCode, asOfDate).values().stream()
.map(this::toDto)
.collect(Collectors.toList());
List<Map<String, Object>> out = new ArrayList<>();
getUpload1Config(formCode, asOfDate).map(this::toDto).ifPresent(out::add);
getUpload2Config(formCode, asOfDate).map(this::toDto).ifPresent(out::add);
getUpload3Config(formCode, asOfDate).map(this::toDto).ifPresent(out::add);
return out;
}

public List<Map<String, Object>> getConfigDtosForForm(String formCode, LocalDateTime asOf) {


+ 79
- 18
src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfMergeService.java Parādīt failu

@@ -22,8 +22,6 @@ import com.itextpdf.kernel.utils.PdfMerger;
@Service
public class PdfMergeService {

private static final String SKIP_AND_APPEND = "SKIP_AND_APPEND";

private final FormSigPageService formSigPageService;

public PdfMergeService(FormSigPageService formSigPageService) {
@@ -143,22 +141,7 @@ public class PdfMergeService {
FormSigPage cfg = configOpt.get();
int pageFrom = cfg.getPageFrom();
int pageTo = cfg.getPageTo();
boolean skipAndAppend = SKIP_AND_APPEND.equals(cfg.getAction());

if (skipAndAppend && totalPagesA >= pageFrom) {
if (pageFrom > 1) {
merger.merge(docA, 1, pageFrom - 1);
}
if (totalPagesA > pageFrom) {
merger.merge(docA, pageFrom + 1, totalPagesA);
}
if (pdfBFlattenedBytes != null) {
try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
PdfDocument docB = new PdfDocument(readerB_merge)) {
merger.merge(docB, 1, 1);
}
}
} else if (!skipAndAppend && totalPagesA >= pageTo) {
if (totalPagesA >= pageTo) {
int repStartA = pageFrom;
int repEndA = pageTo;
int pagesToInsertB = pageTo - pageFrom + 1;
@@ -268,4 +251,82 @@ public class PdfMergeService {
public byte[] mergePdf2sItext7(String formCode, byte[] pdfABytes, byte[] pdfBBytes) throws IOException {
return mergePdf2sItext7(formCode, LocalDate.now(), pdfABytes, pdfBBytes);
}

/**
* Merge upload3 PDF using config from form_sig_page (third signature block; run after upload1 and upload2).
*/
public byte[] mergePdf3sItext7(String formCode, LocalDate asOfDate, byte[] pdfABytes, byte[] pdfBBytes) throws IOException {
Optional<FormSigPage> configOpt = formSigPageService.getUpload3Config(formCode, asOfDate);

byte[] pdfAFlattenedBytes;
try (PdfReader readerA = new PdfReader(new ByteArrayInputStream(pdfABytes));
ByteArrayOutputStream tempBaosA = new ByteArrayOutputStream();
PdfWriter tempWriterA = new PdfWriter(tempBaosA);
PdfDocument docA_mod = new PdfDocument(readerA, tempWriterA)) {

flattenPdf(docA_mod);
docA_mod.close();
pdfAFlattenedBytes = tempBaosA.toByteArray();
}

byte[] pdfBFlattenedBytes = null;
if (pdfBBytes != null && pdfBBytes.length > 0) {
try (PdfReader readerB = new PdfReader(new ByteArrayInputStream(pdfBBytes));
ByteArrayOutputStream tempBaosB = new ByteArrayOutputStream();
PdfWriter tempWriterB = new PdfWriter(tempBaosB);
PdfDocument docB_mod = new PdfDocument(readerB, tempWriterB)) {

flattenPdf(docB_mod);
docB_mod.close();
pdfBFlattenedBytes = tempBaosB.toByteArray();
}
}

try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(baos);
PdfDocument mergedPdf = new PdfDocument(writer);
PdfReader readerA_merge = new PdfReader(new ByteArrayInputStream(pdfAFlattenedBytes));
PdfDocument docA = new PdfDocument(readerA_merge)) {

PdfMerger merger = new PdfMerger(mergedPdf);
int totalPagesA = docA.getNumberOfPages();

if (configOpt.isEmpty()) {
merger.merge(docA, 1, totalPagesA);
mergedPdf.close();
return baos.toByteArray();
}

FormSigPage cfg = configOpt.get();
int repStartA = cfg.getPageFrom();
int repEndA = cfg.getPageTo();
int repCountB = repEndA - repStartA + 1;

if (totalPagesA >= repEndA) {
if (repStartA > 1) {
merger.merge(docA, 1, repStartA - 1);
}
if (pdfBFlattenedBytes != null) {
try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
PdfDocument docB = new PdfDocument(readerB_merge)) {
if (docB.getNumberOfPages() >= repCountB) {
merger.merge(docB, 1, repCountB);
}
}
}
if (totalPagesA > repEndA) {
merger.merge(docA, repEndA + 1, totalPagesA);
}
} else {
merger.merge(docA, 1, totalPagesA);
}

mergedPdf.close();
return baos.toByteArray();
}
}

public byte[] mergePdf3sItext7(String formCode, byte[] pdfABytes, byte[] pdfBBytes) throws IOException {
return mergePdf3sItext7(formCode, LocalDate.now(), pdfABytes, pdfBBytes);
}
}

+ 84
- 2
src/main/java/com/ffii/lioner/modules/lioner/pdf/service/PdfService.java Parādīt failu

@@ -6,14 +6,21 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.sql.Timestamp;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.pdfbox.Loader;
@@ -37,6 +44,7 @@ import com.ffii.lioner.modules.lioner.client.service.ClientService;
import com.ffii.lioner.modules.lioner.commonField.entity.CommonField;
import com.ffii.lioner.modules.lioner.commonField.service.CommonFieldService;
import com.ffii.lioner.modules.lioner.pdf.entity.Consultant;
import com.ffii.lioner.modules.lioner.pdf.entity.FormSigPage;
import com.ffii.lioner.modules.lioner.pdf.entity.Pdf;
import com.ffii.lioner.modules.lioner.pdf.entity.PdfRepository;
import com.ffii.lioner.modules.lioner.pdf.req.UpdatePdfReq;
@@ -65,9 +73,11 @@ public class PdfService extends AbstractBaseEntityService<Pdf, Long, PdfReposito
private CommonFieldService commonFieldService;
private ClientService clientService;
private ConsultantService consultantService;
private FormSigPageService formSigPageService;
public PdfService(JdbcDao jdbcDao, PdfRepository repository, AuditLogService auditLogService, FileService fileService,
TemplateService templateService, ClientService clientService, ConsultantService consultantService, CommonFieldService commonFieldService) {
TemplateService templateService, ClientService clientService, ConsultantService consultantService, CommonFieldService commonFieldService,
FormSigPageService formSigPageService) {
super(jdbcDao, repository);
this.auditLogService = auditLogService;
this.fileService = fileService;
@@ -75,6 +85,7 @@ public class PdfService extends AbstractBaseEntityService<Pdf, Long, PdfReposito
this.clientService = clientService;
this.consultantService = consultantService;
this.commonFieldService = commonFieldService;
this.formSigPageService = formSigPageService;
}

// public Map<String,Object> getAuditLogObject(Map<String,Object> req){
@@ -2707,6 +2718,8 @@ public class PdfService extends AbstractBaseEntityService<Pdf, Long, PdfReposito
+ " (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, "
+ " (select f.id from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload3' and fr.refId = ff.id order by fr.id desc limit 1) as upload3FileId, "
+ " (select f.skey from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload3' and fr.refId = ff.id order by fr.id desc limit 1) as upload3FileSkey, "
+ " ff.id, "
+ " ff.templateId, "
@@ -2735,7 +2748,75 @@ public class PdfService extends AbstractBaseEntityService<Pdf, Long, PdfReposito
}
sql.append(" ORDER BY id desc ");

return jdbcDao.queryForList(sql.toString(), args);
List<Map<String, Object>> rows = jdbcDao.queryForList(sql.toString(), args);
enrichRowsWithSigTypes(rows);
return rows;
}

/**
* Which signature upload slots apply for this row (same resolution as merge: formCode + filled_form.created).
*/
private void enrichRowsWithSigTypes(List<Map<String, Object>> rows) {
if (rows == null || rows.isEmpty()) {
return;
}
for (Map<String, Object> row : rows) {
String formCode = (String) row.get("formCode");
if (formCode == null || formCode.isBlank()) {
row.put("sigTypes", List.of("upload1"));
continue;
}
LocalDate asOf = jdbcTimestampToLocalDate(row.get("created"));
if (asOf == null) {
asOf = LocalDate.now();
}
Map<String, FormSigPage> cfg = formSigPageService.getConfigForForm(formCode, asOf);
List<String> sigTypes = new ArrayList<>();
if (cfg.containsKey("upload1")) {
sigTypes.add("upload1");
}
if (cfg.containsKey("upload2")) {
sigTypes.add("upload2");
}
if (cfg.containsKey("upload3")) {
sigTypes.add("upload3");
}
if (sigTypes.isEmpty()) {
sigTypes.add("upload1");
}
row.put("sigTypes", sigTypes);
}
}

/**
* As-of date for form_sig_page (same basis as merged download: filled_form.created in JVM default zone).
*/
public Optional<LocalDate> findFilledFormAsOfDate(Long filledFormId) {
if (filledFormId == null) {
return Optional.empty();
}
String sql = "SELECT ff.created FROM filled_form ff WHERE ff.deleted = FALSE AND ff.id = :id";
return jdbcDao.queryForMap(sql, Map.of("id", filledFormId))
.map(m -> jdbcTimestampToLocalDate(m.get("created")));
}

private static LocalDate jdbcTimestampToLocalDate(Object o) {
if (o == null) {
return null;
}
if (o instanceof LocalDate) {
return (LocalDate) o;
}
if (o instanceof LocalDateTime) {
return ((LocalDateTime) o).toLocalDate();
}
if (o instanceof Timestamp) {
return ((Timestamp) o).toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
if (o instanceof java.util.Date) {
return ((java.util.Date) o).toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
return null;
}

public Map<String, Object> loadPDF(Long id) {
@@ -4693,6 +4774,7 @@ public class PdfService extends AbstractBaseEntityService<Pdf, Long, PdfReposito

+ " (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, "
+ " (select f.id from file_ref fr left join file f on fr.fileId = f.id where fr.refType = 'upload3' and fr.refId = ff.id order by fr.id desc limit 1) as upload3FileId, "
+ " ff.id, "
+ " ff.remarks, "


+ 2
- 3
src/main/java/com/ffii/lioner/modules/lioner/pdf/web/FormSigPageController.java Parādīt failu

@@ -4,7 +4,6 @@ import java.util.List;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -26,11 +25,11 @@ import com.ffii.lioner.modules.lioner.pdf.service.FormSigPageService;
import jakarta.validation.Valid;

/**
* Admin-only CRUD for form_sig_page (signature page config per formCode/startDate/sigType).
* CRUD for form_sig_page (signature page config per formCode/startDate/sigType).
* Access is aligned with {@code /template} (authenticated users; UI restricts via VIEW TEMPLATE).
*/
@RestController
@RequestMapping("/pdf/form-sig-page")
@PreAuthorize("hasAuthority('MANAGE_SYSTEM_CONFIGURATION')")
public class FormSigPageController {

private final FormSigPageService formSigPageService;


+ 25
- 4
src/main/java/com/ffii/lioner/modules/lioner/pdf/web/PdfController.java Parādīt failu

@@ -272,6 +272,10 @@ public class PdfController {
.map(val -> ((Integer) val).longValue())
.orElse(null);

Long upload3FileId = Optional.ofNullable(d.get("upload3FileId"))
.map(val -> ((Integer) val).longValue())
.orElse(null);

// Safely retrieve byte arrays using Optional chaining (prevents NullPointerExceptions)
byte[] pdfBytes = Optional.ofNullable(fileId)
.flatMap(fileService::findFileBlobByFileId)
@@ -289,6 +293,11 @@ public class PdfController {
.map(FileBlob::getBytes)
.orElse(null);

byte[] pdfUpload3Bytes = Optional.ofNullable(upload3FileId)
.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:");
@@ -310,6 +319,10 @@ public class PdfController {
if (d.get("upload2FileId") != null) {
finalPdfBytes = pdfMergeService.mergePdf2sItext7(formCode, asOfDate, finalPdfBytes, pdfUpload2Bytes);
}

if (d.get("upload3FileId") != null) {
finalPdfBytes = pdfMergeService.mergePdf3sItext7(formCode, asOfDate, finalPdfBytes, pdfUpload3Bytes);
}
// --- 4. Build ResponseEntity ---
HttpHeaders headers = new HttpHeaders();
@@ -326,14 +339,22 @@ public class PdfController {
}

/**
* Returns form_sig_page config for labels (upload1/upload2 page range and label text).
* Optional asOfDate (yyyy-MM-dd); defaults to today if omitted.
* Returns form_sig_page config for labels (upload1/upload2/upload3 page range and label text).
* Prefer filledFormId so the as-of date matches merged download (filled_form.created).
* Otherwise optional asOfDate (yyyy-MM-dd); defaults to today if still unresolved.
*/
@GetMapping("/form-sig-page-config")
public Map<String, Object> getFormSigPageConfig(
@RequestParam String formCode,
@RequestParam(required = false) String asOfDate) {
LocalDate date = parseLocalDate(asOfDate);
@RequestParam(required = false) String asOfDate,
@RequestParam(required = false) Long filledFormId) {
LocalDate date = null;
if (filledFormId != null) {
date = pdfService.findFilledFormAsOfDate(filledFormId).orElse(null);
}
if (date == null) {
date = parseLocalDate(asOfDate);
}
if (date == null) {
date = LocalDate.now();
}


+ 4
- 0
src/main/resources/db/changelog/changes/39_form_sig_page_drop_action/01_drop_form_sig_page_action.sql Parādīt failu

@@ -0,0 +1,4 @@
--liquibase formatted sql

--changeset lioner:form_sig_page_drop_action
ALTER TABLE `form_sig_page` DROP COLUMN `action`;

Notiek ielāde…
Atcelt
Saglabāt