Skip to content

Commit

Permalink
backend : package element label generation
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminpochat committed Apr 5, 2024
1 parent de05259 commit 00bb4c6
Show file tree
Hide file tree
Showing 20 changed files with 678 additions and 5 deletions.
5 changes: 5 additions & 0 deletions backend/app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.redsix</groupId>
<artifactId>pdfcompare</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package eu.viandeendirect.common;

import eu.viandeendirect.model.BeefProduction;

import java.util.Locale;

public interface EnumLabelManager<T> {

default String getLabel(T enumValue, Locale locale) {
return switch (locale.getLanguage()) {
case "fr" -> getFrenchLabel(enumValue);
default -> "undefined";
};
}

String getFrenchLabel(T enumValue);
}
57 changes: 57 additions & 0 deletions backend/app/src/main/java/eu/viandeendirect/common/PDFService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package eu.viandeendirect.common;

import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import eu.viandeendirect.model.BeefProduction;
import org.apache.tomcat.util.codec.binary.Base64;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;

public abstract class PDFService<T> {
public ByteArrayOutputStream generatePDF(T arguments) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useFastMode();
builder.withHtmlContent(getContentAsHtml(arguments), "/");
builder.toStream(outputStream);
builder.run();
return outputStream;
}

protected String getTemplate() throws URISyntaxException, IOException {
return Files.lines(Paths.get(getClass().getClassLoader().getResource(getTemplatePath()).toURI())).collect(Collectors.joining());
}

protected String getCSS() throws URISyntaxException, IOException {
return Files.lines(Paths.get(getClass().getClassLoader().getResource(getCSSPath()).toURI())).collect(Collectors.joining());
}

protected abstract String getTemplatePath();

protected abstract String getCSSPath();

protected abstract String getContentAsHtml(T argument);

protected String getViandeEnDirectLogoAsBase64() {
return getImageAsBase64("images/viande_en_direct.png");
}

protected String getLabelRougeLogoAsBase64(BeefProduction beefProduction) {
if (!beefProduction.getLabelRougeCertified()) {
return "";
}
return getImageAsBase64("images/label_rouge.jpg");
}

protected String getImageAsBase64(String filePath) {
try {
return Base64.encodeBase64String(getClass().getClassLoader().getResource(filePath).openStream().readAllBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package eu.viandeendirect.domains.production;

import eu.viandeendirect.common.EnumLabelManager;
import eu.viandeendirect.model.BeefProduction;
import org.springframework.stereotype.Component;

@Component
public class AnimalTypeLabelManager implements EnumLabelManager<BeefProduction.AnimalTypeEnum> {

@Override
public String getFrenchLabel(BeefProduction.AnimalTypeEnum animalType) {
return switch (animalType) {
case COW -> "vache";
case BULL -> "taureau";
case VEAL -> "veau";
case HEIFER -> "génisse";
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package eu.viandeendirect.domains.production;

import eu.viandeendirect.common.EnumLabelManager;
import eu.viandeendirect.model.BeefProduction;
import org.springframework.stereotype.Component;

@Component
public class CattleBreedLabelManager implements EnumLabelManager<BeefProduction.CattleBreedEnum> {
@Override
public String getFrenchLabel(BeefProduction.CattleBreedEnum cattleBreed) {
return switch (cattleBreed) {
case CHAROLAISE -> "charolaise";
case LIMOUSINE -> "limousine";
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package eu.viandeendirect.domains.production;

import eu.viandeendirect.common.PDFService;
import eu.viandeendirect.model.BeefProduction;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.stream.Collectors;

import static java.util.Locale.FRENCH;

@Service
public class PackageElementLabelService extends PDFService<PackageElementLabelService.Arguments> {

@Autowired
AnimalTypeLabelManager animalTypeLabelManager;

@Autowired
CattleBreedLabelManager cattleBreedLabelManager;

private String productLabelCSS;
private String productLabelTemplate;

public PackageElementLabelService() throws URISyntaxException, IOException {
productLabelTemplate = getTemplate();
productLabelCSS = getCSS();
}

@Override
protected String getTemplatePath() {
return "html/pdf/package_element_label_template.html";
}

@Override
protected String getCSSPath() {
return "html/pdf/package_element_label_template.css";
}

@Override
protected String getContentAsHtml(PackageElementLabelService.Arguments arguments) {
var htmlStart = String.format("<html><meta charset=\"UTF-8\"/><head><style type=\"text/css\">%s</style></head><body>", productLabelCSS);
var htmlEnd = "</body></html>";
return arguments.elementsNames.stream()
.map(elementName -> String.format(productLabelTemplate, getLabelsAsHtml(arguments.beefProduction, elementName)))
.collect(Collectors.joining("", htmlStart, htmlEnd));
}

private String getLabelsAsHtml(BeefProduction beefProduction, String elementName) {
return String.format("""
<table>
<tr>
<td>%1$s race %2$s</td>
<td rowspan="2">
<img src="data:image/jpg;base64, %7$s" class="certification-images"></img>
</td>
</tr>
<tr>
<td>%3$s</td>
</tr>
<tr>
<td colspan="2" class="element-name">
%4$s
</td>
</tr>
<tr>
<td colspan="2">
DLC : %5$td/%5$tm/%5$tY
</td>
</tr>
<tr>
<td colspan="2">
DLC congelé : %6$td/%6$tm/%6$tY
</td>
</tr>
</table>""",
StringUtils.capitalize(animalTypeLabelManager.getLabel(beefProduction.getAnimalType(), FRENCH)),
cattleBreedLabelManager.getLabel(beefProduction.getCattleBreed(), FRENCH),
beefProduction.getAnimalIdentifier(),
elementName,
beefProduction.getCuttingDate().plusDays(10),
beefProduction.getCuttingDate().plusYears(1),
getLabelRougeLogoAsBase64(beefProduction));
}

public record Arguments(BeefProduction beefProduction, List<String> elementsNames) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<meta charset="UTF-8">
<div>La commande n° %1$s a été enregistrée sur <a href='%2$s'>ViandeEnDirect.eu</a>.</div>
<div>
<ul>
<li>Montant de la commande : %3$s €TTC</li>
<li>Quantité commandée : %4$s kg</li>
<li>Date et heure de la livraison : le %5$td/%5$tm/%5$tY entre %5$tR et %6$tR</li>
<li>Adresse de la livraison :<br>
%7$s<br>
%8$s<br>
%9$s<br>
%10$s<br>
%11$s<br>
%12$s<br>
%13$s<br>
</li>
</ul>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<meta charset="UTF-8">
<div>La commande n° %s a été enregistrée sur <a href='%s'>ViandeEnDirect.eu</a>.</div>
<div>
<ul>
<li>Client :
<ul>
<li>Nom : %s %s</li>
<li>Email : %s</li>
<li>Téléphone : %s</li>
</ul>
</li>
<li>Montant de la commande : %s €TTC</li>
<li>Quantité commandée : %s kg</li>
</ul>
</div>
51 changes: 51 additions & 0 deletions backend/app/src/main/resources/html/pdf/invoice_template.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@page {
size: A4 portrait;
}

body {
font-family: sans-serif;
}

.bill {
page-break-after: always;
}

.full-width-width {
width: 100%;
}

.articles-table, .articles-table thead, .articles-table tr, .articles-table td {
border-collapse: collapse;
border-color: grey;
border-style: solid;
border-width: thin;
padding: 1mm;
}

.with-top-margin {
margin-top: 2cm;
}

.table-head {
background-color: navy;
color: white;
font-weight: bold;
}

.align-right {
text-align: right;
}

.payed {
font-weigth: bolder;
font-size: 1cm;
color: red;
border-color: red;
border-style: solid;
border-width: 2mm;
border-radius: 2mm;
padding: 5mm;
text-align: center;
transform: rotate(10deg);
width: 3cm;
}
75 changes: 75 additions & 0 deletions backend/app/src/main/resources/html/pdf/invoice_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<div class="bill">
<div>
<table class="full-width-width entete-facture">
<tbody>
<tr>
<td>
<div>Vendeur</div>
<div>%1$s</div>
%2$s
<div>%3$s %4$s</div>
<div>SIREN : %5$s</div>
<div>Tel. : %6$s</div>
</td>
<td>
<div>Client</div>
<div>%7$s %8$s</div>
<div>Tel. : %9$s</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="with-top-margin">
<table class="full-width-width">
<tr>
<td>
<div>
Facture N° %17$tY%17$tm%17$td-%10$s
</div>
<div>
Date : %11$td/%11$tm/%11$tY
</div>
</td>
<td>
<div class="payed">PAYÉ</div>
</td>
</tr>
</table>
</div>
<div class="with-top-margin">
<table class="full-width-width articles-table">
<thead class="table-head">
<td>Désignation</td>
<td>Quantité</td>
<td>Prix Unitaire HT</td>
<td>Total HT</td>
</thead>
%12$s
<tr>
<td></td>
<td></td>
<td class="table-head">TOTAL HT</td>
<td class="align-right">%13$.2f €</td>
</tr>
<tr>
<td></td>
<td></td>
<td class="table-head">Montant de TVA</td>
<td class="align-right">%14$.2f €</td>
</tr>
<tr>
<td></td>
<td></td>
<td class="table-head">TOTAL TTC</td>
<td class="align-right">%15$.2f €</td>
</tr>
</table>
</div>
<div class="with-top-margin">
Date de réglement : %16$td/%16$tm/%16$tY
</div>
<div>
Date de livraison : %17$td/%17$tm/%17$tY
</div>
</div>
Loading

0 comments on commit 00bb4c6

Please sign in to comment.