mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-06 02:36:49 +00:00
feat: manually create invoice
This commit is contained in:
parent
3568bc3e09
commit
7c3208c3b5
6 changed files with 657 additions and 114 deletions
|
|
@ -1,114 +1,287 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="main.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f9f9f9;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #007b8f;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.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="logo.png">
|
||||
<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/>
|
||||
<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>Voyageurs:</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/>
|
||||
<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="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/>
|
||||
<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 />
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-total space-between">
|
||||
<div></div>
|
||||
<div class="total">
|
||||
<div class="amount-due">
|
||||
Total
|
||||
</div>
|
||||
<div class="amount-due-total">
|
||||
{{ total }}
|
||||
</div>
|
||||
<div class="amount-due">Total</div>
|
||||
<div class="amount-due-total">{{ .Total }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
123
cmd/pdf/main.go
Normal file
123
cmd/pdf/main.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
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("assets/html/invoice.html")
|
||||
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: "VillaFleurie",
|
||||
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)
|
||||
}
|
||||
|
|
@ -71,6 +71,16 @@ 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
|
|||
292
output.html
Normal file
292
output.html
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f9f9f9;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #007b8f;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.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>VillaFleurie</b><br />
|
||||
4 rue Gerty Archimede<br />
|
||||
97190 Le Gosier<br />
|
||||
<b>Tel:</b> +590 690 44 15 30<br />
|
||||
<b>Mail:</b> location.villafleurie@gmail.com<br />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="billing-details space-between">
|
||||
<table class="info-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>VillaFleurie</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Tel:</strong></td>
|
||||
<td>+590 690 44 15 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Voyageurs:</strong></td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Plateforme:</strong></td>
|
||||
<td>Privée</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="info-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Nº de facture:</strong></td>
|
||||
<td>VFNI0332</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Du:</strong></td>
|
||||
<td>15 Janvier 2025</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Au:</strong></td>
|
||||
<td>15 Mars 2025</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Montant Total:</strong></td>
|
||||
<td>2065.00</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-gray rounded">
|
||||
|
||||
<tr class="item-row">
|
||||
<td class="text-break product_name">T2</td>
|
||||
<td>59</td>
|
||||
<td>35.00</td>
|
||||
<td class="align-right">2065.00</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="payment-summary space-between">
|
||||
<table class="summary-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Montant Total:</strong></td>
|
||||
<td>2065.00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Montant Payé:</strong></td>
|
||||
<td>1565.00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Solde Restant:</strong></td>
|
||||
<td>500.00</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Espèces</td>
|
||||
<td>500.00</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Cheque</td>
|
||||
<td>1565.00</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 />
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-total space-between">
|
||||
<div></div>
|
||||
<div class="total">
|
||||
<div class="amount-due">Total</div>
|
||||
<div class="amount-due-total">2065.00</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue