2025-05-23 13:50:57 +02:00
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
|
|
|
const form = document.getElementById("invoiceForm");
|
2025-05-23 15:42:32 +02:00
|
|
|
const invoiceItems = document.getElementById("invoiceItems");
|
|
|
|
|
const addItemButton = document.getElementById("addItemButton");
|
2025-05-31 17:41:17 +02:00
|
|
|
const clearFormButton = document.createElement("button");
|
|
|
|
|
const recipientNameInput = form.recipient_name;
|
|
|
|
|
const clientSuggestions = document.createElement("div");
|
2025-05-23 13:50:57 +02:00
|
|
|
|
2025-05-31 17:41:17 +02:00
|
|
|
// Configuration de la boîte de suggestions
|
|
|
|
|
clientSuggestions.className =
|
|
|
|
|
"client-suggestions absolute z-10 bg-white shadow-lg rounded-md w-full max-h-60 overflow-y-auto hidden";
|
|
|
|
|
recipientNameInput.parentNode.style.position = "relative";
|
|
|
|
|
recipientNameInput.parentNode.appendChild(clientSuggestions);
|
|
|
|
|
|
|
|
|
|
// Charger les clients précédents
|
|
|
|
|
let clientsData = JSON.parse(localStorage.getItem("clientsData") || "[]");
|
|
|
|
|
|
|
|
|
|
// Ajouter un bouton pour effacer le formulaire
|
|
|
|
|
clearFormButton.type = "button";
|
|
|
|
|
clearFormButton.className =
|
|
|
|
|
"bg-red-500 text-white px-4 py-2 rounded-md hover:bg-red-600 ml-4";
|
|
|
|
|
clearFormButton.textContent = "Effacer le formulaire";
|
|
|
|
|
clearFormButton.id = "clearFormButton";
|
|
|
|
|
|
|
|
|
|
// Ajouter le bouton après le bouton de soumission
|
|
|
|
|
const submitButton = form.querySelector('button[type="submit"]');
|
|
|
|
|
submitButton.parentNode.insertBefore(
|
|
|
|
|
clearFormButton,
|
|
|
|
|
submitButton.nextSibling
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Gestionnaire d'événement pour effacer le formulaire
|
|
|
|
|
clearFormButton.addEventListener("click", () => {
|
|
|
|
|
if (confirm("Êtes-vous sûr de vouloir effacer le formulaire ?")) {
|
|
|
|
|
localStorage.removeItem("invoiceData");
|
|
|
|
|
form.reset();
|
|
|
|
|
// Réinitialiser les lignes de facturation
|
|
|
|
|
invoiceItems.innerHTML = "";
|
|
|
|
|
addInvoiceItem();
|
|
|
|
|
showMessage("Formulaire effacé", "success");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Restaurer les données du formulaire depuis localStorage si elles existent
|
|
|
|
|
restoreFormData();
|
|
|
|
|
|
|
|
|
|
// Initialiser avec une ligne de facturation par défaut ou restaurer les lignes sauvegardées
|
|
|
|
|
if (invoiceItems.children.length === 0) {
|
|
|
|
|
addInvoiceItem();
|
|
|
|
|
}
|
2025-05-23 13:50:57 +02:00
|
|
|
|
2025-05-23 15:42:32 +02:00
|
|
|
// Ajouter une ligne de facturation lorsqu'on clique sur le bouton
|
|
|
|
|
addItemButton.addEventListener("click", addInvoiceItem);
|
2025-05-23 13:50:57 +02:00
|
|
|
|
2025-05-31 17:41:17 +02:00
|
|
|
// Sauvegarder les données pendant la saisie (debounced)
|
|
|
|
|
let saveTimeout;
|
|
|
|
|
form.addEventListener("input", () => {
|
|
|
|
|
clearTimeout(saveTimeout);
|
|
|
|
|
saveTimeout = setTimeout(() => {
|
|
|
|
|
saveFormData();
|
|
|
|
|
}, 500); // Attendre 500ms après la dernière saisie
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Gérer l'auto-complétion des clients
|
|
|
|
|
recipientNameInput.addEventListener("input", function () {
|
|
|
|
|
const query = this.value.toLowerCase();
|
|
|
|
|
if (query.length < 2) {
|
|
|
|
|
clientSuggestions.classList.add("hidden");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Filtrer les clients qui correspondent à la recherche
|
|
|
|
|
const matches = clientsData.filter((client) =>
|
|
|
|
|
client.name.toLowerCase().includes(query)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (matches.length === 0) {
|
|
|
|
|
clientSuggestions.classList.add("hidden");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Afficher les suggestions
|
|
|
|
|
clientSuggestions.innerHTML = matches
|
|
|
|
|
.map(
|
|
|
|
|
(client) => `
|
|
|
|
|
<div class="client-suggestion p-2 hover:bg-gray-100 cursor-pointer" data-client-id="${client.id}">
|
|
|
|
|
<div class="font-medium">${client.name}</div>
|
|
|
|
|
<div class="text-sm text-gray-600">${client.address}, ${client.postal_code} ${client.town}</div>
|
|
|
|
|
</div>
|
|
|
|
|
`
|
|
|
|
|
)
|
|
|
|
|
.join("");
|
|
|
|
|
|
|
|
|
|
clientSuggestions.classList.remove("hidden");
|
|
|
|
|
|
|
|
|
|
// Ajouter des gestionnaires d'événements pour les suggestions
|
|
|
|
|
document.querySelectorAll(".client-suggestion").forEach((suggestion) => {
|
|
|
|
|
suggestion.addEventListener("click", function () {
|
|
|
|
|
const clientId = this.getAttribute("data-client-id");
|
|
|
|
|
const client = clientsData.find((c) => c.id === clientId);
|
|
|
|
|
if (client) {
|
|
|
|
|
fillClientData(client);
|
|
|
|
|
clientSuggestions.classList.add("hidden");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Masquer les suggestions lorsqu'on clique ailleurs
|
|
|
|
|
document.addEventListener("click", function (e) {
|
|
|
|
|
if (
|
|
|
|
|
!recipientNameInput.contains(e.target) &&
|
|
|
|
|
!clientSuggestions.contains(e.target)
|
|
|
|
|
) {
|
|
|
|
|
clientSuggestions.classList.add("hidden");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Fonction pour remplir les données du client
|
|
|
|
|
function fillClientData(client) {
|
|
|
|
|
form.recipient_name.value = client.name;
|
|
|
|
|
form.recipient_address.value = client.address;
|
|
|
|
|
form.recipient_postal_code.value = client.postal_code;
|
|
|
|
|
form.recipient_town.value = client.town;
|
|
|
|
|
form.recipient_country.value = client.country;
|
|
|
|
|
if (client.vat_number) {
|
|
|
|
|
form.recipient_vat_number.value = client.vat_number;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour sauvegarder un nouveau client
|
|
|
|
|
function saveClient() {
|
|
|
|
|
// Ne sauvegarder que si les champs essentiels sont remplis
|
|
|
|
|
if (
|
|
|
|
|
!form.recipient_name.value ||
|
|
|
|
|
!form.recipient_address.value ||
|
|
|
|
|
!form.recipient_postal_code.value ||
|
|
|
|
|
!form.recipient_town.value
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const clientData = {
|
|
|
|
|
id: Date.now().toString(), // ID unique
|
|
|
|
|
name: form.recipient_name.value,
|
|
|
|
|
address: form.recipient_address.value,
|
|
|
|
|
postal_code: form.recipient_postal_code.value,
|
|
|
|
|
town: form.recipient_town.value,
|
|
|
|
|
country: form.recipient_country.value,
|
|
|
|
|
vat_number: form.recipient_vat_number.value || null,
|
|
|
|
|
lastUsed: new Date().toISOString(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Vérifier si le client existe déjà (par nom)
|
|
|
|
|
const existingClientIndex = clientsData.findIndex(
|
|
|
|
|
(client) => client.name.toLowerCase() === clientData.name.toLowerCase()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (existingClientIndex !== -1) {
|
|
|
|
|
// Mettre à jour le client existant
|
|
|
|
|
clientsData[existingClientIndex] = {
|
|
|
|
|
...clientsData[existingClientIndex],
|
|
|
|
|
...clientData,
|
|
|
|
|
id: clientsData[existingClientIndex].id, // Conserver l'ID d'origine
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
// Ajouter le nouveau client
|
|
|
|
|
clientsData.push(clientData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Trier par date d'utilisation (plus récent en premier)
|
|
|
|
|
clientsData.sort((a, b) => new Date(b.lastUsed) - new Date(a.lastUsed));
|
|
|
|
|
|
|
|
|
|
// Limiter à 50 clients
|
|
|
|
|
clientsData = clientsData.slice(0, 50);
|
|
|
|
|
|
|
|
|
|
// Sauvegarder dans localStorage
|
|
|
|
|
localStorage.setItem("clientsData", JSON.stringify(clientsData));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour sauvegarder les données du formulaire
|
|
|
|
|
function saveFormData() {
|
|
|
|
|
const formData = {
|
|
|
|
|
language: form.language.value,
|
|
|
|
|
invoice_number: form.invoice_number.value,
|
|
|
|
|
amount: form.amount.value,
|
|
|
|
|
currency: form.currency.value,
|
|
|
|
|
recipient_name: form.recipient_name.value,
|
|
|
|
|
recipient_address: form.recipient_address.value,
|
|
|
|
|
recipient_postal_code: form.recipient_postal_code.value,
|
|
|
|
|
recipient_town: form.recipient_town.value,
|
|
|
|
|
recipient_country: form.recipient_country.value,
|
|
|
|
|
recipient_vat_number: form.recipient_vat_number.value || null,
|
|
|
|
|
items: collectInvoiceItems(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
localStorage.setItem("invoiceData", JSON.stringify(formData));
|
|
|
|
|
|
|
|
|
|
// Sauvegarder aussi dans l'historique des factures récentes
|
|
|
|
|
saveToRecentInvoices(formData);
|
|
|
|
|
|
|
|
|
|
// Sauvegarder les informations du client si tous les champs sont remplis
|
|
|
|
|
saveClient();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour sauvegarder dans l'historique des factures récentes
|
|
|
|
|
function saveToRecentInvoices(formData) {
|
|
|
|
|
if (!formData.recipient_name) return; // Ne pas sauvegarder si pas de nom de destinataire
|
|
|
|
|
|
|
|
|
|
let recentInvoices = JSON.parse(
|
|
|
|
|
localStorage.getItem("recentInvoices") || "[]"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Créer un identifiant unique basé sur le nom et la date
|
|
|
|
|
const now = new Date();
|
|
|
|
|
const id = `${formData.recipient_name}_${now.toISOString()}`;
|
|
|
|
|
|
|
|
|
|
// Ajouter la facture actuelle à l'historique avec un timestamp
|
|
|
|
|
const invoiceWithMeta = {
|
|
|
|
|
...formData,
|
|
|
|
|
id,
|
|
|
|
|
lastEdited: now.toISOString(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Vérifier si une facture similaire existe déjà (même destinataire)
|
|
|
|
|
const existingIndex = recentInvoices.findIndex(
|
|
|
|
|
(invoice) => invoice.recipient_name === formData.recipient_name
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (existingIndex !== -1) {
|
|
|
|
|
// Remplacer la facture existante
|
|
|
|
|
recentInvoices[existingIndex] = invoiceWithMeta;
|
|
|
|
|
} else {
|
|
|
|
|
// Ajouter la nouvelle facture
|
|
|
|
|
recentInvoices.unshift(invoiceWithMeta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Limiter à 10 factures récentes
|
|
|
|
|
recentInvoices = recentInvoices.slice(0, 10);
|
|
|
|
|
|
|
|
|
|
localStorage.setItem("recentInvoices", JSON.stringify(recentInvoices));
|
|
|
|
|
|
|
|
|
|
// Mettre à jour la liste des factures récentes dans l'interface
|
|
|
|
|
updateRecentInvoicesList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour mettre à jour la liste des factures récentes dans l'interface
|
|
|
|
|
function updateRecentInvoicesList() {
|
|
|
|
|
const recentInvoicesContainer = document.getElementById("recentInvoices");
|
|
|
|
|
if (!recentInvoicesContainer) {
|
|
|
|
|
// Créer le conteneur s'il n'existe pas
|
|
|
|
|
const container = document.createElement("div");
|
|
|
|
|
container.id = "recentInvoices";
|
|
|
|
|
container.className = "mt-8 bg-white rounded-lg shadow p-4";
|
|
|
|
|
container.innerHTML = `
|
|
|
|
|
<h3 class="text-lg font-semibold mb-4">Factures récentes</h3>
|
|
|
|
|
<div id="recentInvoicesList" class="space-y-2"></div>
|
|
|
|
|
`;
|
|
|
|
|
form.parentNode.insertBefore(container, form.nextSibling);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const recentInvoicesList = document.getElementById("recentInvoicesList");
|
|
|
|
|
const recentInvoices = JSON.parse(
|
|
|
|
|
localStorage.getItem("recentInvoices") || "[]"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (recentInvoices.length === 0) {
|
|
|
|
|
recentInvoicesList.innerHTML = `<p class="text-gray-500">Aucune facture récente</p>`;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
recentInvoicesList.innerHTML = recentInvoices
|
|
|
|
|
.map(
|
|
|
|
|
(invoice) => `
|
|
|
|
|
<div class="flex justify-between items-center p-2 border-b">
|
|
|
|
|
<div>
|
|
|
|
|
<span class="font-medium">${invoice.recipient_name}</span>
|
|
|
|
|
<span class="text-sm text-gray-500 ml-2">${invoice.amount} ${
|
|
|
|
|
invoice.currency
|
|
|
|
|
}</span>
|
|
|
|
|
<span class="text-xs text-gray-400 ml-2">${new Date(
|
|
|
|
|
invoice.lastEdited
|
|
|
|
|
).toLocaleDateString()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="load-invoice bg-blue-500 text-white px-2 py-1 rounded text-sm" data-id="${
|
|
|
|
|
invoice.id
|
|
|
|
|
}">
|
|
|
|
|
Charger
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
`
|
|
|
|
|
)
|
|
|
|
|
.join("");
|
|
|
|
|
|
|
|
|
|
// Ajouter les gestionnaires d'événements pour charger les factures
|
|
|
|
|
document.querySelectorAll(".load-invoice").forEach((button) => {
|
|
|
|
|
button.addEventListener("click", (e) => {
|
|
|
|
|
const id = e.target.getAttribute("data-id");
|
|
|
|
|
const invoice = recentInvoices.find((inv) => inv.id === id);
|
|
|
|
|
if (invoice) {
|
|
|
|
|
if (
|
|
|
|
|
confirm(
|
|
|
|
|
"Charger cette facture ? Les données actuelles seront remplacées."
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
loadInvoice(invoice);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour charger une facture depuis l'historique
|
|
|
|
|
function loadInvoice(invoice) {
|
|
|
|
|
// Remplir le formulaire avec les données de la facture
|
|
|
|
|
form.language.value = invoice.language || "";
|
|
|
|
|
form.invoice_number.value = invoice.invoice_number || "";
|
|
|
|
|
form.amount.value = invoice.amount || "";
|
|
|
|
|
form.currency.value = invoice.currency || "EUR";
|
|
|
|
|
form.recipient_name.value = invoice.recipient_name || "";
|
|
|
|
|
form.recipient_address.value = invoice.recipient_address || "";
|
|
|
|
|
form.recipient_postal_code.value = invoice.recipient_postal_code || "";
|
|
|
|
|
form.recipient_town.value = invoice.recipient_town || "";
|
|
|
|
|
form.recipient_country.value = invoice.recipient_country || "";
|
|
|
|
|
form.recipient_vat_number.value = invoice.recipient_vat_number || "";
|
|
|
|
|
|
|
|
|
|
// Restaurer les lignes de facturation
|
|
|
|
|
invoiceItems.innerHTML = "";
|
|
|
|
|
if (invoice.items && invoice.items.length > 0) {
|
|
|
|
|
invoice.items.forEach((item) => {
|
|
|
|
|
addInvoiceItem(item.description, item.amount);
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
addInvoiceItem();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sauvegarder dans le localStorage
|
|
|
|
|
localStorage.setItem("invoiceData", JSON.stringify(invoice));
|
|
|
|
|
|
|
|
|
|
showMessage("Facture chargée avec succès", "success");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour restaurer les données du formulaire depuis localStorage
|
|
|
|
|
function restoreFormData() {
|
|
|
|
|
const savedData = localStorage.getItem("invoiceData");
|
|
|
|
|
if (!savedData) {
|
|
|
|
|
// Mettre à jour la liste des factures récentes même s'il n'y a pas de données sauvegardées
|
|
|
|
|
updateRecentInvoicesList();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const formData = JSON.parse(savedData);
|
|
|
|
|
|
|
|
|
|
// Remplir les champs du formulaire
|
|
|
|
|
if (formData.language) form.language.value = formData.language;
|
|
|
|
|
if (formData.invoice_number)
|
|
|
|
|
form.invoice_number.value = formData.invoice_number;
|
|
|
|
|
if (formData.amount) form.amount.value = formData.amount;
|
|
|
|
|
if (formData.currency) form.currency.value = formData.currency;
|
|
|
|
|
if (formData.recipient_name)
|
|
|
|
|
form.recipient_name.value = formData.recipient_name;
|
|
|
|
|
if (formData.recipient_address)
|
|
|
|
|
form.recipient_address.value = formData.recipient_address;
|
|
|
|
|
if (formData.recipient_postal_code)
|
|
|
|
|
form.recipient_postal_code.value = formData.recipient_postal_code;
|
|
|
|
|
if (formData.recipient_town)
|
|
|
|
|
form.recipient_town.value = formData.recipient_town;
|
|
|
|
|
if (formData.recipient_country)
|
|
|
|
|
form.recipient_country.value = formData.recipient_country;
|
|
|
|
|
if (formData.recipient_vat_number)
|
|
|
|
|
form.recipient_vat_number.value = formData.recipient_vat_number;
|
|
|
|
|
|
|
|
|
|
// Restaurer les lignes de facturation
|
|
|
|
|
if (formData.items && formData.items.length > 0) {
|
|
|
|
|
// Vider les lignes existantes
|
|
|
|
|
invoiceItems.innerHTML = "";
|
|
|
|
|
|
|
|
|
|
// Ajouter chaque ligne sauvegardée
|
|
|
|
|
formData.items.forEach((item) => {
|
|
|
|
|
addInvoiceItem(item.description, item.amount);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mettre à jour la liste des factures récentes
|
|
|
|
|
updateRecentInvoicesList();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Erreur lors de la restauration des données:", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 15:42:32 +02:00
|
|
|
// Fonction pour créer une nouvelle ligne de facturation
|
|
|
|
|
function addInvoiceItem(description = "", amount = "") {
|
|
|
|
|
const itemId = Date.now(); // ID unique pour l'élément
|
|
|
|
|
const itemDiv = document.createElement("div");
|
|
|
|
|
itemDiv.className = "invoice-item grid grid-cols-5 gap-2";
|
|
|
|
|
itemDiv.dataset.id = itemId;
|
|
|
|
|
|
|
|
|
|
itemDiv.innerHTML = `
|
|
|
|
|
<div class="col-span-3">
|
|
|
|
|
<input type="text" name="item_description_${itemId}" placeholder="Description" value="${description}"
|
|
|
|
|
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-span-1">
|
|
|
|
|
<input type="number" step="0.01" name="item_amount_${itemId}" placeholder="Montant" value="${amount}"
|
|
|
|
|
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-span-1">
|
|
|
|
|
<button type="button" class="delete-item text-red-500 hover:text-red-700" data-id="${itemId}">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
// Ajouter un gestionnaire d'événements pour supprimer la ligne
|
|
|
|
|
const deleteButton = itemDiv.querySelector(".delete-item");
|
|
|
|
|
deleteButton.addEventListener("click", function () {
|
|
|
|
|
const id = this.getAttribute("data-id");
|
|
|
|
|
deleteInvoiceItem(id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
invoiceItems.appendChild(itemDiv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour supprimer une ligne de facturation
|
|
|
|
|
function deleteInvoiceItem(id) {
|
|
|
|
|
const item = document.querySelector(`.invoice-item[data-id="${id}"]`);
|
|
|
|
|
if (item) {
|
|
|
|
|
item.remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// S'assurer qu'il reste au moins une ligne
|
|
|
|
|
if (invoiceItems.children.length === 0) {
|
|
|
|
|
addInvoiceItem();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour collecter toutes les lignes de facturation
|
|
|
|
|
function collectInvoiceItems() {
|
|
|
|
|
const items = [];
|
|
|
|
|
document.querySelectorAll(".invoice-item").forEach((item) => {
|
|
|
|
|
const id = item.dataset.id;
|
|
|
|
|
const description = item.querySelector(
|
|
|
|
|
`[name="item_description_${id}"]`
|
|
|
|
|
).value;
|
|
|
|
|
const amount = item.querySelector(`[name="item_amount_${id}"]`).value;
|
|
|
|
|
|
|
|
|
|
if (description && amount) {
|
|
|
|
|
items.push({ description, amount });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return items;
|
2025-05-23 13:50:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fonction pour valider le formulaire
|
2025-05-23 15:42:32 +02:00
|
|
|
function validateForm() {
|
2025-05-23 13:50:57 +02:00
|
|
|
const requiredFields = [
|
2025-05-23 15:42:32 +02:00
|
|
|
form.invoice_number,
|
|
|
|
|
form.amount,
|
|
|
|
|
form.recipient_name,
|
|
|
|
|
form.recipient_address,
|
|
|
|
|
form.recipient_postal_code,
|
|
|
|
|
form.recipient_town,
|
|
|
|
|
form.recipient_country,
|
2025-05-23 13:50:57 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const field of requiredFields) {
|
2025-05-23 15:42:32 +02:00
|
|
|
if (!field.value) {
|
|
|
|
|
showMessage(`Le champ ${field.name} est requis`, "error");
|
|
|
|
|
field.focus();
|
2025-05-23 13:50:57 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 15:42:32 +02:00
|
|
|
const items = collectInvoiceItems();
|
|
|
|
|
if (items.length === 0) {
|
|
|
|
|
showMessage("Ajoutez au moins une ligne de facturation", "error");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 13:50:57 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 15:42:32 +02:00
|
|
|
// Fonction pour afficher les messages
|
|
|
|
|
function showMessage(message, type = "success") {
|
|
|
|
|
const messageDiv = document.createElement("div");
|
|
|
|
|
messageDiv.className = `${type}-message fixed top-4 right-4 p-4 rounded-md shadow-lg ${
|
|
|
|
|
type === "success" ? "bg-green-500" : "bg-red-500"
|
|
|
|
|
} text-white`;
|
|
|
|
|
messageDiv.textContent = message;
|
|
|
|
|
document.body.appendChild(messageDiv);
|
|
|
|
|
|
|
|
|
|
// Afficher le message
|
|
|
|
|
setTimeout(() => messageDiv.classList.add("opacity-100"), 100);
|
|
|
|
|
|
|
|
|
|
// Supprimer le message après 3 secondes
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
messageDiv.classList.remove("opacity-100");
|
|
|
|
|
setTimeout(() => messageDiv.remove(), 300);
|
|
|
|
|
}, 3000);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 13:50:57 +02:00
|
|
|
// Gestionnaire de soumission du formulaire
|
|
|
|
|
form.addEventListener("submit", function (e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
2025-05-23 15:42:32 +02:00
|
|
|
if (!validateForm()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 13:50:57 +02:00
|
|
|
// Récupérer les données du formulaire
|
|
|
|
|
const formData = {
|
|
|
|
|
language: form.language.value,
|
|
|
|
|
invoice_number: form.invoice_number.value,
|
2025-05-23 15:42:32 +02:00
|
|
|
amount: form.amount.value, // Montant total
|
2025-05-23 13:50:57 +02:00
|
|
|
currency: form.currency.value,
|
|
|
|
|
recipient_name: form.recipient_name.value,
|
|
|
|
|
recipient_address: form.recipient_address.value,
|
|
|
|
|
recipient_postal_code: form.recipient_postal_code.value,
|
|
|
|
|
recipient_town: form.recipient_town.value,
|
|
|
|
|
recipient_country: form.recipient_country.value,
|
|
|
|
|
recipient_vat_number: form.recipient_vat_number.value || null,
|
2025-05-23 15:42:32 +02:00
|
|
|
items: collectInvoiceItems(), // Ajouter les lignes de facturation
|
2025-05-23 13:50:57 +02:00
|
|
|
};
|
|
|
|
|
|
2025-05-31 17:41:17 +02:00
|
|
|
// Sauvegarder les données du formulaire dans localStorage
|
|
|
|
|
localStorage.setItem("invoiceData", JSON.stringify(formData));
|
|
|
|
|
|
|
|
|
|
// Sauvegarder les informations du client
|
|
|
|
|
saveClient();
|
|
|
|
|
|
2025-05-23 13:50:57 +02:00
|
|
|
// Rediriger vers la page de prévisualisation avec les données
|
|
|
|
|
const queryString = encodeURIComponent(JSON.stringify(formData));
|
|
|
|
|
window.location.href = `/preview?data=${queryString}`;
|
|
|
|
|
});
|
|
|
|
|
});
|