Skip to content

Commit 3a4401b

Browse files
committed
basic logic for basic peppol functionalities
1 parent 67ae862 commit 3a4401b

8 files changed

Lines changed: 160 additions & 4 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
package tech.artcoded.websitev2.changelogs;
3+
4+
import io.mongock.api.annotations.ChangeUnit;
5+
import io.mongock.api.annotations.Execution;
6+
import io.mongock.api.annotations.RollbackExecution;
7+
import java.io.IOException;
8+
9+
import lombok.extern.slf4j.Slf4j;
10+
import tech.artcoded.websitev2.pages.invoice.InvoiceGenerationRepository;
11+
import tech.artcoded.websitev2.peppol.PeppolStatus;
12+
13+
@Slf4j
14+
@ChangeUnit(id = "add-peppol-status", order = "46", author = "Nordine Bittich")
15+
public class CHANGE_LOG_46_AddPeppolStatus {
16+
17+
@RollbackExecution
18+
public void rollbackExecution() {
19+
}
20+
21+
@Execution
22+
public void execute(InvoiceGenerationRepository repo)
23+
throws IOException {
24+
var invoices = repo.findAll().stream().map(i -> i.toBuilder().peppolStatus(PeppolStatus.OLD).build()).toList();
25+
repo.saveAll(invoices);
26+
}
27+
}

artcoded/src/main/java/tech/artcoded/websitev2/pages/invoice/InvoiceGeneration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.springframework.data.annotation.Transient;
1111
import org.springframework.data.mongodb.core.mapping.Document;
1212

13+
import tech.artcoded.websitev2.peppol.PeppolStatus;
1314
import tech.artcoded.websitev2.utils.helper.DateHelper;
1415
import tech.artcoded.websitev2.utils.helper.IdGenerators;
1516

@@ -74,6 +75,7 @@ public class InvoiceGeneration implements Serializable {
7475
private String invoiceUBLId;
7576
private String freemarkerTemplateId;
7677

78+
private PeppolStatus peppolStatus;
7779
private String specialNote;
7880

7981
// wheiter it was imported from an old system

artcoded/src/main/java/tech/artcoded/websitev2/pages/invoice/InvoiceGenerationController.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import org.springframework.web.bind.annotation.*;
88
import org.springframework.web.multipart.MultipartFile;
99

10+
import tech.artcoded.websitev2.peppol.PeppolService;
11+
import tech.artcoded.websitev2.peppol.PeppolStatus;
12+
1013
import javax.inject.Inject;
1114
import java.util.List;
1215
import java.util.Map;
@@ -15,11 +18,13 @@
1518
@RequestMapping("/api/invoice")
1619
public class InvoiceGenerationController {
1720
private final InvoiceService invoiceService;
21+
private final PeppolService peppolService;
1822

1923
@Inject
20-
public InvoiceGenerationController(
24+
public InvoiceGenerationController(PeppolService peppolService,
2125
InvoiceService invoiceService) {
2226
this.invoiceService = invoiceService;
27+
this.peppolService = peppolService;
2328
}
2429

2530
@PostMapping("/new")
@@ -92,6 +97,12 @@ public ResponseEntity<List<InvoiceGeneration>> findByIds(@RequestParam(value = "
9297
return ResponseEntity.ok(invoiceService.findAll(ids));
9398
}
9499

100+
@PostMapping("/send-to-peppol")
101+
public void findByIds(@RequestParam(value = "id") String id) {
102+
this.invoiceService.findById(id).filter(i -> PeppolStatus.NOT_SENT.equals(i.getPeppolStatus()))
103+
.ifPresent(i -> peppolService.addInvoice(i));
104+
}
105+
95106
@PostMapping(value = "/manual-upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
96107
public ResponseEntity<Void> manualUpload(
97108
@RequestPart("manualUploadFile") MultipartFile file, @RequestParam("id") String id) {

artcoded/src/main/java/tech/artcoded/websitev2/pages/invoice/InvoiceService.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import tech.artcoded.websitev2.pages.personal.PersonalInfo;
4848
import tech.artcoded.websitev2.pages.personal.PersonalInfoService;
4949
import tech.artcoded.websitev2.pages.timesheet.TimesheetRepository;
50+
import tech.artcoded.websitev2.peppol.PeppolStatus;
5051
import tech.artcoded.websitev2.rest.util.MockMultipartFile;
5152
import tech.artcoded.websitev2.rest.util.PdfToolBox;
5253
import tech.artcoded.websitev2.upload.FileUploadService;
@@ -463,8 +464,11 @@ public InvoiceGeneration generateInvoice(InvoiceGeneration invoiceGeneration) {
463464
this.invoiceToUBL(partialInvoice), "xml"),
464465
id, false);
465466
}
466-
InvoiceGeneration invoiceToSave = partialInvoice.toBuilder().invoiceUploadId(pdfId)
467-
.invoiceUBLId(ublId).build();
467+
InvoiceGeneration invoiceToSave = partialInvoice.toBuilder()
468+
.invoiceUploadId(pdfId)
469+
.peppolStatus(PeppolStatus.NOT_SENT)
470+
.invoiceUBLId(ublId)
471+
.build();
468472
InvoiceGeneration saved = repository.save(invoiceToSave);
469473
this.notificationService.sendEvent(
470474
"New Invoice Ready (%s)".formatted(
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package tech.artcoded.websitev2.peppol;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.nio.file.Files;
6+
import java.util.Date;
7+
import java.util.List;
8+
9+
import org.apache.camel.Body;
10+
import org.apache.camel.Exchange;
11+
import org.apache.camel.Header;
12+
import org.apache.camel.builder.RouteBuilder;
13+
import org.springframework.beans.factory.annotation.Value;
14+
import org.springframework.stereotype.Service;
15+
16+
import lombok.SneakyThrows;
17+
import lombok.extern.slf4j.Slf4j;
18+
import tech.artcoded.websitev2.pages.fee.FeeService;
19+
import tech.artcoded.websitev2.pages.invoice.InvoiceGeneration;
20+
import tech.artcoded.websitev2.pages.invoice.InvoiceGenerationRepository;
21+
import tech.artcoded.websitev2.rest.util.MockMultipartFile;
22+
import tech.artcoded.websitev2.upload.FileUploadService;
23+
24+
@Service
25+
@Slf4j
26+
public class PeppolService extends RouteBuilder {
27+
28+
@Value("${application.upload.pathToPeppolExpenditure}")
29+
private String pathToPeppolExpenditure;
30+
31+
@Value("${application.upload.pathToPeppolInvoice}")
32+
private String pathToPeppolInvoice;
33+
34+
private final FileUploadService uploadService;
35+
private final FeeService feeService;
36+
private final InvoiceGenerationRepository invoiceRepository;
37+
38+
public PeppolService(FileUploadService uploadService,
39+
FeeService feeService,
40+
InvoiceGenerationRepository invoiceRepository) {
41+
this.uploadService = uploadService;
42+
this.invoiceRepository = invoiceRepository;
43+
this.feeService = feeService;
44+
}
45+
46+
@SneakyThrows
47+
public void addInvoice(InvoiceGeneration invoice) {
48+
log.info("receiving invoice {}. copying it to {} and set status to processing...", invoice.getId(),
49+
pathToPeppolInvoice);
50+
var ubl = this.uploadService.findOneById(invoice.getInvoiceUBLId())
51+
.orElseThrow(() -> new RuntimeException("file with id %s not found".formatted(invoice.getInvoiceUBLId())));
52+
53+
var file = this.uploadService.getFile(ubl);
54+
var out = new File(pathToPeppolInvoice, "%s.xml".formatted(invoice.getId()));
55+
Files.copy(file.toPath(), out.toPath());
56+
this.invoiceRepository.findById(invoice.getId())
57+
.map(i -> i.toBuilder().peppolStatus(PeppolStatus.PROCESSING).build())
58+
.ifPresent(invoiceRepository::save);
59+
}
60+
61+
void updatePeppolStatus(@Header(Exchange.FILE_NAME) String fileName) throws IOException {
62+
var invoiceId = fileName.replace(".xml", "");
63+
invoiceRepository.findById(invoiceId).map(i -> i.toBuilder().peppolStatus(PeppolStatus.SUCCESS).build())
64+
.ifPresentOrElse(invoiceRepository::save,
65+
() -> log.error(fileName + ": cannot extract invoice id or invoice doesn't exist."));
66+
67+
}
68+
69+
@SneakyThrows
70+
void pushFee(@Body File file, @Header(Exchange.FILE_NAME) String fileName,
71+
@Header(Exchange.FILE_CONTENT_TYPE) String contentType) {
72+
73+
this.feeService.save("[PEPPOL]: " + fileName, "New peppol expense", new Date(), List.of(MockMultipartFile.builder()
74+
.originalFilename(fileName)
75+
.contentType(contentType)
76+
.name(fileName)
77+
.bytes(Files.readAllBytes(file.toPath()))
78+
.build()));
79+
80+
}
81+
82+
@Override
83+
public void configure() throws Exception {
84+
onException(Exception.class)
85+
.handled(true)
86+
.transform().simple("Exception occurred due: ${exception.message}")
87+
.log("${body}");
88+
89+
from("file:%s/success?noop=true&idempotent=true&idempotentRepository=#fileIdempotentRepository"
90+
.formatted(pathToPeppolInvoice))
91+
.routeId("Peppol::UpdateProcessedInvoices")
92+
.log("receiving file '${headers.%s}', will update peppol status".formatted(Exchange.FILE_NAME))
93+
.bean(() -> this, "updatePeppolStatus");
94+
95+
from("file:" + pathToPeppolExpenditure)
96+
.routeId("Peppol::PeppolExpenseToFee")
97+
.log("receiving file '${headers.%s}', will convert it to fee".formatted(Exchange.FILE_NAME))
98+
.bean(() -> this, "pushFee");
99+
}
100+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package tech.artcoded.websitev2.peppol;
2+
3+
public enum PeppolStatus {
4+
OLD, NOT_SENT, PROCESSING, SUCCESS
5+
}

artcoded/src/main/java/tech/artcoded/websitev2/upload/FileUploadService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,13 @@ public Optional<byte[]> getUploadAsBytes(String id) {
7979
return findOneById(id).map(this::uploadToByteArray);
8080
}
8181

82+
public File getFile(FileUpload fileUpload) {
83+
return new File(getUploadFolder(), getFileNameOnDisk(fileUpload));
84+
}
85+
8286
@SneakyThrows
8387
public byte[] uploadToByteArray(FileUpload upload) {
84-
File file = new File(getUploadFolder(), getFileNameOnDisk(upload));
88+
File file = this.getFile(upload);
8589
if (file.exists()) {
8690
return FileUtils.readFileToByteArray(file);
8791
} else {

artcoded/src/main/resources/application.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ application:
33
defaultGraph: ${DEFAULT_GRAPH_UPLOAD:https://bittich.be/graphs/public}
44
pathToBackup: ${application.basePath}/files-backup
55
pathToUpload: ${application.basePath}/files
6+
pathToPeppolFTP: ${application.basePath}/peppol
7+
pathToPeppolExpenditure: ${application.upload.pathToPeppolFTP}/expenses
8+
pathToPeppolInvoice: ${application.upload.pathToPeppolFTP}/invoices
69
cv:
710
defaultGraph: ${DEFAULT_GRAPH_CV:https://bittich.be/graphs/public}
811
dossier:

0 commit comments

Comments
 (0)