mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-06 02:36:49 +00:00
parent
49c49f4098
commit
541c813be0
30 changed files with 1194 additions and 340 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -29,3 +29,4 @@ tmp.pdf
|
|||
*templ.txt
|
||||
token.json
|
||||
.aider*
|
||||
output.html
|
||||
|
|
@ -1,115 +1,288 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f9f9f9;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="main.css">
|
||||
</head>
|
||||
.header {
|
||||
background-color: #007b8f;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
<body>
|
||||
<div class="header space-between">
|
||||
<img class="logo" src="logo.png">
|
||||
.logo {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.payee {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid #ddd;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.info-table {
|
||||
width: 48%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.info-table td {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.billing-details {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.items-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.items-table th,
|
||||
.items-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.items-table th {
|
||||
background-color: #007b8f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.items-table .align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.bg-gray {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.payment-summary {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.summary-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.summary-table td {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.payment-history h3 {
|
||||
color: #007b8f;
|
||||
}
|
||||
|
||||
.history-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.history-table th,
|
||||
.history-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.history-table th {
|
||||
background-color: #007b8f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #eef7f9;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.order-total {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.total {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.amount-due {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.amount-due-total {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #007b8f;
|
||||
}
|
||||
|
||||
.space-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.text-break {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header space-between">
|
||||
<img class="logo" src="assets/img/logo.png"/>
|
||||
<div class="payee">
|
||||
<b>{{ host.name }}</b><br/>
|
||||
{{ host.address }}<br/>
|
||||
{{ host.zip_code}} {{ host.city }}<br/>
|
||||
<b>Tel : </b>{{ host.phone }}<br/>
|
||||
<b>Mail : </b>{{host.email }}<br/>
|
||||
<b>{{ .Host.Name }}</b><br/>
|
||||
{{ .Host.Address }}<br/>
|
||||
{{ .Host.ZipCode }} {{ .Host.City }}<br/>
|
||||
<b>Tel :</b> {{ .Host.Phone }}<br/>
|
||||
<b>Mail :</b> {{ .Host.Email }}<br/>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="billing-details space-between">
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="billing-details space-between">
|
||||
<table class="info-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{name}}</strong></td>
|
||||
<td><strong>{{ .Name }}</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Tel : </strong></td>
|
||||
<td>{{phone_number}}</td>
|
||||
<td><strong>Tel :</strong></td>
|
||||
<td>{{ .PhoneNumber }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Voyageurs : </strong></td>
|
||||
<td>{{ customers_number }}</td>
|
||||
<td><strong>Client :</strong></td>
|
||||
<td>{{ .CustomersNumber }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Plateforme : </strong></td>
|
||||
<td>{{platform}}</td>
|
||||
<td><strong>Plateforme :</strong></td>
|
||||
<td>{{ .Platform }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="info-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Nº de facture : </strong></td>
|
||||
<td>{{id}}</td>
|
||||
<td><strong>Nº de facture :</strong></td>
|
||||
<td>{{ .ID }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Du : </strong></td>
|
||||
<td>{{ from }}</td>
|
||||
<td><strong>Du :</strong></td>
|
||||
<td>{{ .From }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Au : </strong></td>
|
||||
<td>{{ to }}</td>
|
||||
<td><strong>Au :</strong></td>
|
||||
<td>{{ .To }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Montant : </strong></td>
|
||||
<td>{{ total }}</td>
|
||||
<td><strong>Montant Total :</strong></td>
|
||||
<td>{{ .Total }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="order-details">
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="order-details">
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Objet</th>
|
||||
<th>Quantité</th>
|
||||
<th>Prix</th>
|
||||
<th class="align-right">Total</th>
|
||||
<th>Prix (€)</th>
|
||||
<th class="align-right">Total (€)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-gray rounded">
|
||||
{% for row in lines %}
|
||||
{{ range .Lines }}
|
||||
<tr class="item-row">
|
||||
<td class="text-break product_name">
|
||||
{{ row.name }}
|
||||
</td>
|
||||
<td>{{ row.quantity }}</td>
|
||||
<td>{{row.price }}</td>
|
||||
<td class="align-right">{{ row.total }}</td>
|
||||
<td class="text-break product_name">{{ .Name }}</td>
|
||||
<td>{{ .Quantity }}</td>
|
||||
<td>{{ .Price }}</td>
|
||||
<td class="align-right">{{ .Total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="order-summary space-between">
|
||||
</div>
|
||||
|
||||
<div class="payment-history">
|
||||
<h3>Historique des Paiements</h3>
|
||||
<table class="history-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Mode de Paiement</th>
|
||||
<th>Montant (€)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Payments }}
|
||||
<tr>
|
||||
<td>{{ .Date }}</td>
|
||||
<td>{{ .Method }}</td>
|
||||
<td>{{ .Amount }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="payment-summary space-between">
|
||||
<table class="summary-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Montant Total :</strong></td>
|
||||
<td>{{ .Total }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Montant Payé :</strong></td>
|
||||
<td>{{ .AmountPaid }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Solde Restant :</strong></td>
|
||||
<td>{{ .BalanceDue }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="order-summary space-between">
|
||||
<div class="card">
|
||||
<b>Notes</b> <br/>
|
||||
TVA non applicable, art. 293 B du CGI <br/>
|
||||
Dispensé d’immatriculation au registre du commerce et des sociétés (RCS) et au répertoire des métiers. <br/>
|
||||
Conditions de paiement : paiement à réception de facture. Aucun escompte consenti pour règlement anticipé ou désistement. Tout incident de paiement est passible d'intérêts de retard. Le montant des pénalités résulte de l'application aux sommes restant dues d'un taux d'intérêt légal en vigueur au moment de l'incident. <br/>
|
||||
Dispensé d’immatriculation au registre du commerce et des sociétés (RCS)
|
||||
et au répertoire des métiers. <br/>
|
||||
Conditions de paiement : paiement à réception de facture. Aucun escompte
|
||||
consenti pour règlement anticipé ou désistement. Tout incident de
|
||||
paiement est passible d'intérêts de retard. Le montant des pénalités
|
||||
résulte de l'application aux sommes restant dues d'un taux d'intérêt
|
||||
légal en vigueur au moment de l'incident. <br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-total space-between">
|
||||
</div>
|
||||
<div class="order-total space-between">
|
||||
<div></div>
|
||||
<div class="total">
|
||||
<div class="amount-due">
|
||||
Total
|
||||
<div class="amount-due">Total</div>
|
||||
<div class="amount-due-total">{{ .Total }}</div>
|
||||
</div>
|
||||
<div class="amount-due-total">
|
||||
{{ total }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
124
cmd/pdf/main.go
Normal file
124
cmd/pdf/main.go
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
const invoiceTemplate = "assets/html/invoice.html"
|
||||
|
||||
func main() {
|
||||
// Define the invoice data structure
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Read the template file
|
||||
tmpl, err := template.ParseFiles(invoiceTemplate)
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing template: %v", err)
|
||||
}
|
||||
|
||||
// Create sample invoice data
|
||||
invoice := Invoice{
|
||||
Host: struct {
|
||||
Name string
|
||||
Address string
|
||||
ZipCode string
|
||||
City string
|
||||
Phone string
|
||||
Email string
|
||||
}{
|
||||
Name: "VillaFleurie",
|
||||
Address: "4 rue Gerty Archimede",
|
||||
ZipCode: "97190",
|
||||
City: "Le Gosier",
|
||||
Phone: "+590 690 44 15 30",
|
||||
Email: "location.villafleurie@gmail.com",
|
||||
},
|
||||
Name: "Michel Le Corre",
|
||||
//PhoneNumber: "+590 690 44 15 30",
|
||||
CustomersNumber: 2,
|
||||
Platform: "Privée",
|
||||
ID: "VFNI0332",
|
||||
From: "15 Janvier 2025",
|
||||
To: "15 Mars 2025",
|
||||
Total: "2065.00 €",
|
||||
AmountPaid: "1565.00 €",
|
||||
BalanceDue: "500.00 €",
|
||||
Lines: []struct {
|
||||
Name string
|
||||
Quantity int
|
||||
Price string
|
||||
Total string
|
||||
}{
|
||||
{
|
||||
Name: "T2",
|
||||
Quantity: 59,
|
||||
Price: "35.00",
|
||||
Total: "2065.00",
|
||||
},
|
||||
},
|
||||
Payments: []struct {
|
||||
Date string
|
||||
Method string
|
||||
Amount string
|
||||
}{
|
||||
{
|
||||
"–",
|
||||
"Espèces",
|
||||
"500.00",
|
||||
},
|
||||
{
|
||||
"–",
|
||||
"Chèque",
|
||||
"1065.00",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Create a buffer to store the rendered HTML
|
||||
var buf bytes.Buffer
|
||||
// Execute the template with the invoice data
|
||||
if err := tmpl.Execute(&buf, invoice); err != nil {
|
||||
log.Fatalf("Error executing template: %v", err)
|
||||
}
|
||||
|
||||
// Write the rendered HTML to a 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)
|
||||
}
|
||||
|
|
@ -5,4 +5,5 @@ const (
|
|||
RouteBooking = "/bookings"
|
||||
RouteReports = "/reports"
|
||||
RouteItem = "/items"
|
||||
RoutePayment = "/payments"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@ import (
|
|||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
Create(calendarId, name, description string, from, to time.Time) error
|
||||
}
|
||||
|
||||
type GoogleClient struct {
|
||||
calIds map[string]struct{}
|
||||
*calendar.Service
|
||||
|
|
|
|||
|
|
@ -11,11 +11,6 @@ import (
|
|||
"github.com/labstack/gommon/log"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
BuildInvoice(context map[string]any) error
|
||||
BuildReport(context map[string]any, period string, month, year int) error
|
||||
}
|
||||
|
||||
type PdfClient struct {
|
||||
path string
|
||||
invoiceId string
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func (ps *PgStore) CardTotal(from, to time.Time) (float64, error) {
|
|||
|
||||
func (ps *PgStore) Get(id int) *booking.Booking {
|
||||
var b booking.Booking
|
||||
ps.db.Preload("Items").First(&b, id)
|
||||
ps.db.Preload("Items").Preload("Payments").First(&b, id)
|
||||
return &b
|
||||
}
|
||||
|
||||
|
|
@ -136,3 +136,29 @@ func (ps *PgStore) UpdateItem(id int, item string, paymentMethod string, payment
|
|||
Error
|
||||
return i, err
|
||||
}
|
||||
|
||||
func (ps *PgStore) CreatePayment(p *booking.Payment) (*booking.Payment, error) {
|
||||
if err := ps.db.Create(p).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to create payment: %w", err)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (ps *PgStore) GetPayment(id int) (*booking.Payment, error) {
|
||||
p := &booking.Payment{}
|
||||
err := ps.db.First(p, id).Error
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (ps *PgStore) UpdatePayment(id int, amount float64, paymentMethod string) (*booking.Payment, error) {
|
||||
p := new(booking.Payment)
|
||||
err := ps.db.Model(p).
|
||||
Clauses(clause.Returning{}).
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]any{
|
||||
"amount": amount,
|
||||
"payment_method": paymentMethod,
|
||||
}).
|
||||
Error
|
||||
return p, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,21 @@ func handleBookingListPage(bs *booking.Service, hc *config.Host) echo.HandlerFun
|
|||
}
|
||||
}
|
||||
|
||||
func handleBookingList(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
search := c.FormValue("search")
|
||||
|
||||
var bookings []*booking.Line
|
||||
if search != "" {
|
||||
bookings = bs.Search(search)
|
||||
} else {
|
||||
bookings = bs.All()
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, bookings)
|
||||
}
|
||||
}
|
||||
|
||||
func handleBookingCreatePage(hc *config.Host) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
return renderTempl(c, http.StatusOK, view.NewBooking(hc.Platforms))
|
||||
|
|
@ -122,6 +137,8 @@ func handleBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|||
Url: templ.EscapeString(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)),
|
||||
PdfUrl: templ.SafeURL(fmt.Sprintf("%s/pdf/%d", constant.RouteBooking, b.Id)),
|
||||
CancelUrl: fmt.Sprintf("%s/%d/cancel", constant.RouteBooking, b.Id),
|
||||
PaymentUrl: fmt.Sprintf("%s/%d", constant.RoutePayment, b.Id),
|
||||
Items: view.ItemListViewModel{
|
||||
Items: u.Map(b.Items, func(i booking.Item) view.ItemViewModel {
|
||||
return view.ItemViewModel{
|
||||
Id: strconv.Itoa(i.Id),
|
||||
|
|
@ -129,11 +146,18 @@ func handleBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|||
Quantity: strconv.Itoa(i.Quantity),
|
||||
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
||||
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
||||
PaymentMethod: i.PaymentMethod,
|
||||
PaymentStatus: i.PaymentStatus,
|
||||
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
||||
}
|
||||
}),
|
||||
Payments: u.Map(b.Payments, func(p booking.Payment) view.PaymentViewModel {
|
||||
return view.PaymentViewModel{
|
||||
Amount: strconv.FormatFloat(p.Amount, 'f', 2, 64),
|
||||
PaymentMethod: p.PaymentMethod,
|
||||
PaymentUrl: fmt.Sprintf("%s/%d", constant.RoutePayment, p.ID),
|
||||
}
|
||||
}),
|
||||
},
|
||||
Total: strconv.FormatFloat(u.Reduce(b.Items, func(i booking.Item, sum float64) float64 {
|
||||
return sum + i.Price*float64(i.Quantity)
|
||||
}, 0.0), 'f', 2, 64),
|
||||
|
|
@ -219,7 +243,6 @@ func handleLineItemForm(bs *booking.Service) echo.HandlerFunc {
|
|||
Item: i.Item,
|
||||
Quantity: strconv.Itoa(i.Quantity),
|
||||
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
||||
PaymentMethod: i.PaymentMethod,
|
||||
PaymentStatus: i.PaymentStatus,
|
||||
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
||||
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
||||
|
|
@ -275,7 +298,6 @@ func handleCreateItem(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|||
Item: i.Item,
|
||||
Quantity: strconv.Itoa(i.Quantity),
|
||||
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
||||
PaymentMethod: i.PaymentMethod,
|
||||
PaymentStatus: i.PaymentStatus,
|
||||
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
||||
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
||||
|
|
@ -300,7 +322,6 @@ func handleItemPay(bs *booking.Service) echo.HandlerFunc {
|
|||
Item: i.Item,
|
||||
Quantity: strconv.Itoa(i.Quantity),
|
||||
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
||||
PaymentMethod: i.PaymentMethod,
|
||||
PaymentStatus: i.PaymentStatus,
|
||||
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
||||
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
||||
|
|
@ -332,7 +353,6 @@ func handleItemUpdate(bs *booking.Service) echo.HandlerFunc {
|
|||
Item: i.Item,
|
||||
Quantity: strconv.Itoa(i.Quantity),
|
||||
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
||||
PaymentMethod: i.PaymentMethod,
|
||||
PaymentStatus: i.PaymentStatus,
|
||||
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
||||
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
||||
|
|
@ -340,6 +360,29 @@ func handleItemUpdate(bs *booking.Service) echo.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handlePaymentUpdate(bs *booking.Service) echo.HandlerFunc {
|
||||
type updatePayment struct {
|
||||
Id int `param:"id"`
|
||||
Amount float64 `form:"amount"`
|
||||
PaymentMethod string `form:"paymentMethod"`
|
||||
}
|
||||
return func(c echo.Context) error {
|
||||
up := new(updatePayment)
|
||||
|
||||
if err := c.Bind(up); err != nil {
|
||||
return fmt.Errorf("could not parse update payment request body: %w", err)
|
||||
}
|
||||
|
||||
p := bs.UpdatePayment(up.Id, up.Amount, up.PaymentMethod)
|
||||
|
||||
return renderTempl(c, http.StatusOK, view.PaymentLine(&view.PaymentViewModel{
|
||||
Amount: strconv.FormatFloat(p.Amount, 'f', 2, 64),
|
||||
PaymentMethod: p.PaymentMethod,
|
||||
PaymentUrl: fmt.Sprintf("%s/%d", constant.RoutePayment, p.ID),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func handleBookingCancel(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
idStr := c.Param("id")
|
||||
|
|
|
|||
80
internal/server/handle_payments.go
Normal file
80
internal/server/handle_payments.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
u "github.com/rjNemo/underscore"
|
||||
|
||||
"github.com/rjNemo/rentease/internal/constant"
|
||||
"github.com/rjNemo/rentease/internal/service/booking"
|
||||
"github.com/rjNemo/rentease/internal/view"
|
||||
)
|
||||
|
||||
func handleCreatePayment(bs *booking.Service) echo.HandlerFunc {
|
||||
type CreatePaymentInput struct {
|
||||
Amount float64 `form:"amount"`
|
||||
PaymentMethod string `form:"paymentMethod"`
|
||||
}
|
||||
|
||||
return func(c echo.Context) error {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
np := new(CreatePaymentInput)
|
||||
c.Bind(np)
|
||||
|
||||
b := bs.One(id)
|
||||
|
||||
_, err = bs.CreatePayment(b.Id, np.Amount, np.PaymentMethod)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nb := bs.One(id)
|
||||
|
||||
return renderTempl(c, http.StatusOK, view.ItemList(view.ItemListViewModel{
|
||||
Items: u.Map(nb.Items, func(i booking.Item) view.ItemViewModel {
|
||||
return view.ItemViewModel{
|
||||
Id: strconv.Itoa(i.Id),
|
||||
Item: i.Item,
|
||||
Quantity: strconv.Itoa(i.Quantity),
|
||||
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
||||
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
||||
PaymentStatus: i.PaymentStatus,
|
||||
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
||||
}
|
||||
}),
|
||||
Payments: u.Map(nb.Payments, func(p booking.Payment) view.PaymentViewModel {
|
||||
return view.PaymentViewModel{
|
||||
Amount: strconv.FormatFloat(p.Amount, 'f', 2, 64),
|
||||
PaymentMethod: p.PaymentMethod,
|
||||
PaymentUrl: fmt.Sprintf("%s/%d", constant.RoutePayment, p.ID),
|
||||
}
|
||||
}),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func handlePaymentForm(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := bs.OnePayment(id)
|
||||
form := view.PaymentForm(&view.PaymentViewModel{
|
||||
Amount: strconv.FormatFloat(p.Amount, 'f', 2, 64),
|
||||
PaymentMethod: p.PaymentMethod,
|
||||
PaymentUrl: fmt.Sprintf("%s/%d", constant.RoutePayment, p.ID),
|
||||
})
|
||||
return renderTempl(c, http.StatusOK, form)
|
||||
}
|
||||
}
|
||||
|
|
@ -18,9 +18,11 @@ func (s Server) MountHandlers() {
|
|||
},
|
||||
}))
|
||||
api.POST("/sync", handleSync(s.bs))
|
||||
api.GET("/bookings", handleBookingList(s.bs))
|
||||
|
||||
private := s.Router.Group("")
|
||||
private.Use(MakeAuthMiddleware(s.as))
|
||||
|
||||
private.GET("/bookings", handleBookingListPage(s.bs, s.hc))
|
||||
private.GET("/bookings/new", handleBookingCreatePage(s.hc))
|
||||
private.POST("/bookings/new", handleBookingCreate(s.bs))
|
||||
|
|
@ -29,10 +31,16 @@ func (s Server) MountHandlers() {
|
|||
private.PATCH("/bookings/:id/cancel", handleBookingCancel(s.bs))
|
||||
private.POST("/bookings/:id/items", handleCreateItem(s.bs, s.hc))
|
||||
private.GET("/bookings/pdf/:id", handlePdfCreateInvoice(s.bs, s.hc))
|
||||
|
||||
private.POST("/items/:id", handleItemPay(s.bs))
|
||||
private.PUT("/items/:id", handleItemUpdate(s.bs))
|
||||
private.GET("/items/:id", handleLineItemForm(s.bs))
|
||||
|
||||
private.GET("/reports", handleReportsPage())
|
||||
private.GET("/reports/do", handleReportCompute(s.bs, s.hc))
|
||||
private.GET("/reports/pdf", handlePdfCreateReport(s.bs))
|
||||
|
||||
private.POST("/payments/:id", handleCreatePayment(s.bs))
|
||||
private.PUT("/payments/:id", handlePaymentUpdate(s.bs))
|
||||
private.GET("/payments/:id", handlePaymentForm(s.bs))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,26 @@ func (m *MockStore) UpdateItem(id int, item string, paymentMethod string, paymen
|
|||
return args.Get(0).(*Item), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockStore) CreatePayment(p *Payment) (*Payment, error) {
|
||||
args := m.Called(p)
|
||||
return args.Get(0).(*Payment), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockStore) GetPayment(id int) (*Payment, error) {
|
||||
args := m.Called(id)
|
||||
return args.Get(0).(*Payment), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockStore) UpdatePayment(id int, amount float64, paymentMethod string) (*Payment, error) {
|
||||
args := m.Called(id, amount, paymentMethod)
|
||||
return args.Get(0).(*Payment), args.Error(1)
|
||||
}
|
||||
|
||||
// MockParserClient is a mock implementation of the parser.Client interface
|
||||
type MockParserClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// MockCalendarClient is a mock implementation of the calendar.Client interface
|
||||
type MockCalendarClient struct {
|
||||
mock.Mock
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type Booking struct {
|
|||
Platform string
|
||||
ExternalId *string `gorm:"uniqueIndex:booking_external_id"`
|
||||
Items []Item
|
||||
Payments []Payment `gorm:"foreignKey:BookingID"`
|
||||
Id int
|
||||
CustomerNumber int `gorm:"column:customers"`
|
||||
PlatformFees float64 `gorm:"type:decimal(10,2)"`
|
||||
|
|
@ -29,7 +30,8 @@ type Booking struct {
|
|||
|
||||
// NewBooking creates a new booking with the given parameters
|
||||
func NewBooking(from, to time.Time, name, phoneNumber, email, platform string,
|
||||
customerNumber int, platformFees float64, externalId *string) *Booking {
|
||||
customerNumber int, platformFees float64, externalId *string,
|
||||
) *Booking {
|
||||
return &Booking{
|
||||
From: from,
|
||||
To: to,
|
||||
|
|
|
|||
23
internal/service/booking/payment.go
Normal file
23
internal/service/booking/payment.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package booking
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Payment struct {
|
||||
gorm.Model
|
||||
BookingID uint `gorm:"not null;index"`
|
||||
Booking Booking `gorm:"foreignKey:BookingID;constraint:OnDelete:CASCADE"`
|
||||
Amount float64
|
||||
PaymentMethod string
|
||||
}
|
||||
|
||||
func (bs Service) OnePayment(id int) *Payment {
|
||||
p, err := bs.store.GetPayment(id)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
|
@ -5,8 +5,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/rjNemo/rentease/internal/config"
|
||||
"github.com/rjNemo/rentease/internal/driver/calendar"
|
||||
"github.com/rjNemo/rentease/internal/driver/pdf"
|
||||
)
|
||||
|
||||
type Store interface {
|
||||
|
|
@ -24,6 +22,20 @@ type Store interface {
|
|||
PayItem(id int) (*Item, error)
|
||||
GetItem(id int) (*Item, error)
|
||||
UpdateItem(id int, item string, paymentMethod string, paymentStatus string, qty int, price float64) (*Item, error)
|
||||
|
||||
// Payment methods
|
||||
CreatePayment(p *Payment) (*Payment, error)
|
||||
GetPayment(id int) (*Payment, error)
|
||||
UpdatePayment(id int, amount float64, paymentMethod string) (*Payment, error)
|
||||
}
|
||||
|
||||
type PdfClient interface {
|
||||
BuildInvoice(context map[string]any) error
|
||||
BuildReport(context map[string]any, period string, month, year int) error
|
||||
}
|
||||
|
||||
type CalendarClient interface {
|
||||
Create(calendarId, name, description string, from, to time.Time) error
|
||||
}
|
||||
|
||||
type parserClient interface {
|
||||
|
|
@ -33,11 +45,11 @@ type parserClient interface {
|
|||
type Service struct {
|
||||
store Store
|
||||
parser parserClient
|
||||
calendar calendar.Client
|
||||
pdf pdf.Client
|
||||
calendar CalendarClient
|
||||
pdf PdfClient
|
||||
}
|
||||
|
||||
func NewService(store Store, parser parserClient, calendar calendar.Client, pdf pdf.Client) (*Service, error) {
|
||||
func NewService(store Store, parser parserClient, calendar CalendarClient, pdf PdfClient) (*Service, error) {
|
||||
return &Service{
|
||||
store: store,
|
||||
parser: parser,
|
||||
|
|
@ -91,3 +103,24 @@ func (bs Service) Cancel(id int) {
|
|||
func (bs Service) BuildInvoice(b *Booking, hc *config.Host) error {
|
||||
return bs.pdf.BuildInvoice(b.Serialize(hc))
|
||||
}
|
||||
|
||||
func (bs Service) CreatePayment(bid int, amount float64, paymentMethod string) (*Payment, error) {
|
||||
p, err := bs.store.CreatePayment(&Payment{
|
||||
BookingID: uint(bid),
|
||||
Amount: amount,
|
||||
PaymentMethod: paymentMethod,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (bs Service) UpdatePayment(id int, amount float64, paymentMethod string) *Payment {
|
||||
p, err := bs.store.UpdatePayment(id, amount, paymentMethod)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
package booking_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/rjNemo/rentease/internal/service/booking"
|
||||
)
|
||||
|
||||
const content = " Date d'arrivée jeu. 3 avr. 2025 Date de départ dim. 6 avr. 2025 Durée de séjour : 3 nuits Nombre de personnes : \n 2\n Nombre d'hébergements \n 1\n Montant total € 186 Nom du client : \n Olga Korovina\n \n ru\n \n okorov.905387@guest.booking.com\n Contactez vos clients ! Indiquez-leur l'heure à laquelle vous souhaitez les accueillir ou l'endroit où ils récupéreront leurs clés. Un simple appel suffit : Afficher le numéro de téléphone Vous pouvez également leur envoyer un e-mail ou un message. Langue préférée \n russe\n Canal : Booking.com Code IATA/TIDS : \n PC029090\n Numéro de réservation : \n 4453602306\n Montant soumis à commission : € 177 Reçu jeu. 2 janv. 2025 Commission : € 31,86 Bloc-notes (usage interne) Ajoutez une note ici \n\n Maison 1 Chambre T2 - VillaFleurie au bourg du Gosier)\n € 186 jeu. 3 avr. 2025 dim. 6 avr. 2025 Nom du client \n Olga Korovina\n Occupation maximum 2 adultes, 2 enfants (3 personnes max.) Photo de l'hébergement Date Tarif Tarif par nuit \n 03 - 04 avril\n \n Standard Rate\n € 59\n 04 - 05 avril\n \n Standard Rate\n € 59\n 05 - 06 avril\n \n Standard Rate\n € 59Sous-total € 177\n Taxe de séjour\n € 1.50 par personne et par nuit € 9Tarif total de l'hébergement € 186 Le tarif comprend 8.9 % de TVA Conversation avec le client \n Aucun message\n \n Les conversations avec vos clients apparaîtront ici.\n Booking.com reçoit tous les messages écrits ici et les traite selon sa Charte de confidentialité et informations sur les cookies Conditions "
|
||||
|
||||
func TestParseFromApi(t *testing.T) {
|
||||
externalId := "4453602306"
|
||||
tests := []struct {
|
||||
name string
|
||||
rawContent string
|
||||
expected *booking.Booking
|
||||
}{
|
||||
{
|
||||
name: "parse booking from raw content",
|
||||
rawContent: content,
|
||||
expected: &booking.Booking{
|
||||
From: time.Date(2025, time.April, 3, 0, 0, 0, 0, time.UTC),
|
||||
To: time.Date(2025, time.April, 6, 0, 0, 0, 0, time.UTC),
|
||||
Name: "Olga Korovina",
|
||||
Email: "okorov.905387@guest.booking.com",
|
||||
Platform: "Booking",
|
||||
CustomerNumber: 2,
|
||||
PlatformFees: 31.86,
|
||||
ExternalId: &externalId,
|
||||
Canceled: false,
|
||||
Items: []booking.Item{
|
||||
{
|
||||
BookingId: 0,
|
||||
Item: "T2",
|
||||
Quantity: 3,
|
||||
Price: 59.0,
|
||||
PaymentMethod: "Card",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
bs, _ := booking.NewService(&booking.MockStore{}, nil, nil, nil)
|
||||
|
||||
actual, err := bs.ParseFromApi(tt.rawContent)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
assert.Equal(t, tt.expected, actual, "expected %v, got %v", tt.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ 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">Line Items</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>
|
||||
|
|
@ -40,19 +40,14 @@ templ BookingById(booking *BookingViewModel) {
|
|||
<th>Quantity</th>
|
||||
<th>Price (€)</th>
|
||||
<th>Payment Method</th>
|
||||
<th>Payment Status</th>
|
||||
<th>Sub-total (€)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="line-items">
|
||||
for _, item := range booking.Items {
|
||||
@LineItem(&item)
|
||||
}
|
||||
</tbody>
|
||||
@ItemList(booking.Items)
|
||||
<tfoot>
|
||||
<tr class="font-semibold">
|
||||
<td colspan="5" class="text-right">Total:</td>
|
||||
<td colspan="4" class="text-right">Total:</td>
|
||||
<td>{ booking.Total }</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
|
@ -129,5 +124,41 @@ templ BookingById(booking *BookingViewModel) {
|
|||
</form>
|
||||
</div>
|
||||
</details>
|
||||
@PaymentModal(booking.PaymentUrl)
|
||||
}
|
||||
}
|
||||
|
||||
templ PaymentModal(paymentUrl string) {
|
||||
<dialog id="payment_modal" class="modal">
|
||||
<div class="modal-box">
|
||||
<h3 class="text-lg font-bold">Add Payment</h3>
|
||||
<form
|
||||
class="py-4 space-y-4"
|
||||
hx-post={ paymentUrl }
|
||||
hx-target="#line-items"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::after-request="if(event.detail.successful) payment_modal.close()"
|
||||
>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Amount</span>
|
||||
</label>
|
||||
<input type="number" step="0.01" name="amount" class="input input-bordered w-full" required autofocus/>
|
||||
</div>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Payment Method</span>
|
||||
</label>
|
||||
<select name="paymentMethod" class="select select-bordered w-full" required>
|
||||
<option value="">Select payment method</option>
|
||||
<option value="Cash">Cash</option>
|
||||
<option value="Card">Card</option>
|
||||
<option value="Cheque">Cheque</option>
|
||||
<option value="Transfer">Bank Transfer</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Payment </button>
|
||||
</form>
|
||||
</div>
|
||||
</dialog>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,24 +117,22 @@ func BookingById(booking *BookingViewModel) templ.Component {
|
|||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</section><section class=\"p-4 bg-base-100 rounded-lg shadow-sm\"><h3 class=\"text-xl font-semibold mb-4\">Line Items</h3><div class=\"overflow-x-auto\"><table class=\"table table-zebra w-full\"><thead><tr><th>Item</th><th>Quantity</th><th>Price (€)</th><th>Payment Method</th><th>Payment Status</th><th>Sub-total (€)</th><th></th></tr></thead> <tbody id=\"line-items\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</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><div class=\"overflow-x-auto\"><table class=\"table table-zebra w-full\"><thead><tr><th>Item</th><th>Quantity</th><th>Price (€)</th><th>Payment Method</th><th>Sub-total (€)</th><th></th></tr></thead>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, item := range booking.Items {
|
||||
templ_7745c5c3_Err = LineItem(&item).Render(ctx, templ_7745c5c3_Buffer)
|
||||
templ_7745c5c3_Err = ItemList(booking.Items).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</tbody><tfoot><tr class=\"font-semibold\"><td colspan=\"5\" class=\"text-right\">Total:</td><td>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<tfoot><tr class=\"font-semibold\"><td colspan=\"4\" class=\"text-right\">Total:</td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
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: 56, Col: 26}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 51, Col: 26}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -147,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: 72, Col: 51}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 67, Col: 51}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -165,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: 84, Col: 28}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 79, Col: 28}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -178,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: 84, Col: 37}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 79, Col: 37}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -201,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: 120, Col: 37}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 115, Col: 37}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -214,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: 120, Col: 55}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/booking_by_id.templ`, Line: 115, Col: 55}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -229,6 +227,10 @@ func BookingById(booking *BookingViewModel) templ.Component {
|
|||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = PaymentModal(booking.PaymentUrl).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
templ_7745c5c3_Err = layout.BaseLayout().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
|
|
@ -239,4 +241,46 @@ func BookingById(booking *BookingViewModel) templ.Component {
|
|||
})
|
||||
}
|
||||
|
||||
func PaymentModal(paymentUrl string) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var13 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var13 == nil {
|
||||
templ_7745c5c3_Var13 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<dialog id=\"payment_modal\" class=\"modal\"><div class=\"modal-box\"><h3 class=\"text-lg font-bold\">Add Payment</h3><form class=\"py-4 space-y-4\" hx-post=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
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}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\" hx-target=\"#line-items\" hx-swap=\"outerHTML\" hx-on::after-request=\"if(event.detail.successful) payment_modal.close()\"><div class=\"form-control w-full\"><label class=\"label\"><span class=\"label-text\">Amount</span></label> <input type=\"number\" step=\"0.01\" name=\"amount\" class=\"input input-bordered w-full\" required autofocus></div><div class=\"form-control w-full\"><label class=\"label\"><span class=\"label-text\">Payment Method</span></label> <select name=\"paymentMethod\" class=\"select select-bordered w-full\" required><option value=\"\">Select payment method</option> <option value=\"Cash\">Cash</option> <option value=\"Card\">Card</option> <option value=\"Cheque\">Cheque</option> <option value=\"Transfer\">Bank Transfer</option></select></div><button type=\"submit\" class=\"btn btn-primary\">Add Payment </button></form></div></dialog>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
|
|
|
|||
|
|
@ -15,11 +15,18 @@ type BookingViewModel struct {
|
|||
ExternalId string
|
||||
Platforms []string
|
||||
PlatformFees string
|
||||
Items []ItemViewModel
|
||||
Items ItemListViewModel
|
||||
ItemList []string
|
||||
PaymentMethods []string
|
||||
Url string
|
||||
PdfUrl templ.SafeURL
|
||||
PaymentUrl string
|
||||
CancelUrl string
|
||||
Total string
|
||||
}
|
||||
|
||||
type PaymentViewModel struct {
|
||||
Amount string
|
||||
PaymentMethod string
|
||||
PaymentUrl string
|
||||
}
|
||||
|
|
|
|||
35
internal/view/item_list.templ
Normal file
35
internal/view/item_list.templ
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package view
|
||||
|
||||
templ ItemList(itemList ItemListViewModel) {
|
||||
<tbody id="line-items">
|
||||
for _, item := range itemList.Items {
|
||||
@LineItem(&item)
|
||||
}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>Price (€)</th>
|
||||
<th>Payment Method</th>
|
||||
<th>Sub-total (€)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
if len(itemList.Payments) >0 {
|
||||
for _,payment := range itemList.Payments {
|
||||
<tr class="hover">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>- { payment.Amount }</td>
|
||||
<td>{ payment.PaymentMethod }</td>
|
||||
<td></td>
|
||||
<td class="flex gap-2">
|
||||
<button class="btn btn-sm btn-outline" hx-get={ payment.PaymentUrl } hx-target="closest tr" hx-swap="outerHTML">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
}
|
||||
101
internal/view/item_list_templ.go
Normal file
101
internal/view/item_list_templ.go
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.3.819
|
||||
package view
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
func ItemList(itemList ItemListViewModel) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<tbody id=\"line-items\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, item := range itemList.Items {
|
||||
templ_7745c5c3_Err = LineItem(&item).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</tbody> <thead><tr><th></th><th></th><th>Price (€)</th><th>Payment Method</th><th>Sub-total (€)</th><th></th></tr></thead> <tbody>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if len(itemList.Payments) > 0 {
|
||||
for _, payment := range itemList.Payments {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<tr class=\"hover\"><td></td><td></td><td>- ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(payment.Amount)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/item_list.templ`, Line: 25, Col: 27}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(payment.PaymentMethod)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/item_list.templ`, Line: 26, Col: 32}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</td><td></td><td class=\"flex gap-2\"><button class=\"btn btn-sm btn-outline\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(payment.PaymentUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/item_list.templ`, Line: 29, Col: 72}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" hx-target=\"closest tr\" hx-swap=\"outerHTML\">Edit</button></td></tr>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</tbody>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
6
internal/view/item_list_viewmodel.go
Normal file
6
internal/view/item_list_viewmodel.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package view
|
||||
|
||||
type ItemListViewModel struct {
|
||||
Items []ItemViewModel
|
||||
Payments []PaymentViewModel
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ type ItemViewModel struct {
|
|||
Quantity string
|
||||
Price string
|
||||
SubTotal string
|
||||
PaymentMethod string
|
||||
PaymentStatus string
|
||||
ItemUrl string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,10 @@ templ LineItem(item *ItemViewModel) {
|
|||
<td>{ item.Item }</td>
|
||||
<td>{ item.Quantity }</td>
|
||||
<td>{ item.Price }</td>
|
||||
<td>{ item.PaymentMethod }</td>
|
||||
<td>{ item.PaymentStatus }</td>
|
||||
<td>–</td>
|
||||
<td>{ item.SubTotal }</td>
|
||||
<td class="flex gap-2">
|
||||
<button class="btn btn-sm btn-outline" hx-get={ item.ItemUrl } hx-target="closest tr" hx-swap="outerHTML">Edit</button>
|
||||
if item.PaymentStatus != "Completed" {
|
||||
<button class="btn btn-sm btn-success" hx-post={ item.ItemUrl } hx-target="closest tr" hx-swap="outerHTML">Paid</button>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
|
@ -23,7 +19,7 @@ templ LineItemForm(item *ItemViewModel) {
|
|||
<td><input class="input input-bordered input-sm w-full" value={ item.Item } name="item" form="edit-item"/></td>
|
||||
<td><input class="input input-bordered input-sm w-full" value={ item.Quantity } name="quantity" form="edit-item"/></td>
|
||||
<td><input class="input input-bordered input-sm w-full" value={ item.Price } name="price" form="edit-item"/></td>
|
||||
<td><input class="input input-bordered input-sm w-full" value={ item.PaymentMethod } name="paymentMethod" form="edit-item"/></td>
|
||||
<td>–</td>
|
||||
<td><input class="input input-bordered input-sm w-full" value={ item.PaymentStatus } name="PaymentStatus" form="edit-item"/></td>
|
||||
<td>{ item.SubTotal }</td>
|
||||
<td>
|
||||
|
|
|
|||
|
|
@ -68,82 +68,33 @@ func LineItem(item *ItemViewModel) templ.Component {
|
|||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</td><td>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</td><td>–</td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.PaymentMethod)
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.SubTotal)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 8, Col: 26}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 9, Col: 21}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</td><td>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</td><td class=\"flex gap-2\"><button class=\"btn btn-sm btn-outline\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(item.PaymentStatus)
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(item.ItemUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 9, Col: 26}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 11, Col: 63}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(item.SubTotal)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 10, Col: 21}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</td><td class=\"flex gap-2\"><button class=\"btn btn-sm btn-outline\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.ItemUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 12, Col: 63}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" hx-target=\"closest tr\" hx-swap=\"outerHTML\">Edit</button> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if item.PaymentStatus != "Completed" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<button class=\"btn btn-sm btn-success\" hx-post=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(item.ItemUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 14, Col: 65}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" hx-target=\"closest tr\" hx-swap=\"outerHTML\">Paid</button>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</td></tr>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" hx-target=\"closest tr\" hx-swap=\"outerHTML\">Edit</button></td></tr>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
|
@ -167,103 +118,90 @@ func LineItemForm(item *ItemViewModel) templ.Component {
|
|||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var10 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var10 == nil {
|
||||
templ_7745c5c3_Var10 = templ.NopComponent
|
||||
templ_7745c5c3_Var7 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var7 == nil {
|
||||
templ_7745c5c3_Var7 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<tr class=\"hover\"><form hx-put=\"")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<tr class=\"hover\"><form hx-put=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.ItemUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 18, Col: 29}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" id=\"edit-item\" hx-target=\"closest tr\" hx-swap=\"outerHTML\"><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(item.Item)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 19, Col: 76}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\" name=\"item\" form=\"edit-item\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(item.Quantity)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 20, Col: 80}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" name=\"quantity\" form=\"edit-item\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.ItemUrl)
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.Price)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 22, Col: 29}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 21, Col: 77}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\" id=\"edit-item\" hx-target=\"closest tr\" hx-swap=\"outerHTML\"><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\" name=\"price\" form=\"edit-item\"></td><td>–</td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(item.Item)
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(item.PaymentStatus)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 23, Col: 76}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 23, Col: 85}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\" name=\"item\" form=\"edit-item\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" name=\"PaymentStatus\" form=\"edit-item\"></td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 string
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(item.Quantity)
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(item.SubTotal)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 24, Col: 80}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 24, Col: 22}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\" name=\"quantity\" form=\"edit-item\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var14 string
|
||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(item.Price)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 25, Col: 77}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\" name=\"price\" form=\"edit-item\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var15 string
|
||||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(item.PaymentMethod)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 26, Col: 85}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" name=\"paymentMethod\" form=\"edit-item\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(item.PaymentStatus)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 27, Col: 85}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\" name=\"PaymentStatus\" form=\"edit-item\"></td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var17 string
|
||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(item.SubTotal)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/line_item.templ`, Line: 28, Col: 22}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</td><td><button class=\"btn btn-sm btn-primary\" type=\"submit\" form=\"edit-item\">Save</button></td></form></tr>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</td><td><button class=\"btn btn-sm btn-primary\" type=\"submit\" form=\"edit-item\">Save</button></td></form></tr>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
|
|
|||
46
internal/view/payment.templ
Normal file
46
internal/view/payment.templ
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package view
|
||||
|
||||
templ PaymentLine(payment *PaymentViewModel) {
|
||||
<tr class="hover">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>- { payment.Amount }</td>
|
||||
<td>{ payment.PaymentMethod }</td>
|
||||
<td></td>
|
||||
<td class="flex gap-2">
|
||||
<button class="btn btn-sm btn-outline" hx-get={ payment.PaymentUrl } hx-target="closest tr" hx-swap="outerHTML">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
templ PaymentForm(payment *PaymentViewModel) {
|
||||
<tr class="hover">
|
||||
<form hx-put={ payment.PaymentUrl } id="edit-payment" hx-target="closest tr" hx-swap="outerHTML">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<input
|
||||
class="input input-bordered input-sm w-full"
|
||||
type="number"
|
||||
inputmode="decimal"
|
||||
step="0.01"
|
||||
value={ payment.Amount }
|
||||
name="amount"
|
||||
form="edit-payment"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input input-bordered input-sm w-full"
|
||||
value={ payment.PaymentMethod }
|
||||
name="paymentMethod"
|
||||
form="edit-payment"
|
||||
/>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" type="submit" form="edit-payment">Save</button>
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
}
|
||||
147
internal/view/payment_templ.go
Normal file
147
internal/view/payment_templ.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.3.819
|
||||
package view
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
func PaymentLine(payment *PaymentViewModel) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<tr class=\"hover\"><td></td><td></td><td>- ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(payment.Amount)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/payment.templ`, Line: 7, Col: 24}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</td><td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(payment.PaymentMethod)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/payment.templ`, Line: 8, Col: 29}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</td><td></td><td class=\"flex gap-2\"><button class=\"btn btn-sm btn-outline\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(payment.PaymentUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/payment.templ`, Line: 11, Col: 69}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" hx-target=\"closest tr\" hx-swap=\"outerHTML\">Edit</button></td></tr>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func PaymentForm(payment *PaymentViewModel) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var5 == nil {
|
||||
templ_7745c5c3_Var5 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<tr class=\"hover\"><form hx-put=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(payment.PaymentUrl)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/payment.templ`, Line: 18, Col: 35}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" id=\"edit-payment\" hx-target=\"closest tr\" hx-swap=\"outerHTML\"><td></td><td></td><td><input class=\"input input-bordered input-sm w-full\" type=\"number\" inputmode=\"decimal\" step=\"0.01\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(payment.Amount)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/payment.templ`, Line: 27, Col: 27}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" name=\"amount\" form=\"edit-payment\"></td><td><input class=\"input input-bordered input-sm w-full\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(payment.PaymentMethod)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/view/payment.templ`, Line: 35, Col: 34}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" name=\"paymentMethod\" form=\"edit-payment\"></td><td></td><td><button class=\"btn btn-sm btn-primary\" type=\"submit\" form=\"edit-payment\">Save</button></td></form></tr>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
4
justfile
4
justfile
|
|
@ -48,3 +48,7 @@ format:
|
|||
# Lint the code
|
||||
lint:
|
||||
@golangci-lint run ./...
|
||||
|
||||
pdf:
|
||||
@go run cmd/pdf/main.go
|
||||
@open output.html
|
||||
|
|
|
|||
2
main.go
2
main.go
|
|
@ -53,7 +53,7 @@ func run(c context.Context, getEnv func(string) string) error {
|
|||
return fmt.Errorf("error connecting to the database %w", err)
|
||||
}
|
||||
|
||||
if err = database.Migrate(db, &booking.Booking{}, &booking.BookingRequest{}, &booking.Item{}); err != nil {
|
||||
if err = database.Migrate(db, &booking.Booking{}, &booking.BookingRequest{}, &booking.Item{}, &booking.Payment{}); err != nil {
|
||||
return fmt.Errorf("error migrating the database %w", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
24
scripts/init_payments_table.sh
Normal file
24
scripts/init_payments_table.sh
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
|
||||
DB_NAME="your_database_name"
|
||||
DB_USER="your_username"
|
||||
DB_HOST="your_host" # e.g., localhost or an IP address
|
||||
DB_PORT="your_port" # Default PostgreSQL port is 5432
|
||||
SQL_FILE="payment_migration.sql" # File containing the SQL script
|
||||
|
||||
# Check if the SQL file exists
|
||||
if [ ! -f "$SQL_FILE" ]; then
|
||||
echo "Error: SQL file '$SQL_FILE' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute the SQL script
|
||||
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f "$SQL_FILE"
|
||||
|
||||
# Check the result of the execution
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "SQL script executed successfully."
|
||||
else
|
||||
echo "Error: Failed to execute SQL script."
|
||||
exit 1
|
||||
fi
|
||||
10
scripts/payment_migration.sql
Normal file
10
scripts/payment_migration.sql
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
INSERT INTO payments (created_at, updated_at, deleted_at, booking_id, amount, payment_method)
|
||||
SELECT MIN(i.created_at) AS created_at, -- Use the earliest created_at timestamp for this payment
|
||||
MAX(i.updated_at) AS updated_at, -- Use the latest updated_at timestamp for this payment
|
||||
i.deleted_at, -- Use the deleted_at timestamp from items
|
||||
i.booking_id, -- The associated booking_id
|
||||
SUM(i.price * i.quantity) AS amount, -- Calculate total amount from price * quantity
|
||||
i.payment_method -- The payment method
|
||||
FROM items i
|
||||
WHERE i.deleted_at IS NULL -- Exclude soft-deleted items
|
||||
GROUP BY i.booking_id, i.payment_method, i.deleted_at;
|
||||
Loading…
Reference in a new issue