import { SolidTemplateElement, Helpers, store } from 'https://cdn.skypack.dev/@startinblox/core@beta'; // const base_url = import.meta.url.replace(/\/[^\/]*$/, ''); const base_url = "https://cdn.skypack.dev/@startinblox/component-invoicing@1.1"; Helpers.importCSS(`${base_url}/css/main.css?min`); export class SolidInvoicing extends SolidTemplateElement { constructor() { super() } static get propsDefinition() { return { dataSrc: 'data-src', routerPrefix: 'router-prefix', uploadUrl: 'upload-url' } } connectedCallback() { this.addEventListener('click', (e) => { // display invoice details if(e.target && e.target.closest('[name="invoice-title"]')){ let invoice = e.target.closest('[name="invoice-title"]'); invoice.closest('solid-display').classList.toggle('invoice-visible') } // close dialog if(e.target && e.target.closest('.close-button')){ let routeName = e.target.closest('#clients-invoices') ? 'invoice-list' : 'freelance-invoice-list' window.dispatchEvent( new CustomEvent('requestNavigation', { detail: { route: routeName } }), ); } // access pdf invoice if (e.target && e.target.closest('.print')) { let printWindow = window.open('', 'PRINT', 'height=400,width=600'); printWindow.document.write(` <html> <head> <title></title> <link rel="stylesheet" href="${base_url}/css/main.css?min" media="screen"/> <link rel="stylesheet" href="${base_url}/css/main.css?min" media="print"/> <style>:root{--solid-invoicing-primary: #6259e5;--solid-invoicing-secondary: #ffb700; font-family: sans-serif}</style> </head> <body> ${document.getElementById('print').innerHTML} </body> </html> `); printWindow.document.close(); printWindow.focus(); setTimeout(() => { printWindow.print(); printWindow.close(); }, 1000); return true; } // Duplicate invoice if (e.target && e.target.closest('.duplication-button')) { const form = this.querySelector('.duplicate-form').component; form.getFormValue().then((value) => { let resources = value; resources["@context"] = form.context; const resourceId = this.querySelector('.new-customer-invoice-form')?.component.resourceId; if (!resourceId) { console.warn('No URI found to post a new invoice.'); return; } store.post(this.cleanInvoiceBeforeDuplicate(resources), resourceId).then(() => { this.dispatchEvent( new CustomEvent('requestNavigation', { bubbles: true, detail: { route: "invoice-list" }, }), ); }); }); } // Close duplicate dialog if (e.target && e.target.closest('.close-duplication-dialog')) { this.dispatchEvent( new CustomEvent('requestNavigation', { bubbles: true, detail: { route: "invoice-list" }, }), ); } }); } cleanInvoiceBeforeDuplicate(invoice) { delete invoice["@id"]; delete invoice.batches["@id"]; invoice.batches.forEach((batch, indexb) => { delete invoice.batches[indexb]["@id"]; batch.tasks.forEach((task, indext) => { delete invoice.batches[indexb].tasks[indext]["@id"]; }); }); return invoice; } template({dataSrc, routerPrefix, uploadUrl}) { let prefix = routerPrefix ? `route-prefix="${routerPrefix}"`: '' return ` <div id="solid-invoicing" class="solid-invoicing"> <!-- widgets ==================================== --> <solid-widget name="widget-money"> <template> <div>\${value?value:0} €</div> </template> </solid-widget> <solid-widget name="widget-tva-rate"> <template> <div>TVA \${value} %</div> </template> </solid-widget> <solid-widget name="widget-invoice-number"> <template> <div>N°\${value}</div> </template> </solid-widget> <solid-widget name="widget-batches"> <template> <solid-display class="batches-list" data-src="\${value}" fields="batch-header(title, amount), batch-body(tasks), batch-footer(ht-total(ht-label, htAmount))" value-amount="Montants" value-ht-label="Total HT" widget-tasks="widget-tasks" widget-htAmount="widget-money" ></solid-display> </template> </solid-widget> <solid-widget name="widget-tasks"> <template> <solid-display class="tasks-list" data-src="\${value}" fields="price-line(title, htAmount)" widget-htAmount="widget-money" ></solid-display> </template> </solid-widget> <solid-widget name="widget-form-batches"> <template> <solid-form data-src="\${value}" data-holder naked fields="batch-header(title), batch-body(tasks)" widget-tasks="widget-form-tasks" widget-title="solid-form-placeholder-text" label-title="Nom du lot" label-tasks="" multiple-tasks> </solid-form> </template> </solid-widget> <solid-widget name="widget-form-tasks"> <template> <solid-form data-src="\${value}" class="tasks-list" data-holder naked fields="price-line(title, htAmount)" widget-htAmount="solid-form-placeholder-text" widget-title="solid-form-placeholder-text" label-title="Tâche" label-htAmount="Montant" > </solid-form> </template> </solid-widget> <solid-widget name="widget-render-title"> <template> <div><strong>Facture N°\${value}</strong></div> </template> </solid-widget> <solid-widget name="widget-render-metadata"> <template> <div> <div class="invoice-render__fees"> <p>\${value}</p> <p>Intérêts de retard : 6% / an</p> <p>Une indemnité forfaitaire de 40€ sera exigée en sus de la pénalité de retard dès le premier jour de retard.</p> </div> <div class="invoice-render__rib"> <div><strong>Règlement par virement :</strong></div> <table> <tr> <td>BIC</td> <td>CMCIFR2A</td> </tr> <tr> <td>IBAN</td> <td>FR76 1027 8060 8200 0205 5370 166</td> </tr> </table> </div> </div> </template> </solid-widget> <solid-widget name="widget-embed-drive"> <template> <embed src="\${value}" width="560px" height="800px"/> </template> </solid-widget> <solid-widget name="close-button"> <template> <button class="close-button"> <img src="${base_url}/images/close-icon.svg" width="14" height="14" /> </button> </template> </solid-widget> <!-- /widgets ==================================== --> <!-- customer ==================================== --> <section id="clients-invoices" class="invoices-list invoices-list--clients"> <header> <h2>Factures pour le client</h2> <solid-router default-route="invoice-list" ${prefix}> <solid-route name="invoice-list"></solid-route> <solid-route name="add-invoice" class="button">Créer une nouvelle facture</solid-route> <solid-route name="show-invoice" use-id></solid-route> <solid-route name="edit-invoice" use-id></solid-route> <solid-route name="duplicate-invoice" use-id></solid-route> </solid-router> </header> <dialog data-view="add-invoice" class="invoice-form"> <close-button></close-button> <h3>Créer une nouvelle facture</h3> <solid-form class="new-customer-invoice-form" data-src="${dataSrc}" nested-field="customerInvoices" fields="first-line(title, identifier), second-line(state, invoicingDate), batches, last-line(tvaRate, additionalText)" label-title="Nom de la facture" label-identifier="Identifiant" label-state="Statut" label-invoicingDate="Date" label-tvaRate="TVA" label-additionalText="Mention Libre" label-batches="" widget-state="solid-form-dropdown-label" widget-batches="widget-form-batches" widget-invoicingDate="solid-form-date-label" widget-tvaRate="solid-form-number-label" enum-state="En attente = pending, Envoyé = sent, Payé = paid" class-state="custom-select" multiple-batches required-title required-identifier required-invoicingDate required-tvaRate next="invoice-list" ></solid-form> </dialog> <dialog data-view="edit-invoice" class="invoice-form"> <close-button></close-button> <h3>Modifier la facture</h3> <solid-form bind-resources fields="first-line(title, identifier), second-line(state, invoicingDate), batches, last-line(tvaRate, additionalText)" label-title="Nom de la facture" label-identifier="Identifiant" label-state="Statut" label-invoicingDate="Date" label-tvaRate="TVA" label-additionalText="Mention Libre" label-batches="" widget-state="solid-form-dropdown-label" widget-batches="widget-form-batches" widget-invoicingDate="solid-form-date-label" widget-tvaRate="solid-form-number-label" enum-state="En attente = pending, Envoyé = sent, Payé = paid" class-state="custom-select" multiple-batches next="invoice-list" required-title required-identifier required-invoicingDate required-tvaRate ></solid-form> </dialog> <dialog data-view="duplicate-invoice" class="invoice-form" id="duplicate"> <close-button></close-button> <h3>Dupliquer la facture</h3> <h4>Voulez-vous dupliquer cette facture ?</h4> <solid-form class="duplicate-form" bind-resources fields="first-line(title, identifier), second-line(state, invoicingDate), batches, last-line(tvaRate, additionalText)" widget-state="solid-form-dropdown-label" widget-batches="widget-form-batches" widget-invoicingDate="solid-form-date-label" widget-tvaRate="solid-form-number-label" enum-state="En attente = pending, Envoyé = sent, Payé = paid" class-state="custom-select" multiple-batches naked ></solid-form> <div class="popup-buttons"> <button class="popup-buttons__cancel close-duplication-dialog">Annuler</button> <button class="popup-buttons__validate duplication-button">Confirmer</button> </div> </dialog> <solid-display data-view="invoice-list" class="invoices-list__item" data-src="${dataSrc}" nested-field="customerInvoices" fields="invoice-title(invoice-main(invoice-header(title, identifier), invoice-footer(invoicingDate, htAmount)), invoice-aside(state)), invoice-hidden(actions(duplicate, edit, show), batches, invoice-totals(totals-header, ht-total(ht-label, htAmount), tva-total(tvaRate, tvaAmount), ttc-total(ttc-label, ttcAmount)))" value-totals-header="TOTAL DE LA FACTURE" value-ht-label="Total HT" value-ttc-label="Total TTC" widget-batches="widget-batches" widget-htAmount="widget-money" widget-tvaAmount="widget-money" widget-ttcAmount="widget-money" widget-tvaRate="widget-tva-rate" widget-identifier="widget-invoice-number" label-edit="Éditer" label-show="Aperçu client" label-duplicate="Dupliquer" action-edit="edit-invoice" action-show="show-invoice" action-duplicate="duplicate-invoice" order-desc="invoicingDate" ></solid-display> <!-- render --> <dialog class="invoice-dialog" data-view="show-invoice"> <close-button></close-button> <div id="print"> <div class="invoice-render"> <img src="${base_url}/images/happy-dev-logo.png" width="200" /> <solid-display class="display-invoice" bind-resources fields="invoice-head(invoice-header-left(identifier, invoicingDate), invoice-header-right(customer-infos(customer.name, customer.address))), batches, invoice-payment(additionalText, invoice-totals(ht-total(ht-label, htAmount), tva-total(tvaRate, tvaAmount), ttc-total(ttc-label, ttcAmount), tva-notice)), invoice-footer" value-ht-label="Total HT" value-ttc-label="Total TTC" value-tva-notice="TVA récupérable à l'encaissement" widget-identifier="widget-render-title" label-invoicingDate="Date: " widget-invoicingDate="solid-display-value-date-label" widget-additionalText="widget-render-metadata" widget-batches="widget-batches" widget-htAmount="widget-money" widget-tvaAmount="widget-money" widget-ttcAmount="widget-money" widget-tvaRate="widget-tva-rate" ></solid-display> <div class="invoice-render__footer"> <div class="invoice-render__hd-address"> <p><strong>Happy Dev</strong></p> <p>75 rue du Javelot</p> <p>75013 Paris</p> <p>contact@happy-dev.fr</p> </div> <div class="invoice-render__hd-legal"> <p><strong>SIRET : </strong>81314060500011</p> <p><strong>N° de TVA intracommunautaire : </strong>FR 61 813140605</p> <p>SAS à capital variable enregistrée au RCS de Paris</p> </div> </div> </div> </div> </br> <div class="popup-buttons"> <button class="popup-buttons__validate print">Imprimer</button> </div> </dialog> <!-- /render --> </section> <!-- /customer ==================================== --> <!-- freelance ==================================== --> <section id="freelances-invoices" class="invoices-list invoices-list--freelances"> <header> <h2>Factures des indépendants</h2> <solid-router default-route="freelance-invoice-list" ${prefix}> <solid-route name="freelance-invoice-list"></solid-route> <solid-route name="edit-freelance-invoice"></solid-route> <solid-route name="add-freelance-invoice" class="button">Importer une facture</solid-route> </solid-router> </header> <dialog data-view="add-freelance-invoice" class="invoice-form"> <close-button></close-button> <h3>Importer une facture</h3> <solid-form data-src="${dataSrc}" nested-field="freelancerInvoices" fields="first-line(freelanceFullname, identifier), second-line(htAmount, invoicingDate), third-line(state, uploadUrl)" label-freelanceFullname="Nom du prestataire" label-identifier="Numéro de la prestation" label-invoicingDate="Date de facturation" label-state="Statut" label-uploadUrl="Lien de la facture" label-htAmount="Montant HT" widget-invoicingDate="solid-form-date-label" widget-uploadUrl="solid-form-file-label" widget-htAmount="solid-form-number-label" widget-state="solid-form-dropdown-label" upload-url-uploadUrl="${uploadUrl}" enum-state="En attente = pending, Envoyé = sent, Payé = paid" class-state="custom-select" required-freelanceFullname required-identifier required-invoicingDate required-htAmount next="freelance-invoice-list" ></solid-form> </dialog> <dialog data-view="edit-freelance-invoice" class="invoice-form"> <close-button></close-button> <h3>Modifier une facture</h3> <solid-form bind-resources fields="first-line(freelanceFullname, identifier), second-line(invoicingDate, htAmount), third-line(state, uploadUrl)" label-freelanceFullname="Nom du prestataire" label-identifier="Numéro de la prestation" label-invoicingDate="Date de facturation" label-state="Statut" label-uploadUrl="Lien de la facture" label-htAmount="Montant HT" widget-invoicingDate="solid-form-date-label" widget-uploadUrl="solid-form-file-label" widget-htAmount="solid-form-number-label" widget-state="solid-form-dropdown-label" upload-url-uploadUrl="${uploadUrl}" enum-state="En attente = pending, Envoyé = sent, Payé = paid" class-state="custom-select" required-freelanceFullname required-identifier required-invoicingDate required-htAmount next="freelance-invoice-list" ></solid-form> </dialog> <solid-display data-view="freelance-invoice-list" data-src="${dataSrc}" nested-field="freelancerInvoices" fields="invoice-title(invoice-main(invoice-header(freelanceFullname, identifier), invoice-footer(invoicingDate, htAmount)), invoice-aside(state)), invoice-hidden(actions(edit), uploadUrl)" label-edit="Éditer" action-edit="edit-freelance-invoice" widget-htAmount="widget-money" widget-uploadUrl="widget-embed-drive" order-desc="invoicingDate" ></solid-display> </section> <!-- /freelance ==================================== --> </div> `; } } customElements.define('solid-invoicing', SolidInvoicing);