update report template (#43)

This commit is contained in:
Ruidy 2025-02-22 12:28:56 +01:00 committed by GitHub
parent b0198f7f9a
commit 44cf04bac7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 210 additions and 92 deletions

View file

@ -1,68 +1,118 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="fr">
<head> <head>
<link rel="stylesheet" href="main.css"> <style>
body {
font-family: Arial, sans-serif;
background-color: #f9f9f9;
color: #333;
margin: 0;
padding: 20px;
}
.header {
background-color: #007b8f;
color: white;
padding: 20px;
text-align: center;
font-size: 24px;
font-weight: bold;
}
.report-summary {
display: flex;
justify-content: space-between;
margin-top: 20px;
padding: 15px;
background-color: #eef7f9;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.summary-item {
font-size: 18px;
font-weight: bold;
}
.bookings-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
background-color: white;
}
.bookings-table th, .bookings-table td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
.bookings-table th {
background-color: #007b8f;
color: white;
}
.total-row {
font-weight: bold;
background-color: #eef7f9;
}
</style>
</head> </head>
<body> <body>
<h1>Bilan réservations</h1> <div class="header">
<h2>{{month}} {{ year }}</h2> Rapport Mensuel - {{ .Month }} {{ .Year }}
<div class="overflow-auto"> </div>
<table class="items-table">
<thead> <div class="report-summary">
<tr> <div class="summary-item">Revenu total : {{ .Total }} €</div>
<th scope="col">#</th> <div class="summary-item">dont paiements par Carte Bancaire : {{ .CardTotal }} €</div>
<th scope="col">Nom</th> <div class="summary-item">Frais Booking.com : {{ .BookingFees }} €</div>
<th scope="col">Du</th> <div class="summary-item">Frais NemoImmo : {{ .Fee }} €</div>
<th scope="col">Au</th> <div class="summary-item">Bénéfice : {{ .Profit }} €</div>
<th scope="col">Revenue (€)</th> </div>
<th scope="col">Platforme</th>
<th scope="col">Commission (€)</th> <table class="bookings-table">
<th scope="col">NemoImmo (€)</th> <thead>
<th scope="col">Profit (€)</th> <tr>
</tr> <th>N° Facture</th>
</thead> <th>Nom Client</th>
<tbody> <th>Du</th>
{% for row in lines %} <th>Au</th>
<tr> <th>Revenu (€)</th>
<th scope="row"> {{ row.Id }} </th> <th>Plateforme</th>
<td>{{ row.CustomerName }}</td> <th>Frais Plateforme (€)</th>
<td>{{ row.From }}</td> <th>Frais NemoImmo (€)</th>
<td>{{ row.To }}</td> <th>Bénéfice (€)</th>
<td>{{ row.Total }}</td> </tr>
<td>{{ row.Platform }}</td> </thead>
<td>{{ row.PlatformFees }}</td> <tbody>
<td>{{ row.Fee }}</td> {{ range .Lines }}
<td>{{ row.Profit }}</td> <tr>
</tr> <td>{{ .InvoiceNumber }}</td>
{% endfor %} <td>{{ .CustomerName }}</td>
</tbody> <td>{{ .From }}</td>
<tfoot> <td>{{ .To }}</td>
<tr> <td>{{ .Total }}</td>
<td scope="row">Totaux</td> <td>{{ .Platform }}</td>
<td></td> <td>{{ .PlatformFees }}</td>
<td></td> <td>{{ .Fee }}</td>
<td></td> <td>{{ .Profit }}</td>
<td>{{ total }}</td> </tr>
<td></td> {{ end }}
<td>{{ platformFees }}</td> </tbody>
<td>{{ fee }}</td> <tfoot>
<td>{{ profit }}</td> <tr class="total-row">
</tr> <td colspan="4">Totaux</td>
<tr> <td>{{ .Total }}</td>
<td scope="row"></td> <td></td>
<td></td> <td>{{ .PlatformFees }}</td>
<td></td> <td>{{ .Fee }}</td>
<td>dont CB :</td> <td>{{ .Profit }}</td>
<td>{{ cardTotal }}</td> </tr>
<td>Frais Booking :</td> </tfoot>
<td>{{ bookingFees }}</td> </table>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</body> </body>
</html> </html>

View file

@ -13,4 +13,4 @@ func (p Platform) ToFrench() string {
type Translatable interface { type Translatable interface {
ToFrench() string ToFrench() string
} }

View file

@ -1,6 +1,8 @@
package constant package constant
var Months = []string{ type Month string
var Months = []Month{
"January", "January",
"February", "February",
"March", "March",
@ -14,3 +16,20 @@ var Months = []string{
"November", "November",
"December", "December",
} }
func (m Month) ToFrench() string {
return map[Month]string{
"January": "Janvier",
"February": "Février",
"March": "Mars",
"April": "Avril",
"May": "Mai",
"June": "Juin",
"July": "Juillet",
"August": "Août",
"September": "Septembre",
"October": "Octobre",
"November": "Novembre",
"December": "Décembre",
}[m]
}

View file

@ -3,6 +3,7 @@ package pdf
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"log"
"os" "os"
"text/template" "text/template"
@ -36,6 +37,23 @@ func (pc *HtmlPdfClient) BuildInvoice(data booking.Invoice) (string, error) {
return outputPath, nil return outputPath, nil
} }
func (pc *HtmlPdfClient) BuildReport(context map[string]any, period string, month int, year int) error { func (pc *HtmlPdfClient) BuildReport(report booking.ReportData, period string, month int, year int) (string, error) {
panic("unimplemented") tmpl, err := template.ParseFS(assets.Static, "assets/html/report.html")
if err != nil {
return "", fmt.Errorf("error parsing template: %v", err)
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, report); err != nil {
log.Printf("err: %+v\n", err)
return "", fmt.Errorf("error executing template: %v", err)
}
outputPath := fmt.Sprintf("report-%s-%d-%d.html", period, month, year)
if err := os.WriteFile(outputPath, buf.Bytes(), 0644); err != nil {
log.Printf("err: %+v\n", err)
return "", fmt.Errorf("error writing HTML file: %v", err)
}
return outputPath, nil
} }

View file

@ -62,11 +62,11 @@ func handlePdfCreateReport(bs *booking.Service) echo.HandlerFunc {
} }
report := bs.Report(period, month, year) report := bs.Report(period, month, year)
err = bs.BuildReport(report, period, month, year) filePath,err := bs.BuildReport(report, period, month, year)
if err != nil { if err != nil {
return err return err
} }
return c.Attachment("tmp.pdf", fmt.Sprintf("VF-%02d-report.pdf", month)) return c.File(filePath)
} }
} }

View file

@ -29,7 +29,9 @@ func handleReportsPage() echo.HandlerFunc {
if err != nil { if err != nil {
yearStr = time.Now().Format("2006") yearStr = time.Now().Format("2006")
} }
return renderTempl(c, http.StatusOK, view.Reports(constant.Months, month, yearStr)) return renderTempl(c, http.StatusOK, view.Reports(u.Map(constant.Months, func(m constant.Month) string {
return string(m)
}), month, yearStr))
} }
} }

View file

@ -6,8 +6,13 @@ import (
"time" "time"
u "github.com/rjNemo/underscore" u "github.com/rjNemo/underscore"
"github.com/rjNemo/rentease/internal/config"
"github.com/rjNemo/rentease/internal/constant"
) )
var hc = config.NewHost()
type Report struct { type Report struct {
Lines []*Line Lines []*Line
Total float64 Total float64
@ -18,27 +23,51 @@ type Report struct {
BookingFees float64 BookingFees float64
} }
func (r Report) Serialize(month, year int) map[string]any { type ReportData struct {
return map[string]any{ Month string
"month": month, Year int
"year": year, Total string
"total": strconv.FormatFloat(r.Total, 'f', 2, 64), PlatformFees string
"platform_fees": strconv.FormatFloat(r.PlatformFees, 'f', 2, 64), Fee string
"fee": strconv.FormatFloat(r.Fee, 'f', 2, 64), Profit string
"profit": strconv.FormatFloat(r.Profit, 'f', 2, 64), CardTotal string
"card_total": strconv.FormatFloat(r.CardTotal, 'f', 2, 64), BookingFees string
"booking_fees": strconv.FormatFloat(r.BookingFees, 'f', 2, 64), Lines []ReportLine
"lines": u.Map(r.Lines, func(l *Line) map[string]any { }
return map[string]any{
"id": l.Id, type ReportLine struct {
"name": l.CustomerName, InvoiceNumber string
"from": l.From.Format("02/01/2006"), CustomerName string
"to": l.To.Format("02/01/2006"), From string
"total": strconv.FormatFloat(l.Total, 'f', 2, 64), To string
"platform": l.Platform, Total string
"platform_fees": strconv.FormatFloat(l.PlatformFees, 'f', 2, 64), Platform string
"fee": strconv.FormatFloat(l.Fee(), 'f', 2, 64), PlatformFees string
"profit": strconv.FormatFloat(l.Profit(), 'f', 2, 64), Fee string
Profit string
}
func (r Report) Data(month, year int) ReportData {
return ReportData{
Month: constant.Months[month-1].ToFrench(),
Year: year,
Total: strconv.FormatFloat(r.Total, 'f', 2, 64),
PlatformFees: strconv.FormatFloat(r.PlatformFees, 'f', 2, 64),
Fee: strconv.FormatFloat(r.Fee, 'f', 2, 64),
Profit: strconv.FormatFloat(r.Profit, 'f', 2, 64),
CardTotal: strconv.FormatFloat(r.CardTotal, 'f', 2, 64),
BookingFees: strconv.FormatFloat(r.BookingFees, 'f', 2, 64),
Lines: u.Map(r.Lines, func(l *Line) ReportLine {
return ReportLine{
InvoiceNumber: l.InvoiceNumber(hc),
CustomerName: l.CustomerName,
From: l.From.Format("02/01/2006"),
To: l.To.Format("02/01/2006"),
Total: strconv.FormatFloat(l.Total, 'f', 2, 64),
Platform: l.Platform,
PlatformFees: strconv.FormatFloat(l.PlatformFees, 'f', 2, 64),
Fee: strconv.FormatFloat(l.Fee(), 'f', 2, 64),
Profit: strconv.FormatFloat(l.Profit(), 'f', 2, 64),
} }
}), }),
} }
@ -82,6 +111,6 @@ func (bs Service) Report(period string, month, year int) *Report {
} }
} }
func (bs Service) BuildReport(report *Report, period string, month, year int) error { func (bs Service) BuildReport(report *Report, period string, month, year int) (string, error) {
return bs.pdf.BuildReport(report.Serialize(month, year), period, month, year) return bs.pdf.BuildReport(report.Data(month, year), period, month, year)
} }

View file

@ -31,7 +31,7 @@ type Store interface {
type PdfClient interface { type PdfClient interface {
BuildInvoice(invoice Invoice) (string, error) BuildInvoice(invoice Invoice) (string, error)
BuildReport(context map[string]any, period string, month, year int) error BuildReport(report ReportData, period string, month, year int) (string, error)
} }
type CalendarClient interface { type CalendarClient interface {