feat: enhance date formatting in rental documents and receipts
This commit is contained in:
1 parent
d7a7aff3ee
commit
3bbbf773f4
5 files changed
+46
-15
No files matched your search
+25
-3
@@ -8,13 +8,17 @@ import org.thymeleaf.context.Context;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Component
|
||||
public class ThymeleafRentalDocumentRenderer implements RentalDocumentRenderer {
|
||||
private static final DateTimeFormatter MONTH = DateTimeFormatter.ofPattern("MMMM yyyy", Locale.FRANCE);
|
||||
private static final FrenchDates DATES = new FrenchDates();
|
||||
|
||||
private final TemplateEngine templates;
|
||||
|
||||
@@ -45,13 +49,13 @@ public class ThymeleafRentalDocumentRenderer implements RentalDocumentRenderer {
|
||||
Context context = context(document);
|
||||
context.setVariable("tenantNames", names(document.contract().tenants().stream()
|
||||
.map(tenant -> tenant.firstName() + " " + tenant.lastName()).toList()));
|
||||
context.setVariable("receiptMonth", document.month().format(MONTH));
|
||||
return render("rental/rent-receipt", context);
|
||||
}
|
||||
|
||||
private Context context(Object document) {
|
||||
Context context = new Context(Locale.FRANCE);
|
||||
context.setVariable("document", document);
|
||||
context.setVariable("dates", DATES);
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -68,4 +72,22 @@ public class ThymeleafRentalDocumentRenderer implements RentalDocumentRenderer {
|
||||
private static String names(List<String> names) {
|
||||
return names.isEmpty() ? "Aucun" : String.join(", ", names);
|
||||
}
|
||||
|
||||
public static final class FrenchDates {
|
||||
private FrenchDates() {
|
||||
}
|
||||
|
||||
public String date(LocalDate date) {
|
||||
return date.getDayOfMonth() + " " + monthName(date) + " " + date.getYear();
|
||||
}
|
||||
|
||||
public String month(YearMonth month) {
|
||||
return monthName(month) + " " + month.getYear();
|
||||
}
|
||||
|
||||
private static String monthName(TemporalAccessor date) {
|
||||
String month = Month.from(date).getDisplayName(TextStyle.FULL, Locale.FRANCE);
|
||||
return Character.toUpperCase(month.charAt(0)) + month.substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
<tr><th>Téléphone du bailleur</th><td th:text="${document.landlord.phone}">+33612345678</td></tr>
|
||||
<tr><th>Adresse du bailleur</th><td th:text="${document.landlord.address}">1 rue de Paris</td></tr>
|
||||
<tr><th>Locataire(s)</th><td th:text="${tenantNames}">Camille Martin</td></tr>
|
||||
<tr><th>Période</th><td><span th:text="${document.period.startDate}">2026-09-01</span> au <span th:text="${document.period.endDate}">2027-08-31</span></td></tr>
|
||||
<tr><th>Période</th><td><span th:text="${dates.date(document.period.startDate)}">1 Septembre 2026</span> au <span th:text="${dates.date(document.period.endDate)}">31 Août 2027</span></td></tr>
|
||||
<tr><th>Loyer mensuel</th><td><span th:text="${document.terms.monthlyRent}">850.00</span> EUR</td></tr>
|
||||
<tr><th>Charges mensuelles</th><td><span th:text="${document.terms.monthlyCharges}">50.00</span> EUR</td></tr>
|
||||
<tr><th>Dépôt de garantie</th><td><span th:text="${document.terms.securityDeposit}">850.00</span> EUR</td></tr>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr><th>Bailleur</th><td th:text="${document.contract.landlord.firstName + ' ' + document.contract.landlord.lastName}">Léa Dubois</td></tr>
|
||||
<tr><th>Logement</th><td th:text="${document.contract.apartment.address}">12 rue de la République</td></tr>
|
||||
<tr><th>Locataire(s)</th><td th:text="${tenantNames}">Camille Martin</td></tr>
|
||||
<tr><th>Reçu le</th><td th:text="${document.receivedAt}">2026-07-05</td></tr>
|
||||
<tr><th>Reçu le</th><td th:text="${dates.date(document.receivedAt)}">5 Juillet 2026</td></tr>
|
||||
<tr><th>Montant reçu</th><td><span th:text="${document.amount}">1200.00</span> EUR</td></tr>
|
||||
<tr><th>Montant remboursé</th><td><span th:text="${document.refundedAmount}">0.00</span> EUR</td></tr>
|
||||
<tr><th>Solde non affecté</th><td><span th:text="${document.unallocatedBalance}">300.00</span> EUR</td></tr>
|
||||
@@ -28,9 +28,9 @@
|
||||
<thead><tr><th>Mois</th><th>Montant</th><th>Date</th></tr></thead>
|
||||
<tbody>
|
||||
<tr th:each="allocation : ${document.allocations}">
|
||||
<td th:text="${allocation.month}">2026-07</td>
|
||||
<td th:text="${dates.month(allocation.month)}">Juillet 2026</td>
|
||||
<td><span th:text="${allocation.amount}">900.00</span> EUR</td>
|
||||
<td th:text="${allocation.allocatedAt}">2026-07-05</td>
|
||||
<td th:text="${dates.date(allocation.allocatedAt)}">5 Juillet 2026</td>
|
||||
</tr>
|
||||
<tr th:if="${document.allocations.empty}"><td colspan="3">Aucune affectation</td></tr>
|
||||
</tbody>
|
||||
@@ -42,7 +42,7 @@
|
||||
<tr th:each="refund : ${document.refunds}">
|
||||
<td th:text="${refund.refundId.value}">refund-1</td>
|
||||
<td><span th:text="${refund.amount}">100.00</span> EUR</td>
|
||||
<td th:text="${refund.refundedAt}">2026-07-06</td>
|
||||
<td th:text="${dates.date(refund.refundedAt)}">6 Juillet 2026</td>
|
||||
</tr>
|
||||
<tr th:if="${document.refunds.empty}"><td colspan="3">Aucun remboursement</td></tr>
|
||||
</tbody>
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
<tr><th>Logement</th><td th:text="${document.contract.apartment.name}">Studio République</td></tr>
|
||||
<tr><th>Adresse</th><td th:text="${document.contract.apartment.address}">12 rue de la République</td></tr>
|
||||
<tr><th>Locataire(s)</th><td th:text="${tenantNames}">Camille Martin</td></tr>
|
||||
<tr><th>Période</th><td th:text="${receiptMonth}">juillet 2026</td></tr>
|
||||
<tr><th>Période</th><td th:text="${dates.month(document.month)}">Juillet 2026</td></tr>
|
||||
<tr><th>Loyer</th><td><span th:text="${document.rent}">850.00</span> EUR</td></tr>
|
||||
<tr><th>Charges</th><td><span th:text="${document.charges}">50.00</span> EUR</td></tr>
|
||||
<tr><th>Total réglé</th><td><span th:text="${document.total}">900.00</span> EUR</td></tr>
|
||||
</table>
|
||||
<footer>Quittance générée le <span th:text="${document.issuedAt}">2026-07-18</span>. Le surplus non affecté n'est pas inclus.</footer>
|
||||
<footer>Quittance générée le <span th:text="${dates.date(document.issuedAt)}">18 Juillet 2026</span>. Le surplus non affecté n'est pas inclus.</footer>
|
||||
</body>
|
||||
</html>
|
||||
+14
-5
@@ -48,8 +48,8 @@ class ThymeleafRentalDocumentRendererTest {
|
||||
ThymeleafRentalDocumentRenderer renderer = new ThymeleafRentalDocumentRenderer(templateEngine());
|
||||
LeaseContractVersion contract = contract();
|
||||
ReceiptAllocation allocation = new ReceiptAllocation(new PaymentAllocationId("allocation-1"),
|
||||
new RentDueId("due-1"), YearMonth.of(2026, 7), new BigDecimal("950.00"),
|
||||
LocalDate.of(2026, 7, 5));
|
||||
new RentDueId("due-1"), YearMonth.of(2026, 6), new BigDecimal("950.00"),
|
||||
LocalDate.of(2026, 8, 6));
|
||||
|
||||
byte[] lease = renderer.renderLease(new LeaseDocument(new LeaseId("lease-1"), contract.landlord(),
|
||||
contract.apartment(), contract.tenants(), contract.guarantors(), contract.period(), contract.terms()));
|
||||
@@ -57,18 +57,27 @@ class ThymeleafRentalDocumentRendererTest {
|
||||
LocalDate.of(2026, 7, 5), LocalDate.of(2026, 7, 6), new BigDecimal("1200.00"),
|
||||
new BigDecimal("50.00"), new BigDecimal("200.00"), contract, List.of(allocation),
|
||||
List.of(new ReceiptRefund(new RentPaymentRefundId("refund-1"), new BigDecimal("50.00"),
|
||||
LocalDate.of(2026, 7, 6)))));
|
||||
LocalDate.of(2026, 9, 7)))));
|
||||
byte[] rentReceipt = renderer.renderRentReceipt(new RentReceipt(new RentDueId("due-1"),
|
||||
YearMonth.of(2026, 7), new BigDecimal("900.00"), new BigDecimal("50.00"),
|
||||
new BigDecimal("950.00"), LocalDate.of(2026, 7, 18), contract));
|
||||
YearMonth.of(2026, 10), new BigDecimal("900.00"), new BigDecimal("50.00"),
|
||||
new BigDecimal("950.00"), LocalDate.of(2026, 7, 19), contract));
|
||||
|
||||
assertAll(() -> assertPdf(lease), () -> assertPdf(paymentReceipt), () -> assertPdf(rentReceipt));
|
||||
String leaseText = pdfText(lease);
|
||||
assertTrue(leaseText.contains("1 Janvier 2026"));
|
||||
assertTrue(leaseText.contains("31 Décembre 2026"));
|
||||
String paymentText = pdfText(paymentReceipt);
|
||||
assertTrue(paymentText.contains("5 Juillet 2026"));
|
||||
assertTrue(paymentText.contains("Juin 2026"));
|
||||
assertTrue(paymentText.contains("6 Août 2026"));
|
||||
assertTrue(paymentText.contains("7 Septembre 2026"));
|
||||
assertTrue(paymentText.contains("1200.00"));
|
||||
assertTrue(paymentText.contains("950.00"));
|
||||
assertTrue(paymentText.contains("200.00"));
|
||||
assertTrue(paymentText.contains("refund-1"));
|
||||
String rentText = pdfText(rentReceipt);
|
||||
assertTrue(rentText.contains("Octobre 2026"));
|
||||
assertTrue(rentText.contains("19 Juillet 2026"));
|
||||
assertTrue(rentText.contains("900.00"));
|
||||
assertTrue(rentText.contains("50.00"));
|
||||
assertFalse(rentText.contains("1200.00"));
|
||||
|
||||
Reference in new issue
Block a user