Newer
Older
import { SolidTemplateElement, Helpers, store } from 'https://cdn.skypack.dev/@startinblox/core@0.17';
import { openInvoiceWindow, cleanInvoiceBeforeDuplicate } from './utils/functions.js';
// const base_url = import.meta.url.replace(/\/[^\/]*$/, '');
const base_url = "https://cdn.skypack.dev/@startinblox/component-invoicing@1.3";
Helpers.importCSS(`${base_url}/css/main.css?min`);
export class SolidInvoicing extends SolidTemplateElement {
constructor() {
if (window.hubl) {
this.localize = (key) => {
return window.hubl.intl.t("invoices." + key) || this.strings[key] || key;
}
}
// populate callbacks
this.customerPopulateCallback = null;
this.customerElement = null;
this.freelancerPopulateCallback = null;
this.freelancerElement = null;
}
static get propsDefinition() {
return {
dataSrc: 'data-src',
uploadUrl: 'upload-dir',
logo: 'logo-dir'
}
}
connectedCallback() {
this.addEventListener('click', (e) => {
if(e.target && e.target.closest('.show-list')){
let invoice = e.target.closest('.invoices-list');
invoice.classList.toggle('invoices-list-visible')
}
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')
}
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 } }),
);
}
if (e.target && e.target.closest('.print')) {
const printWindow = openInvoiceWindow('print', base_url);
setTimeout(() => {
printWindow.print();
printWindow.close();
if (e.target && e.target.closest('.download')) {
openInvoiceWindow('download', base_url);
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(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" },
}),
);
}
// Reactivity: subscribe batches to invoices changes
this.addEventListener('widgetRendered', (e) => {
if (e.target.tagName === 'WIDGET-TASKS') {
const batchDisplay = e.target.closest('solid-display');
if (!batchDisplay) return;
const invoiceSrc = batchDisplay.closest('.invoice-details')?.dataset.src;
if (!invoiceSrc) return;
store.subscribeResourceTo(batchDisplay.dataset.src, invoiceSrc);
}
});
/**
* Get total amount of a list of invoices
* @param {Element} displayElement - solid-display of the invoices
* @param {boolean} includeBusinessProvision - calculate business provision
* @returns {{amount: number, businessProvisionAmount: number, businessProvision: number}} amount informations of invoices
async getTotalAmount(displayElement, includeBusinessProvision = false) {
return new Promise(async (resolve, reject) => {
if (!displayElement) reject('Element not found');
const invoices = displayElement.component.resource;
if (!invoices) resolve(0);
const amount = await Promise.all(invoices['ldp:contains'].map(invoice => invoice.htAmount))
.then(a => a.reduce((acc, current) => parseFloat(acc) + (parseFloat(current) || 0), 0));
let businessProvisionAmount = null;
let businessProvision = null;
if (includeBusinessProvision) {
businessProvision = await this.getBusinessProvision(invoices['ldp:contains'][0]);
businessProvisionAmount = amount * (businessProvision / 100)
}
resolve({ amount, businessProvisionAmount, businessProvision })
/**
* Calculate the business provision of an invoice
* @param {object} invoice - resource
* @returns {Promise<number>} business provision
*/
async getBusinessProvision(invoice) {
if (!invoice) return 0;
const businessProvidersList = await invoice['project.businessprovider'];
let businessProvision = 0;
if (businessProvidersList) {
for (const businessProvider of businessProvidersList['ldp:contains']) {
businessProvision += await businessProvider['fee'];
}
}
return businessProvision;
}
/**
* Generate recap and show values
*/
generateRecap() {
const customerInvoices = this.querySelector('#customer-invoices')
const freelancerInvoices = this.querySelector('#freelancer-invoices')
const recapFreelancerInvoices = this.querySelector('#recap-freelancer-invoices')
const recapCustomerInvoices = this.querySelector('#recap-customer-invoices')
const recapFees = this.querySelector('#recap-fees')
const recapBusinessProvision = this.querySelector('#recap-business-provision')
const infoBusinessProvision = this.querySelector('#info-business-provision')
const recapTotal = this.querySelector('#recap-total')
Promise.all([this.getTotalAmount(customerInvoices, true), this.getTotalAmount(freelancerInvoices, false)])
.then(([customerTotal, freelancerTotal]) => {
if (customerTotal) { // customer amounts
recapCustomerInvoices.innerText = customerTotal.amount.toFixed(2);
recapFees.innerText = (customerTotal.amount * 0.05).toFixed(2);
recapBusinessProvision.innerText = (customerTotal.businessProvisionAmount).toFixed(2);
infoBusinessProvision.innerText = `${customerTotal.businessProvision}%`
if (freelancerTotal) { // freelancer amounts
recapFreelancerInvoices.innerText = freelancerTotal.amount.toFixed(2);
const recapAmount = (customerTotal.amount || 0) - (freelancerTotal.amount || 0);
recapTotal.innerText = recapAmount.toFixed(2);
if (recapAmount > 0) {
recapTotal.classList.remove('icon-dislike');
recapTotal.classList.add('icon-like');
} else {
recapTotal.classList.remove('icon-like');
recapTotal.classList.add('icon-dislike');
.catch(() => {
console.warn('An error occured while generating the recap');
})
/**
* Attach populate listeners on invoices displays
*/
attachPopulateListeners() {
this.detachPopulateListeners(); // to prevent memory leak, detach listeners
this.customerElement = this.querySelector('#customer-invoices')
this.freelancerElement = this.querySelector('#freelancer-invoices')
// Customer callback
this.customerPopulateCallback = () => { // if freelancer populated, generate recap
if (this.freelancerElement && this.freelancerElement.component.resource) this.generateRecap();
}
// Freelancer callback
this.freelancerPopulateCallback = () => { // if customer populated, generate recap
if (this.customerElement && this.customerElement.component.resource) this.generateRecap();
}
// Attach callbacks to events
this.customerElement.addEventListener('populate', this.customerPopulateCallback)
this.freelancerElement.addEventListener('populate', this.freelancerPopulateCallback)
}
/**
* Detach listeners
*/
detachPopulateListeners() {
if (this.customerElement && this.customerPopulateCallback) {
this.customerElement.removeEventListener('populate', this.customerPopulateCallback);
}
if (this.freelancerElement && this.freelancerPopulateCallback) {
this.freelancerElement.removeEventListener('populate', this.freelancerPopulateCallback);
}
}
/**
* Sent after the rendering of the component
*/
template({dataSrc, routerPrefix, uploadUrl, logo}) {
let prefix = routerPrefix ? `route-prefix="${routerPrefix}"`: ''
return `
<div id="solid-invoicing" class="solid-invoicing segment full padding-large sm-padding-xsmall sm-padding-top-xlarge">
<!-- widgets ==================================== -->
<solid-widget name="widget-money">
<template>
</template>
</solid-widget>
<solid-widget name="widget-tva-rate">
<template>
<div>${this.localize('widget.tva_rate')} \${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"
fields="batch-header(title, amount),
batch-body(tasks),
batch-footer(ht-total(ht-label, htAmount))"
value-amount="${this.localize('value.amount')}"
value-ht-label="${this.localize('label.value_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"
widget-title="solid-display-div-multiline"
widget-htAmount="widget-money"
></solid-display>
</template>
</solid-widget>
<solid-widget name="widget-form-batches">
<template>
<solid-form
data-holder
naked
fields="batch-header(title), batch-body(tasks)"
widget-tasks="widget-form-tasks"
widget-title="solid-form-placeholder-text"
label-title="${this.localize('label.title_batch')}"
multiple-tasks
required-title
> </solid-form>
</template>
</solid-widget>
<solid-widget name="widget-form-tasks">
<template>
<solid-form
class="tasks-list"
data-holder
naked
fields="price-line(title, htAmount)"
widget-htAmount="solid-form-placeholder-number"
widget-title="solid-form-placeholder-textarea"
label-title="${this.localize('label.title_task')}"
label-htAmount="${this.localize('label.ht_amount')}"
required-title
required-htAmount
</template>
</solid-widget>
<solid-widget name="widget-render-title">
<template>
<div><strong>${this.localize('widget.render_title')}\${value}</strong></div>
</template>
</solid-widget>
<solid-widget name="widget-render-metadata">
<template>
<div>
<div class="invoice-render__fees">
<p>${this.localize('widget.render_metadata_late')}</p>
<p>${this.localize('widget.render_metadata_indemnity')}</p>
</div>
<div class="invoice-render__rib">
<div><strong>${this.localize('widget.render_metadata_bank_transfert')}</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="widget-nomenclature">
<template>
<div>
<b>${this.localize('title.nomenclature')}</b> : ${this.localize('text.nomenclature')}
</div>
</template>
</solid-widget>
<solid-widget name="widget-state">
<template>
\${value == 'edited' ? '<div class="sm-full button text-xsmall text-bold text-center reversed color-secondary bordered">${this.localize('option.edited')}</div>' : '' }
\${value == 'pending' ? '<div class="sm-full button text-xsmall text-bold text-center color-secondary bordered">${this.localize('option.pending')}</div>' : '' }
\${value == 'sent' ? '<div class="sm-full button text-xsmall text-bold text-center color-third bordered">${this.localize('option.sent')}</div>' : '' }
\${value == 'paid' ? '<div class="sm-full button text-xsmall text-bold text-center reversed color-third bordered">${this.localize('option.paid')}</div>' : '' }
\${value == 'late' ? '<div class="sm-full button text-xsmall text-bold text-center reversed color-primary bordered">${this.localize('option.late')}</div>' : '' }
</template>
</solid-widget>
<solid-widget name="close-button">
<template>
<button class="close-button icon icon-close">
</button>
</template>
</solid-widget>
<!-- /widgets ==================================== -->
<header class="segment full main-menu">
<solid-router class="segment full margin-bottom-medium" default-route="invoices-summary" ${prefix}>
<solid-route name="invoices-summary" class="segment half padding-right-medium">
<div class="segment full border-bottom padding-bottom-small text-uppercase text-large">${this.localize('header.summary')}</div>
<solid-route name="invoices-details" class="segment half padding-left-medium">
<div class="segment full border-bottom padding-bottom-small text-uppercase text-large">${this.localize('header.list')}</div>
</solid-route>
</solid-router>
</header>
<section id="invoices-summary" data-view="invoices-summary">
<div class="segment block half sm-full padding-top-medium padding-bottom-medium padding-right-medium">
<div class="segment full padding-large shadow">
<div class="text-color-heading text-uppercase text-xxlarge text-bold margin-bottom-xsmall whitespace-normal">${this.localize('summary.totalTitle')}</div>
<div class="total-help whitespace-normal text-large">${this.localize('summary.totalTitleHelp')}</div>
<div class="separation-line margin-top-medium margin-bottom-xsmall border-bottom border-color-third"></div>
<span id="recap-total" class="icon margin-top-medium text-xxlarge segment text-bold"></span>
</div>
</div>
<div class="segment full sm-whitespace-normal">
<div class="segment quarter sm-full padding-right-medium">
<div class="segment full padding-medium shadow total-block">
<div class="title-block text-xlarge text-color-heading text-uppercase text-bold margin-bottom-small whitespace-normal">${this.localize('summary.totalCustomerTitle')}</div>
<div class="separation-line margin-top-small margin-bottom-xsmall border-bottom border-color-third"></div>
<span class="total-block-amount text-xxlarge" id="recap-customer-invoices"></span>
<div class="segment quarter sm-full padding-right-medium">
<div class="segment full padding-medium shadow total-block">
<div class="title-block text-xlarge text-color-heading text-uppercase text-bold margin-bottom-small whitespace-normal">${this.localize('summary.totalFreelancerTitle')}</div>
<div class="separation-line margin-top-small margin-bottom-xsmall border-bottom border-color-third"></div>
<span class="total-block-amount text-xxlarge" id="recap-freelancer-invoices"></span>
<div class="segment quarter sm-full padding-right-medium">
<div class="segment full padding-medium shadow total-block">
<div class="title-block text-xlarge text-color-heading text-uppercase text-bold margin-bottom-small whitespace-normal">${this.localize('summary.totalFeesTitle')}</div>
<div class="separation-line margin-top-small margin-bottom-xsmall border-bottom border-color-third"></div>
<span class="total-block-amount text-xxlarge" id="recap-fees"></span>
<div class="segment quarter sm-full padding-right-medium">
<div class="segment full padding-medium shadow total-block bp-block">
<div class="title-block text-xlarge text-color-heading text-uppercase text-bold whitespace-normal">${this.localize('summary.totalBusinessProvisionsTitle')}</div>
<div class="whitespace-normal text-large" id="info-business-provision"></div>
<div class="separation-line margin-top-xsmall margin-bottom-xsmall border-bottom border-color-third"></div>
<span class="total-block-amount text-xxlarge" id="recap-business-provision"></span>
</div>
</section>
<section id="invoices-details" data-view="invoices-details" hidden="">
<!-- customer ==================================== -->
<section id="clients-invoices" class="invoices-list invoices-list--clients">
<header class="segment">
<solid-router default-route="invoice-list" ${prefix}>
<solid-route name="invoice-list"></solid-route>
<solid-route name="add-invoice" class="segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-plus">${this.localize('button.invoice_create')}</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>
<div class="show-list segment half sm-full cursor-pointer sm-margin-top-medium text-bold text-large text-uppercase padding-xsmall icon icon-arrow-down">${this.localize('title.customer_invoices')}</div>
<dialog data-view="add-invoice" class="invoice-form padding-xxlarge sm-padding-medium">
<close-button></close-button>
<h3 class="text-color-heading">${this.localize('title.invoice_create')}</h3>
<solid-form
class="new-customer-invoice-form segment full whitespace-normal"
data-src="${dataSrc}"
nested-field="customerInvoices"
fields="first-line(title, identifier),
second-line(state, invoicingDate),
batches,
last-line(tvaRate, additionalText)"
label-title="${this.localize('label.invoice_title')}"
label-identifier="${this.localize('label.invoice_identifier')}"
label-state="${this.localize('label.invoice_state')}"
label-invoicingDate="${this.localize('label.invoice_invoicing_date')}"
label-tvaRate="${this.localize('label.invoice_tva_rate')}"
label-additionalText="${this.localize('label.invoice_additional_text')}"
placeholder-additionalText="${this.localize('placholder.invoice_additional_text')}"
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"
widget-additionalText="solid-form-placeholder-label-text"
enum-state="${this.localize('option.edited')} = edited, ${this.localize('option.pending')} = pending, ${this.localize('option.sent')} = sent, ${this.localize('option.late')} = late, ${this.localize('option.paid')} = paid"
class-first-line="segment full sm-whitespace-normal"
class-second-line="segment full sm-whitespace-normal"
class-last-line="segment half sm-full"
class-title="segment half sm-full"
class-identifier="segment half sm-full"
class-state="segment half sm-full"
class-invoicingDate="segment half sm-full"
class-state="custom-select"
multiple-batches
next="invoice-list"
required-title
required-identifier
required-invoicingDate
required-tvaRate
submit-button="${this.localize('button.submit_form')}"
></solid-form>
</dialog>
<dialog data-view="edit-invoice" class="invoice-form padding-xxlarge sm-padding-medium">
<close-button></close-button>
<h3>${this.localize('title.invoice_modify')}</h3>
<solid-form
bind-resources
fields="first-line(title, identifier),
second-line(state, invoicingDate),
batches,
last-line(tvaRate, additionalText)"
label-title="${this.localize('label.invoice_title')}"
label-identifier="${this.localize('label.invoice_identifier')}"
label-state="${this.localize('label.invoice_state')}"
label-invoicingDate="${this.localize('label.invoice_invoicing_date')}"
label-tvaRate="${this.localize('label.invoice_tva_rate')}"
label-additionalText="${this.localize('label.invoice_additional_text')}"
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"
widget-additionalText="solid-form-placeholder-label-text"
enum-state="${this.localize('option.edited')} = edited, ${this.localize('option.pending')} = pending, ${this.localize('option.sent')} = sent, ${this.localize('option.late')} = late, ${this.localize('option.paid')} = paid"
class-first-line="segment full sm-whitespace-normal"
class-second-line="segment full sm-whitespace-normal"
class-title="segment half sm-full"
class-identifier="segment half sm-full"
class-state="segment half sm-full"
class-invoicingDate="segment half sm-full"
class-state="custom-select"
multiple-batches
next="invoice-list"
required-title
required-identifier
required-invoicingDate
required-tvaRate
submit-button="${this.localize('button.edit_submit_form')}"
></solid-form>
<solid-delete class="sm-full button text-xsmall text-bold text-uppercase text-center color-secondary bordered icon icon-trash"
bind-resources
next="invoice-list"
confirmation-message="${this.localize('confirm.delete_invoice')}"
confirmation-type="dialog"
confirmation-submit-text="${this.localize('validate.delete_invoice')}"
confirmation-cancel-text="${this.localize('cancel.delete_invoice')}"
confirmation-submit-class="segment sm-full button text-xsmall text-bold reversed text-uppercase text-center color-secondary bordered"
confirmation-cancel-class="cancel segment sm-full button text-xsmall text-bold text-uppercase text-center color-secondary bordered"
data-label="${this.localize('button.delete_submit_form')}"
></solid-delete>
</dialog>
<dialog data-view="duplicate-invoice" class="invoice-form padding-xxlarge sm-padding-medium" id="duplicate">
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
<close-button></close-button>
<h3>${this.localize('title.invoice_duplicate')}</h3>
<h4>${this.localize('question.invoice_duplicate')}</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="${this.localize('option.edited')} = edited, ${this.localize('option.pending')} = pending, ${this.localize('option.sent')} = sent, ${this.localize('option.late')} = late, ${this.localize('option.paid')} = paid"
class-state="custom-select"
class-title="invoice-title"
multiple-batches
naked
></solid-form>
<div class="popup-buttons">
<button class="popup-buttons__cancel close-duplication-dialog">${this.localize('button.duplicate_cancel')}</button>
<button class="popup-buttons__validate duplication-button">${this.localize('button.duplicate_confirm')}</button>
</div>
</dialog>
<solid-display
data-view="invoice-list"
class="invoices-list__item invoice-list-display"
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, print), batches, invoice-totals(totals-header, ht-total(ht-label, htAmount), tva-total(tvaRate, tvaAmount), ttc-total(ttc-label, ttcAmount)))"
value-totals-header="${this.localize('value.totals_header')}"
value-ht-label="${this.localize('label.value_ht')}"
value-ttc-label="${this.localize('label.value_ttc')}"
widget-batches="widget-batches"
widget-htAmount="widget-money"
widget-state="widget-state"
widget-tvaAmount="widget-money"
widget-ttcAmount="widget-money"
widget-tvaRate="widget-tva-rate"
widget-identifier="widget-invoice-number"
label-edit="${this.localize('label.edit')}"
label-show="${this.localize('label.show')}"
label-duplicate="${this.localize('label.duplicate')}"
action-edit="edit-invoice"
action-show="show-invoice"
action-duplicate="duplicate-invoice"
class-edit="children-mdi-pencil edit-invoice"
class-show="children-mdi-eye show-invoice"
class-duplicate="children-mdi-file-replace-outline duplicate-invoice"
classe-print="mdi mdi-dowload print-invoice"
order-desc="invoicingDate"
<dialog class="invoice-dialog padding-xxlarge sm-padding-medium" data-view="show-invoice">
<close-button></close-button>
<div class="popup-buttons">
<button class="popup-buttons__validate print">${this.localize('button.print')}</button>
<button class="popup-buttons__validate download">${this.localize('button.download')}</button>
</div>
<div id="print">
<div class="invoice-render">
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
<solid-display
class="display-invoice"
bind-resources
fields="invoice-head(invoice-header-left(identifier, invoicingDate), invoice-header-right(customer-infos(project.customer.name, project.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="${this.localize('label.value_ht')}"
value-ttc-label="${this.localize('label.value_ttc')}"
value-tva-notice="${this.localize('value.tva_notice')}"
widget-identifier="widget-render-title"
label-invoicingDate="${this.localize('label.invoice_invoicing_date2')}"
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"
class-project.customer.name="segment block whitespace-normal text-color-heading text-bold margin-bottom-xsmall"
></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>${this.localize('text.tva_number')}</strong>FR 61 813140605</p>
<p>${this.localize('text.sas_info')}</p>
</div>
</dialog>
<!-- /render -->
</section>
<!-- /customer ==================================== -->
<!-- freelance ==================================== -->
<section id="freelances-invoices" class="invoices-list invoices-list--freelances">
<header class="segment">
<solid-router default-route="freelance-invoice-list" ${prefix}>
<solid-route name="freelance-invoice-list"></solid-route>
<solid-route name="edit-freelance-invoice" use-id></solid-route>
<solid-route name="add-freelance-invoice" class="segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-cloud-upload">${this.localize('button.invoice_import')}</solid-route>
</solid-router>
<div class="show-list segment half sm-full cursor-pointer text-bold text-large text-uppercase padding-xsmall icon icon-arrow-down">${this.localize('title.freelance_invoices')}</div>
<dialog data-view="add-freelance-invoice" class="invoice-form padding-xxlarge sm-padding-medium">
<close-button></close-button>
<h3>${this.localize('title.invoice_import')}</h3>
<solid-form
data-src="${dataSrc}"
nested-field="freelancerInvoices"
fields="first-line(freelanceFullname, identifier),
second-line(htAmount, nomenclatureNote),
third-line(uploadUrl)"
label-freelanceFullname="${this.localize('label.freelance_fullname')}"
label-identifier="${this.localize('label.freelance_identifier')}"
label-uploadUrl="${this.localize('label.upload_url')}"
label-htAmount="${this.localize('label.freelance_ht_amount')}"
widget-nomenclatureNote="widget-nomenclature"
widget-uploadUrl="solid-form-file-label"
widget-htAmount="solid-form-number-label"
upload-url-uploadUrl="${uploadUrl}"
class-first-line="segment full sm-whitespace-normal"
class-second-line="segment full sm-whitespace-normal"
class-third-line="segment full"
class-freelanceFullname="segment half sm-full"
class-identifier="segment half sm-full"
class-htAmount="segment half sm-full"
class-nomenclatureNote="segment half sm-full"
class-invoicingDate="segment half sm-full"
required-freelanceFullname
required-identifier
required-htAmount
required-uploadUrl
next="freelance-invoice-list"
submit-button="${this.localize('button.submit_form')}"
></solid-form>
</dialog>
<dialog data-view="edit-freelance-invoice" class="invoice-form padding-xxlarge sm-padding-medium">
<close-button></close-button>
<h3>Modifier une facture</h3>
<solid-form
bind-resources
class="edit-freelance-invoice segment full whitespace-normal"
fields="first-line(freelanceFullname, identifier),
second-line(invoicingDate, htAmount),
third-line(state, uploadUrl)"
label-freelanceFullname="${this.localize('label.freelance_fullname')}"
label-identifier="${this.localize('label.freelance_identifier')}"
label-invoicingDate="${this.localize('label.freelance_invoicing_date')}"
label-state="${this.localize('label.invoice_state')}"
label-uploadUrl="${this.localize('label.edit_upload_url')}"
label-htAmount="${this.localize('label.freelance_ht_amount')}"
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="${this.localize('option.edited')} = edited, ${this.localize('option.pending')} = pending, ${this.localize('option.sent')} = sent, ${this.localize('option.late')} = late, ${this.localize('option.paid')} = paid"
class-first-line="segment full sm-whitespace-normal"
class-second-line="segment full sm-whitespace-normal"
class-third-line="segment full"
class-freelanceFullname="segment half sm-full"
class-identifier="segment half sm-full"
class-htAmount="segment half sm-full"
class-nomenclatureNote="segment half sm-full"
class-invoicingDate="segment half sm-full"
required-freelanceFullname
required-identifier
required-invoicingDate
required-htAmount
next="freelance-invoice-list"
submit-button="${this.localize('button.submit_form')}"
></solid-form>
<solid-delete class="sm-full button text-xsmall text-bold text-uppercase text-center color-secondary bordered icon icon-trash"
bind-resources
next="freelance-invoice-list"
confirmation-message="${this.localize('confirm.delete_invoice')}"
confirmation-type="dialog"
confirmation-submit-text="${this.localize('validate.delete_invoice')}"
confirmation-cancel-text="${this.localize('cancel.delete_invoice')}"
confirmation-submit-class="segment sm-full button text-xsmall text-bold reversed text-uppercase text-center color-secondary bordered"
confirmation-cancel-class="cancel segment sm-full button text-xsmall text-bold text-uppercase text-center color-secondary bordered"
data-label="${this.localize('button.delete_submit_form')}"
></solid-delete>
class="invoice-list-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="${this.localize('label.edit')}"
action-edit="edit-freelance-invoice"
widget-htAmount="widget-money"
widget-state="widget-state"
widget-uploadUrl="widget-embed-drive"
order-desc="invoicingDate"
></solid-display>
</section>
<!-- /freelance ==================================== -->
</section>
</div>
`;
}
}
customElements.define('solid-invoicing', SolidInvoicing);