-
Matthieu Fesselier authored8aec7257
solid-invoicing.js 18.15 KiB
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);