refactor building invoice

This commit is contained in:
Ruidy 2025-02-04 10:39:07 +01:00
parent 7796f71590
commit 85c65f2201
No known key found for this signature in database
GPG key ID: E00F51288CB857CC
10 changed files with 56 additions and 138 deletions

File diff suppressed because one or more lines are too long

View file

@ -149,12 +149,12 @@
<body>
<div class="header space-between">
<img class="logo" src="assets/img/logo.png" />
<img class="logo" src="/static/img/logo.png" />
<div class="payee">
<b>{{ .Host.Name }}</b><br />
{{ .Host.Address }}<br />
{{ .Host.ZipCode }} {{ .Host.City }}<br />
<b>Tel :</b> {{ .Host.Phone }}<br />
<b>Tel :</b> {{ .Host.PhoneNumber }}<br />
<b>Mail :</b> {{ .Host.Email }}<br />
</div>
</div>
@ -170,7 +170,7 @@
<td>{{ .PhoneNumber }}</td>
</tr>
<tr>
<td><strong>Client :</strong></td>
<td><strong>Nombre de clients :</strong></td>
<td>{{ .CustomersNumber }}</td>
</tr>
<tr>

View file

@ -1,83 +0,0 @@
package main
import (
"bytes"
"html/template"
"log"
"os"
"time"
"github.com/rjNemo/rentease/internal/config"
"github.com/rjNemo/rentease/internal/service/booking"
)
func main() {
type Invoice struct {
Host struct {
Name string
Address string
ZipCode string
City string
Phone string
Email string
}
Name string
PhoneNumber string
CustomersNumber int
Platform string
ID string
From string
To string
Total string
AmountPaid string
BalanceDue string
Lines []struct {
Name string
Quantity int
Price string
Total string
}
Payments []struct {
Date string
Method string
Amount string
}
}
// Assume these values come from your application's context.
host := config.NewHost()
booking := booking.Booking{
Name: "Michel Le Corre",
PhoneNumber: "+590 690 44 15 30",
CustomerNumber: 2,
Platform: "Privée",
From: time.Date(2025, time.January, 15, 0, 0, 0, 0, time.UTC),
To: time.Date(2025, time.March, 15, 0, 0, 0, 0, time.UTC),
Items: []booking.Item{
{Item: "T2", Quantity: 59, Price: 35.00},
},
}
// Get dynamic invoice data from the booking via Serialize.
invoiceData := booking.Serialize(host)
// Parse the HTML template.
tmpl, err := template.ParseFiles("assets/html/invoice.html")
if err != nil {
log.Fatalf("Error parsing template: %v", err)
}
// Create a buffer to hold the rendered HTML.
var buf bytes.Buffer
if err := tmpl.Execute(&buf, invoiceData); err != nil {
log.Fatalf("Error executing template: %v", err)
}
// Write the rendered HTML to an output file.
outputPath := "output.html"
if err := os.WriteFile(outputPath, buf.Bytes(), 0644); err != nil {
log.Fatalf("Error writing HTML file: %v", err)
}
log.Printf("HTML file created successfully: %s", outputPath)
}

View file

@ -2,6 +2,7 @@ package server
import (
"fmt"
"log"
"net/http"
"strconv"
@ -17,17 +18,18 @@ func handlePdfCreateInvoice(bs *booking.Service, hc *config.Host) echo.HandlerFu
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
log.Println(err)
return err
}
b := bs.One(id)
err = bs.BuildInvoice(b, hc)
filePath, err := bs.BuildInvoice(b, hc)
if err != nil {
log.Println(err)
return err
}
return c.File("output.html")
// return c.File("output.html", fmt.Sprintf("VFNI-%s.pdf", b.InvoiceNumber(hc)))
return c.File(filePath)
}
}

View file

@ -22,7 +22,6 @@ func SentryTracingMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
sentry.WithOpName("http.server"),
sentry.ContinueFromRequest(c.Request()),
sentry.WithTransactionSource(sentry.SourceURL),
}
transaction := sentry.StartTransaction(ctx,

View file

@ -1,5 +1,7 @@
package booking
import "github.com/rjNemo/rentease/internal/config"
type InvoiceLine struct {
Name string
Quantity int
@ -14,14 +16,7 @@ type PaymentLine struct {
}
type Invoice struct {
Host struct {
Name string
Address string
ZipCode string
City string
Phone string
Email string
}
Host config.Host
Name string
PhoneNumber string
CustomersNumber int

View file

@ -58,21 +58,7 @@ func (b Booking) ToInvoice(hc *config.Host) Invoice {
}, 0.0)
return Invoice{
Host: struct {
Name string
Address string
ZipCode string
City string
Phone string
Email string
}{
Name: hc.Name,
Address: hc.Address,
ZipCode: hc.ZipCode,
City: hc.City,
Phone: hc.PhoneNumber,
Email: hc.Email,
},
Host: *hc,
Name: b.Name,
PhoneNumber: b.PhoneNumber,
CustomersNumber: b.CustomerNumber,

View file

@ -2,6 +2,7 @@ package booking
import (
"bytes"
"fmt"
"log"
"os"
"text/template"
@ -103,27 +104,26 @@ func (bs Service) Cancel(id int) {
}
}
func (bs Service) BuildInvoice(b *Booking, hc *config.Host) error {
func (bs Service) BuildInvoice(b *Booking, hc *config.Host) (string, error) {
invoiceData := b.ToInvoice(hc)
log.Printf("%+v", invoiceData)
tmpl, err := template.ParseFiles("assets/html/invoice.html")
if err != nil {
log.Fatalf("Error parsing template: %v", err)
return "", fmt.Errorf("Error parsing template: %v", err)
}
// Create a buffer to hold the rendered HTML.
var buf bytes.Buffer
if err := tmpl.Execute(&buf, invoiceData); err != nil {
log.Fatalf("Error executing template: %v", err)
return "", fmt.Errorf("error executing template: %v", err)
}
// Write the rendered HTML to an output file.
outputPath := "output.html"
outputPath := fmt.Sprintf("%s.html", b.InvoiceNumber(hc))
if err := os.WriteFile(outputPath, buf.Bytes(), 0644); err != nil {
log.Fatalf("Error writing HTML file: %v", err)
return "", fmt.Errorf("error writing HTML file: %v", err)
}
log.Printf("HTML file created successfully: %s", outputPath)
return nil
return outputPath, nil
}

View file

@ -14,16 +14,30 @@ templ BookingById(booking *BookingViewModel) {
</hgroup>
<div class="flex items-center gap-4">
<a class="btn btn-primary btn-sm" href={ booking.PdfUrl } target="_blank">Create PDF</a>
<a href="https://web.whatsapp.com/" target="_blank" rel="noreferrer noopener" class="btn btn-ghost btn-sm btn-square">
<a
href="https://web.whatsapp.com/"
target="_blank"
rel="noreferrer noopener"
class="btn btn-ghost btn-sm btn-square"
>
<img src="/static/icons/whatsapp.png" class="w-6 h-6"/>
</a>
<a href="https://dashboard.stripe.com/payments/new" target="_blank" rel="noreferrer noopener" class="btn btn-ghost btn-sm btn-square">
<a
href="https://dashboard.stripe.com/payments/new"
target="_blank"
rel="noreferrer noopener"
class="btn btn-ghost btn-sm btn-square"
>
<img src="/static/icons/stripe.png" class="w-6 h-6"/>
</a>
if booking.Canceled {
<span class="badge badge-error">Canceled</span>
} else {
<button class="btn btn-outline btn-error btn-sm" hx-patch={ booking.CancelUrl } hx-swap="outerHTML">Cancel</button>
<button
class="btn btn-outline btn-error btn-sm"
hx-patch={ booking.CancelUrl }
hx-swap="outerHTML"
>Cancel</button>
}
</div>
</section>
@ -31,7 +45,9 @@ templ BookingById(booking *BookingViewModel) {
@BookingForm(*booking)
</section>
<section class="p-4 bg-base-100 rounded-lg shadow-sm">
<h3 class="text-xl font-semibold mb-4 flex justify-between items-center">Line Items <button class="btn btn-sm btn-success" onclick="payment_modal.showModal()">Add Payment</button></h3>
<h3 class="text-xl font-semibold mb-4 flex justify-between items-center">
Line Items <button class="btn btn-sm btn-success" onclick="payment_modal.showModal()">Add Payment</button>
</h3>
<div class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
@ -57,7 +73,14 @@ templ BookingById(booking *BookingViewModel) {
</section>
<details class="collapse bg-base-200 mt-8">
<summary class="collapse-title text-xl font-medium flex items-center gap-2 hover:bg-base-300">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"></path>
</svg>
Add New Line Item

View file

@ -98,7 +98,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(booking.CancelUrl)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 26, Col: 82}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 38, Col: 34}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@ -132,7 +132,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(booking.Total)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 51, Col: 26}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 67, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@ -145,7 +145,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/items", booking.Url))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 67, Col: 51}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 90, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
@ -163,7 +163,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(item)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 79, Col: 28}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 102, Col: 28}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@ -176,7 +176,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(item)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 79, Col: 37}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 102, Col: 37}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@ -199,7 +199,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(paymentMethod)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 115, Col: 37}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 138, Col: 37}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
@ -212,7 +212,7 @@ func BookingById(booking *BookingViewModel) templ.Component {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(paymentMethod)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 115, Col: 55}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 138, Col: 55}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
@ -269,7 +269,7 @@ func PaymentModal(paymentUrl string) templ.Component {
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(paymentUrl)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 137, Col: 24}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 160, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {