Newer
Older
import { SolidTemplateElement, Helpers, store } from 'https://cdn.skypack.dev/@startinblox/core@0.16';
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.2";
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',
}
}
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" },
}),
);
}
/**
* 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}) {
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"
fields="price-line(title, htAmount)"
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"
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>
</header>
<dialog data-view="add-invoice" class="invoice-form">
<close-button></close-button>
<h3 class="text-color-heading">${this.localize('title.invoice_create')}</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="${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"
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
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"
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">
<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"
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"
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" id="duplicate">
<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="mdi-pencil mdi"
class-show="mdi-eye mdi"
class-duplicate="mdi-file-replace-outline mdi"
order-desc="invoicingDate"
></solid-display>
<!-- render -->
<dialog class="invoice-dialog" 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>
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
<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(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>
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
</header>
<dialog data-view="add-freelance-invoice" class="invoice-form">
<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}"
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">
<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="${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-state="custom-select"
required-freelanceFullname
required-identifier
required-invoicingDate
required-htAmount
next="freelance-invoice-list"
submit-button="${this.localize('button.submit_form')}"
></solid-form>
</dialog>
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);