Initial commit: L10N_Europe packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:52 +02:00
commit 9803722600
2377 changed files with 380711 additions and 0 deletions

View file

@ -0,0 +1,49 @@
# Italy - Declaration of Intent
Add support for the Declaration of Intent (Dichiarazione di Intento) to the Italian localization.
## Installation
```bash
pip install odoo-bringout-oca-ocb-l10n_it_edi_doi
```
## Dependencies
This addon depends on:
- l10n_it_edi
- sale
## Manifest Information
- **Name**: Italy - Declaration of Intent
- **Version**: 0.1
- **Category**: Accounting/Localizations
- **License**: LGPL-3
- **Installable**: False
## Source
Based on [OCA/OCB](https://github.com/OCA/OCB) branch 16.0, addon `l10n_it_edi_doi`.
## License
This package maintains the original LGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph L10n_it_edi_doi Module - l10n_it_edi_doi
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for l10n_it_edi_doi. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,6 @@
# Dependencies
This addon depends on:
- [l10n_it_edi](../../odoo-bringout-oca-ocb-l10n_it_edi)
- [sale](../../odoo-bringout-oca-ocb-sale)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon l10n_it_edi_doi or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-ocb-l10n_it_edi_doi"
# or
uv pip install odoo-bringout-oca-ocb-l10n_it_edi_doi"
```

View file

@ -0,0 +1,20 @@
# Models
Detected core models and extensions in l10n_it_edi_doi.
```mermaid
classDiagram
class l10n_it_edi_doi_declaration_of_intent
class account_chart_template
class account_fiscal_position
class account_move
class account_tax
class res_company
class res_partner
class sale_order
class sale_order_line
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: l10n_it_edi_doi. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon l10n_it_edi_doi
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,34 @@
# Security
Access control and security definitions in l10n_it_edi_doi.
## Access Control Lists (ACLs)
Model access permissions defined in:
- **[ir.model.access.csv](../l10n_it_edi_doi/security/ir.model.access.csv)**
- 2 model access rules
## Record Rules
Row-level security rules defined in:
```mermaid
graph TB
subgraph "Security Layers"
A[Users] --> B[Groups]
B --> C[Access Control Lists]
C --> D[Models]
B --> E[Record Rules]
E --> F[Individual Records]
end
```
Security files overview:
- **[ir.model.access.csv](../l10n_it_edi_doi/security/ir.model.access.csv)**
- Model access permissions (CRUD rights)
Notes
- Access Control Lists define which groups can access which models
- Record Rules provide row-level security (filter records by user/group)
- Security groups organize users and define permission sets
- All security is enforced at the ORM level by Odoo

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon l10n_it_edi_doi
```

View file

@ -0,0 +1,8 @@
# Wizards
Transient models exposed as UI wizards in l10n_it_edi_doi.
```mermaid
classDiagram
class SaleAdvancePaymentInv
```

View file

@ -0,0 +1,59 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
from . import wizard
from odoo import api, SUPERUSER_ID
import logging
_logger = logging.getLogger(__name__)
def _l10n_it_edi_doi_post_init(cr, registry):
""" Update existing companies that have the Italian Chart of Accounts set """
env = api.Environment(cr, SUPERUSER_ID, {})
chart_template = env.ref('l10n_it.l10n_it_chart_template_generic', raise_if_not_found=False)
if chart_template:
for company in env['res.company'].search([('chart_template_id', '=', chart_template.id)]):
_logger.info("Company %s already has the Italian localization installed, updating...", company.name)
# Create the declaration of intent fiscal position
doi_fp_template = env.ref('l10n_it_edi_doi.declaration_of_intent_fiscal_position')
doi_fp_vals = ((doi_fp_template, chart_template._get_fp_vals(company, doi_fp_template)),)
doi_fp = chart_template._create_records_with_xmlid('account.fiscal.position', doi_fp_vals, company)
# Create the declaration of intent tax
doi_tax_template = env.ref('l10n_it_edi_doi.00di')
tax_template_ref = doi_tax_template._generate_tax(company)['tax_template_to_tax']
doi_tax = tax_template_ref[doi_tax_template]
doi_tax.write({
'l10n_it_has_exoneration': True,
'l10n_it_kind_exoneration': 'N3.5',
'l10n_it_law_reference': 'art. 8, c. 1, lett. c) D.P.R. 633/1972',
})
# Create the fiscal position tax mappings
# Add all the taxes needed for the fiscal position to `tax_template_ref`
for tax_template_id, external_xml_id in doi_fp_template.tax_ids.tax_src_id.get_external_id().items():
tax_template = env['account.tax.template'].browse(tax_template_id)
module, xml_id = external_xml_id.split('.')
tax = env.ref('%s.%s_%s' % (module, company.id, xml_id), raise_if_not_found=False)
if tax:
tax_template_ref[tax_template] = tax
# Gather all the info for the tax mappings
doi_fp_tax_template_vals = []
for tax in doi_fp_template.tax_ids:
tax_src_id = tax_template_ref.get(tax.tax_src_id)
tax_dest_id = tax_template_ref.get(tax.tax_dest_id)
if tax_src_id is None or tax_dest_id is None:
continue
doi_fp_tax_template_vals.append((tax, {
'tax_src_id': tax_src_id.id,
'tax_dest_id': tax_dest_id.id or False,
'position_id': doi_fp.id,
}))
chart_template._create_records_with_xmlid('account.fiscal.position.tax', doi_fp_tax_template_vals, company)
# Set the info on the company
company.l10n_it_edi_doi_tax_id = doi_tax
company.l10n_it_edi_doi_fiscal_position_id = doi_fp

View file

@ -0,0 +1,28 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Italy - Declaration of Intent',
'version': '0.1',
'depends': [
'l10n_it_edi',
'sale',
],
'description': """
Add support for the Declaration of Intent (Dichiarazione di Intento) to the Italian localization.
""",
'category': 'Accounting/Localizations',
'website': 'https://www.odoo.com/documentation/17.0/applications/finance/fiscal_localizations/italy.html',
'data': [
'security/ir.model.access.csv',
'data/account_tax_template.xml',
'data/account_fiscal_position_template_data.xml',
'data/invoice_it_template.xml',
'views/l10n_it_edi_doi_declaration_of_intent_views.xml',
'views/account_move_views.xml',
'views/report_invoice.xml',
'views/res_partner_views.xml',
'views/sale_ir_actions_report_templates.xml',
'views/sale_order_views.xml',
],
'license': 'LGPL-3',
'post_init_hook': '_l10n_it_edi_doi_post_init',
}

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="declaration_of_intent_fiscal_position" model="account.fiscal.position.template">
<field name="sequence">10</field>
<field name="name">Declaration of Intent</field>
<field name="chart_template_id" ref="l10n_it.l10n_it_chart_template_generic"/>
<field name="auto_apply" eval="False" />
<field name="vat_required" eval="False" />
<field name="note">Not taxable (art. 8, c. 1, lett. c) D.P.R. 633/1972) letter intent</field>
</record>
<record id="afpttn_declaration_of_intent_fiscal_position_1" model="account.fiscal.position.tax.template">
<field name="position_id" ref="declaration_of_intent_fiscal_position"/>
<field name="tax_src_id" ref="l10n_it.22v"/>
<field name="tax_dest_id" ref="00di"/>
</record>
<record id="afpttn_declaration_of_intent_fiscal_position_2" model="account.fiscal.position.tax.template">
<field name="position_id" ref="declaration_of_intent_fiscal_position"/>
<field name="tax_src_id" ref="l10n_it.10v"/>
<field name="tax_dest_id" ref="00di"/>
</record>
<record id="afpttn_declaration_of_intent_fiscal_position_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="declaration_of_intent_fiscal_position"/>
<field name="tax_src_id" ref="l10n_it.5v"/>
<field name="tax_dest_id" ref="00di"/>
</record>
<record id="afpttn_declaration_of_intent_fiscal_position_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="declaration_of_intent_fiscal_position"/>
<field name="tax_src_id" ref="l10n_it.4v"/>
<field name="tax_dest_id" ref="00di"/>
</record>
</odoo>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="00di" model="account.tax.template">
<field name="description">Declaration of Intent</field>
<field name="chart_template_id" ref="l10n_it.l10n_it_chart_template_generic"/>
<field name="name">0% E</field>
<field name="sequence">950</field>
<field name="amount">0.0</field>
<field name="amount_type">percent</field>
<field name="type_tax_use">sale</field>
<field name="price_include">False</field>
<field name="tax_group_id" ref="l10n_it.tax_group_fuori"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('l10n_it.tax_report_line_vp2_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('l10n_it.tax_report_line_vp2_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
</record>
</odoo>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="account_invoice_line_it_FatturaPA" inherit_id="l10n_it_edi.account_invoice_line_it_FatturaPA">
<DettaglioLinee position="inside">
<AltriDatiGestionali t-if="record.l10n_it_edi_doi_id">
<TipoDato t-translation="off">INTENTO</TipoDato>
<RiferimentoTesto t-out="record.l10n_it_edi_doi_id.display_name"/>
<RiferimentoData t-out="format_date(record.l10n_it_edi_doi_id.issue_date)"/>
</AltriDatiGestionali>
</DettaglioLinee>
</template>
</data>
</odoo>

View file

@ -0,0 +1,802 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * l10n_it_edi_doi
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-11 09:25+0000\n"
"PO-Revision-Date: 2024-06-11 09:25+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_form_label mx-3\"> to </span>"
msgstr "<span class=\"o_form_label mx-3\"> al </span>"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_form_label mx-3\">/</span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_form_label\">Amounts:</span>"
msgstr "<span class=\"o_form_label\">Importi:</span>"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_form
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_order_form
msgid "<span class=\"o_stat_text\">Declaration of Intent</span>"
msgstr "<span class=\"o_stat_text\">Dichiarazione di Intento</span>"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_partner_l10n_form
msgid "<span class=\"o_stat_text\">Declarations of Intent</span>"
msgstr "<span class=\"o_stat_text\">Dichiarazioni di Intento</span>"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_stat_text\">Invoices</span>"
msgstr "<span class=\"o_stat_text\">Fatture</span>"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_stat_text\">Sale Orders</span>"
msgstr "<span class=\"o_stat_text\">Ordini di vendita</span>"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_move.py:0
#: code:addons/l10n_it_edi_doi/models/sale_order.py:0
#, python-format
msgid "A line using tax %s should not contain any other taxes"
msgstr "Una riga che utilizza la tassa %s non deve contenere altre tasse"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_chart_template
msgid "Account Chart Template"
msgstr "Modello piano dei conti"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Accounting Date"
msgstr "Data contabile"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction
msgid "Action Needed"
msgstr "Azione richiesta"
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__active
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Active"
msgstr "Attivo"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_ids
msgid "Activities"
msgstr "Attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_decoration
msgid "Activity Exception Decoration"
msgstr "Decorazione eccezione attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_state
msgid "Activity State"
msgstr "Stato attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_type_icon
msgid "Activity Type Icon"
msgstr "Icona tipo di attività"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_tree
msgid "Add a Declaration of Intent"
msgstr "Aggiungi Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_attachment_count
msgid "Attachment Count"
msgstr "Conteggio allegati"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_partner__l10n_it_edi_doi_ids
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_users__l10n_it_edi_doi_ids
msgid "Available Declarations of Intent of this partner"
msgstr "Dichiarazioni di Intento disponibili di questo partner"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_res_company
msgid "Companies"
msgstr "Aziende"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__company_id
msgid "Company"
msgstr "Azienda"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_res_partner
msgid "Contact"
msgstr "Contatto"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__create_date
msgid "Created on"
msgstr "Data creazione"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__currency_id
msgid "Currency"
msgstr "Valuta"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Customer"
msgstr "Cliente"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Date Range"
msgstr "Intervallo Date"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__issue_date
msgid "Date of Issue"
msgstr "Data di Emissione"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_date
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_date
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_date
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_date
msgid "Date on which Declaration of Intent is applied"
msgstr "Data di applicazione della Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__issue_date
msgid "Date on which the Declaration of Intent was issued"
msgstr "Data di emissione della Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_l10n_it_edi_doi_declaration_of_intent
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_id
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_id
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_id
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_id
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_account_invoice_filter
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_sales_order_filter
msgid "Declaration of Intent"
msgstr "Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_amount
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_amount
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_amount
msgid "Declaration of Intent Amount"
msgstr "Dichiarazione di Intento Importo"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_not_yet_invoiced
msgid "Declaration of Intent Amount Not Yet Invoiced"
msgstr "Dichiarazione di Intento Importo Non Ancora Fatturato"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_company__l10n_it_edi_doi_fiscal_position_id
msgid "Declaration of Intent Fiscal Position"
msgstr "Dichiarazione di Intento Posizioni Fiscale"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_company__l10n_it_edi_doi_tax_id
msgid "Declaration of Intent Tax"
msgstr "Dichiarazione di Intento Imposta"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_warning
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_warning
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_warning
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_warning
msgid "Declaration of Intent Threshold Warning"
msgstr "Dichiarazione di Intento Avviso di soglia"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_move.py:0
#: code:addons/l10n_it_edi_doi/models/sale_order.py:0
#, python-format
msgid "Declaration of Intent for %s"
msgstr "Dichiarazione di Intento per %s"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/res_partner.py:0
#, python-format
msgid "Declaration of Intent of %s"
msgstr "Dichiarazione di Intento di %s"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__display_name
msgid "Display Name"
msgstr "Nome Visualizzato"
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__draft
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Draft"
msgstr "Bozza"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__end_date
msgid "End Date"
msgstr "Data fine"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.res_partner_view_search
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_account_invoice_filter
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_sales_order_filter
msgid "Exceeded Declaration of Intent"
msgstr "Dichiarazione di Intento superata"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__start_date
msgid "First date on which the Declaration of Intent is valid"
msgstr "Prima data di validità della dichiarazione di intento"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_fiscal_position
msgid "Fiscal Position"
msgstr "Posizione fiscale"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_follower_ids
msgid "Followers"
msgstr "Seguito da"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_partner_ids
msgid "Followers (Partners)"
msgstr "Seguito da (partner)"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_type_icon
msgid "Font awesome icon e.g. fa-tasks"
msgstr "Icona Font Awesome es. fa-tasks"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_move.py:0
#: code:addons/l10n_it_edi_doi/models/sale_order.py:0
#, python-format
msgid ""
"Given the tax %s is applied, there should be a Declaration of Intent "
"selected."
msgstr ""
"Data l'applicazione dell'imposta %s, dovrebbe esserci una Dichiarazione di Intento "
"selezionata."
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__has_message
msgid "Has Message"
msgstr "Contiene messaggio"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__id
msgid "ID"
msgstr "ID"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_icon
msgid "Icon"
msgstr "Icona"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_icon
msgid "Icon to indicate an exception activity."
msgstr "Icona per indicare un'attività eccezione."
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction
msgid "If checked, new messages require your attention."
msgstr "Se selezionata, nuovi messaggi richiedono attenzione."
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_sms_error
msgid "If checked, some messages have a delivery error."
msgstr "Se selezionata, alcuni messaggi presentano un errore di consegna."
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Invoice Date"
msgstr "Data fattura"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__invoiced
msgid "Invoiced"
msgstr "Fatturato"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order_line__qty_invoiced_posted
msgid "Invoiced Quantity (posted)"
msgstr "Quantità fatturata (confermata)"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Invoices"
msgstr "Fatture"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__invoice_ids
msgid "Invoices / Refunds"
msgstr "Fatture / Rimborsi"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "Invoices using Declaration of Intent %s"
msgstr "Fatture con Dichiarazione di Intento %s"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_is_follower
msgid "Is Follower"
msgstr "Sta seguendo"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_move
msgid "Journal Entry"
msgstr "Registrazione contabile"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__end_date
msgid "Last date on which the Declaration of Intent is valid"
msgstr "Data ultima di validità della Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_main_attachment_id
msgid "Main Attachment"
msgstr "Allegato principale"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error
msgid "Message Delivery error"
msgstr "Errore di consegna messaggio"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_ids
msgid "Messages"
msgstr "Messaggi"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__my_activity_date_deadline
msgid "My Activity Deadline"
msgstr "Scadenza mie attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_date_deadline
msgid "Next Activity Deadline"
msgstr "Scadenza prossima attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_summary
msgid "Next Activity Summary"
msgstr "Riepilogo prossima attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_type_id
msgid "Next Activity Type"
msgstr "Tipologia prossima attività"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__not_yet_invoiced
msgid "Not Yet Invoiced"
msgstr "Non Ancora Fatturato"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Not Yet Invoiced Amount"
msgstr "Importo Non Ancora Fatturato"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Number"
msgstr "Numero"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction_counter
msgid "Number of Actions"
msgstr "Numero di azioni"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error_counter
msgid "Number of errors"
msgstr "Numero di errori"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction_counter
msgid "Number of messages requiring action"
msgstr "Numero di messaggi che richiedono un'azione"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error_counter
msgid "Number of messages with delivery error"
msgstr "Numero di messaggi con errore di consegna"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__partner_id
msgid "Partner"
msgstr "Partner"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid ""
"Pay attention, the threshold of your Declaration of Intent %s of %s is exceeded by %s, this document included.\n"
"Invoiced: %s; Not Yet Invoiced: %s"
msgstr ""
"Attenzione, la soglia della tua Dichiarazione di Intento %s di %s è superata da %s, questo documento incluso.\n"
"Fatturato: %s; Non ancora fatturato: %s"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__protocol_number_part1
msgid "Protocol 1"
msgstr "Protocollo 1"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__protocol_number_part2
msgid "Protocol 2"
msgstr "Protocollo 2"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Protocol Number"
msgstr "Numero di Protocollo"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Reactivate"
msgstr "Riattivare"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__remaining
msgid "Remaining"
msgstr "Rimanente"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__remaining_amount
msgid ""
"Remaining amount after deduction of the Invoiced and Not Yet Invoiced "
"amounts."
msgstr ""
"Importo rimanente dopo la deduzione degli importi Fatturati e Non ancora fatturati "
"importi."
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Reset to Draft"
msgstr "Reimposta a bozza"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_user_id
msgid "Responsible User"
msgstr "Utente Responsabile"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Revoke"
msgstr "Revoca"
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__revoked
msgid "Revoked"
msgstr "Revocato"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_sms_error
msgid "SMS Delivery error"
msgstr "Errore di consegna SMS"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_sale_order
msgid "Sales Order"
msgstr "Ordini di vendita"
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_sale_order_line
msgid "Sales Order Line"
msgstr "Riga ordine di vendita"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Sales Orders"
msgstr "Ordini di vendita"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__sale_order_ids
msgid "Sales Orders / Quotations"
msgstr "Ordini di vendita / Preventivi"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "Sales Orders using Declaration of Intent %s"
msgstr "Ordini di vendita con Dichiarazioni di Intento %s"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Show active declarations of intent"
msgstr "Mostra Dichiarazioni di intento attive"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Show draft declarations of intent"
msgstr "Mostra bozze di dichiarazioni di intento."
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Show terminated or revoked Declarations of Intent"
msgstr "Mostra dichiarazioni di intento chiuse o revocate"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__start_date
msgid "Start Date"
msgstr "Data Inizio"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__state
msgid "State"
msgstr "Stato"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_state
msgid ""
"Status based on activities\n"
"Overdue: Due date is already passed\n"
"Today: Activity date is today\n"
"Planned: Future activities."
msgstr ""
"Stato basato sulle attività\n"
"In ritardo: scadenza già superata\n"
"Oggi: attività in data odierna\n"
"Pianificato: attività future."
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_tax
msgid "Tax"
msgstr "Imposta"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Tax excluded"
msgstr "Imposta esclusa"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Terminate"
msgstr "Terminare"
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__terminated
msgid "Terminated"
msgstr "Terminato"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Terminated / Revoked"
msgstr "Terminato / Revocato"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent belongs to company %s, not %s."
msgstr "La Dichiarazione di Intento appartiene alla società %s, non a %s."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent belongs to partner %s, not %s."
msgstr "La Dichiarazione di Intento appartiene al partner %s, non a %s."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent is in draft."
msgstr "La Dichiarazione di Intento è in bozza."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent is valid from %s to %s, not on %s."
msgstr "La Dichiarazione di Intento è valida dal %s a %s, non il %s."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent must be active."
msgstr "La dichiarazione di Intento deve essere attiva."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent uses currency %s, not %s."
msgstr "La Dichiarazione di Intento utilizza la valuta %s, non %s."
#. module: l10n_it_edi_doi
#: model:ir.model.constraint,message:l10n_it_edi_doi.constraint_l10n_it_edi_doi_declaration_of_intent_protocol_number_unique
msgid ""
"The Protocol Number of a Declaration of Intent must be unique! Please choose"
" another one."
msgstr "Il numero di protocollo di una Dichiarazione di Intento deve essere univoco! Per favore scegline"
" un altro."
#. module: l10n_it_edi_doi
#: model:ir.model.constraint,message:l10n_it_edi_doi.constraint_l10n_it_edi_doi_declaration_of_intent_threshold_positive
msgid "The Threshold of a Declaration of Intent must be positive."
msgstr "La Soglia di una Dichiarazione di Intento deve essere positiva."
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__state
msgid ""
"The state of this Declaration of Intent. \n"
"- 'Draft' means that the Declaration of Intent still needs to be confirmed before being usable. \n"
"- 'Active' means that the Declaration of Intent is usable. \n"
"- 'Terminated' designates that the Declaration of Intent has been marked as not to use anymore without invalidating usages of it. \n"
"- 'Revoked' means the Declaration of Intent should not have been used. You will probably need to revert previous usages of it, if any.\n"
msgstr ""
"Lo stato della presente Dichiarazione di Intento. \n"
"- 'Bozza' significa che la Dichiarazione di Intento deve ancora essere confermata prima di essere utilizzabile. \n"
"- 'Attiva' significa che la Dichiarazione di Intento è utilizzabile. \n"
"- 'Terminata' indica che la Dichiarazione di Intento è stata contrassegnata come non più utilizzabile senza invalidarne gli usi. \n"
"- 'Revocata' significa che la Dichiarazione di Intento non deve essere utilizzata. Probabilmente sarà necessario ripristinare gli usi precedenti, se presenti.\n"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__threshold
msgid "Threshold"
msgstr "Soglia"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Total"
msgstr "Totale"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__threshold
msgid ""
"Total amount of allowed sales without VAT under this Declaration of Intent"
msgstr ""
"Importo totale delle vendite consentite senza IVA ai sensi della presente Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__not_yet_invoiced
msgid ""
"Total amount of planned sales under this Declaration of Intent (i.e. current"
" quotation and sales orders) that can still be invoiced"
msgstr ""
"Importo totale delle vendite pianificate nell'ambito della presente Dichiarazione di "
"Intento (cioè l'offerta e gli ordini di vendita attuali) che possono ancora essere fatturati"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_amount
#: model:ir.model.fields,help:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_amount
#: model:ir.model.fields,help:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_amount
msgid "Total amount of sales under the Declaration of Intent of this document"
msgstr ""
"Importo totale delle vendite ai sensi della Dichiarazione di Intento del presente documento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__invoiced
msgid ""
"Total amount of sales under this Declaration of Intent"
msgstr ""
"Importo totale delle vendite ai sensi della presente Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_not_yet_invoiced
msgid ""
"Total under the Declaration of Intent of this document that can still be "
"invoiced"
msgstr ""
"Totale ai sensi della Dichiarazione di Intento del presente documento che può ancora essere "
"fatturati"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_decoration
msgid "Type of the exception activity on record."
msgstr "Tipo di attività eccezione sul record."
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_use
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_use
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_use
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_use
msgid "Use Declaration of Intent"
msgstr "Utilizzare Dichiarazione di Intento"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Validate"
msgstr "Validare"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__website_message_ids
msgid "Website Messages"
msgstr "Messaggi sito web"
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__website_message_ids
msgid "Website communication history"
msgstr "Cronologia comunicazioni sito web"
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid ""
"You cannot delete Declarations of Intents that are already used on at least "
"one Invoice or Sales Order."
msgstr ""
"Non è possibile eliminare dichiarazioni di intenti già utilizzate in almeno "
"una fattura o un ordine di vendita."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_fiscal_position.py:0
#, python-format
msgid ""
"You cannot delete the special fiscal position for Declarations of Intent."
msgstr ""
"Non è possibile eliminare la posizione fiscale speciale per le dichiarazioni di intento."
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_tax.py:0
#, python-format
msgid "You cannot delete the special tax for Declarations of Intent."
msgstr "Non è possibile eliminare la tassa speciale per le dichiarazioni di intento."
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_invoice_document
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_saleorder_document
msgid "Your Declaration of Intent number"
msgstr "Vostra Dichiarazione di Intento nr."
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_invoice_document
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_saleorder_document
msgid "from"
msgstr "del"

View file

@ -0,0 +1,775 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * l10n_it_edi_doi
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-11 09:25+0000\n"
"PO-Revision-Date: 2024-06-11 09:25+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_form_label mx-3\"> to </span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_form_label mx-3\">/</span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_form_label\">Amounts:</span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_form
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_order_form
msgid "<span class=\"o_stat_text\">Declaration of Intent</span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_partner_l10n_form
msgid "<span class=\"o_stat_text\">Declarations of Intent</span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_stat_text\">Invoices</span>"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "<span class=\"o_stat_text\">Sale Orders</span>"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_move.py:0
#: code:addons/l10n_it_edi_doi/models/sale_order.py:0
#, python-format
msgid "A line using tax %s should not contain any other taxes"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_chart_template
msgid "Account Chart Template"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Accounting Date"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction
msgid "Action Needed"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__active
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Active"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_ids
msgid "Activities"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_decoration
msgid "Activity Exception Decoration"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_state
msgid "Activity State"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_type_icon
msgid "Activity Type Icon"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_tree
msgid "Add a Declaration of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_attachment_count
msgid "Attachment Count"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_partner__l10n_it_edi_doi_ids
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_users__l10n_it_edi_doi_ids
msgid "Available Declarations of Intent of this partner"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_res_company
msgid "Companies"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__company_id
msgid "Company"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_res_partner
msgid "Contact"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__create_uid
msgid "Created by"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__create_date
msgid "Created on"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__currency_id
msgid "Currency"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Customer"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Date Range"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__issue_date
msgid "Date of Issue"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_date
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_date
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_date
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_date
msgid "Date on which Declaration of Intent is applied"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__issue_date
msgid "Date on which the Declaration of Intent was issued"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_l10n_it_edi_doi_declaration_of_intent
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_id
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_id
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_id
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_id
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_account_invoice_filter
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_sales_order_filter
msgid "Declaration of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_amount
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_amount
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_amount
msgid "Declaration of Intent Amount"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_not_yet_invoiced
msgid "Declaration of Intent Amount Not Yet Invoiced"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_company__l10n_it_edi_doi_fiscal_position_id
msgid "Declaration of Intent Fiscal Position"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_res_company__l10n_it_edi_doi_tax_id
msgid "Declaration of Intent Tax"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_warning
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_warning
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_warning
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_warning
msgid "Declaration of Intent Threshold Warning"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_move.py:0
#: code:addons/l10n_it_edi_doi/models/sale_order.py:0
#, python-format
msgid "Declaration of Intent for %s"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/res_partner.py:0
#, python-format
msgid "Declaration of Intent of %s"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__display_name
msgid "Display Name"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__draft
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Draft"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__end_date
msgid "End Date"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.res_partner_view_search
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_account_invoice_filter
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_sales_order_filter
msgid "Exceeded Declaration of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__start_date
msgid "First date on which the Declaration of Intent is valid"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_fiscal_position
msgid "Fiscal Position"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_follower_ids
msgid "Followers"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_partner_ids
msgid "Followers (Partners)"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_type_icon
msgid "Font awesome icon e.g. fa-tasks"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_move.py:0
#: code:addons/l10n_it_edi_doi/models/sale_order.py:0
#, python-format
msgid ""
"Given the tax %s is applied, there should be a Declaration of Intent "
"selected."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__has_message
msgid "Has Message"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__id
msgid "ID"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_icon
msgid "Icon"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_icon
msgid "Icon to indicate an exception activity."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction
msgid "If checked, new messages require your attention."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_sms_error
msgid "If checked, some messages have a delivery error."
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Invoice Date"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__invoiced
msgid "Invoiced"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order_line__qty_invoiced_posted
msgid "Invoiced Quantity (posted)"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Invoices"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__invoice_ids
msgid "Invoices / Refunds"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "Invoices using Declaration of Intent %s"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_is_follower
msgid "Is Follower"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_move
msgid "Journal Entry"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__write_uid
msgid "Last Updated by"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__write_date
msgid "Last Updated on"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__end_date
msgid "Last date on which the Declaration of Intent is valid"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_main_attachment_id
msgid "Main Attachment"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error
msgid "Message Delivery error"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_ids
msgid "Messages"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__my_activity_date_deadline
msgid "My Activity Deadline"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_date_deadline
msgid "Next Activity Deadline"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_summary
msgid "Next Activity Summary"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_type_id
msgid "Next Activity Type"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__not_yet_invoiced
msgid "Not Yet Invoiced"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Not Yet Invoiced Amount"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Number"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction_counter
msgid "Number of Actions"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error_counter
msgid "Number of errors"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_needaction_counter
msgid "Number of messages requiring action"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_error_counter
msgid "Number of messages with delivery error"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__partner_id
msgid "Partner"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid ""
"Pay attention, the threshold of your Declaration of Intent %s of %s is exceeded by %s, this document included.\n"
"Invoiced: %s; Not Yet Invoiced: %s"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__protocol_number_part1
msgid "Protocol 1"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__protocol_number_part2
msgid "Protocol 2"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Protocol Number"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Reactivate"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__remaining
msgid "Remaining"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__remaining
msgid ""
"Remaining amount after deduction of the Invoiced and Not Yet Invoiced "
"amounts."
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Reset to Draft"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_user_id
msgid "Responsible User"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Revoke"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__revoked
msgid "Revoked"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__message_has_sms_error
msgid "SMS Delivery error"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_sale_order
msgid "Sales Order"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_sale_order_line
msgid "Sales Order Line"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Sales Orders"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__sale_order_ids
msgid "Sales Orders / Quotations"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "Sales Orders using Declaration of Intent %s"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Show active declarations of intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Show draft declarations of intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Show terminated or revoked Declarations of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__start_date
msgid "Start Date"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__state
msgid "State"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_state
msgid ""
"Status based on activities\n"
"Overdue: Due date is already passed\n"
"Today: Activity date is today\n"
"Planned: Future activities."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model,name:l10n_it_edi_doi.model_account_tax
msgid "Tax"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
msgid "Tax excluded"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Terminate"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields.selection,name:l10n_it_edi_doi.selection__l10n_it_edi_doi_declaration_of_intent__state__terminated
msgid "Terminated"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_declaration_of_intent_search
msgid "Terminated / Revoked"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent belongs to company %s, not %s."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent belongs to partner %s, not %s."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent is in draft."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent is valid from %s to %s, not on %s."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent must be active."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid "The Declaration of Intent uses currency %s, not %s."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.constraint,message:l10n_it_edi_doi.constraint_l10n_it_edi_doi_declaration_of_intent_protocol_number_unique
msgid ""
"The Protocol Number of a Declaration of Intent must be unique! Please choose"
" another one."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.constraint,message:l10n_it_edi_doi.constraint_l10n_it_edi_doi_declaration_of_intent_threshold_positive
msgid "The Threshold of a Declaration of Intent must be positive."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__state
msgid ""
"The state of this Declaration of Intent. \n"
"- 'Draft' means that the Declaration of Intent still needs to be confirmed before being usable. \n"
"- 'Active' means that the Declaration of Intent is usable. \n"
"- 'Terminated' designates that the Declaration of Intent has been marked as not to use anymore without invalidating usages of it. \n"
"- 'Revoked' means the Declaration of Intent should not have been used. You will probably need to revert previous usages of it, if any.\n"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__threshold
msgid "Threshold"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_move_tree
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_quotation_tree
msgid "Total"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__threshold
msgid ""
"Total amount of allowed sales without VAT under this Declaration of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__not_yet_invoiced
msgid ""
"Total amount of planned sales under this Declaration of Intent (i.e. current"
" quotation and sales orders) that can still be invoiced"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_amount
#: model:ir.model.fields,help:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_amount
#: model:ir.model.fields,help:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_amount
msgid "Total amount of sales under the Declaration of Intent of this document"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__invoiced
msgid "Total amount of sales under this Declaration of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_not_yet_invoiced
msgid ""
"Total under the Declaration of Intent of this document that can still be "
"invoiced"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__activity_exception_decoration
msgid "Type of the exception activity on record."
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_bank_statement_line__l10n_it_edi_doi_use
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_move__l10n_it_edi_doi_use
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_account_payment__l10n_it_edi_doi_use
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_sale_order__l10n_it_edi_doi_use
msgid "Use Declaration of Intent"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.view_l10n_it_edi_doi_form
msgid "Validate"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,field_description:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__website_message_ids
msgid "Website Messages"
msgstr ""
#. module: l10n_it_edi_doi
#: model:ir.model.fields,help:l10n_it_edi_doi.field_l10n_it_edi_doi_declaration_of_intent__website_message_ids
msgid "Website communication history"
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/declaration_of_intent.py:0
#, python-format
msgid ""
"You cannot delete Declarations of Intents that are already used on at least "
"one Invoice or Sales Order."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_fiscal_position.py:0
#, python-format
msgid ""
"You cannot delete the special fiscal position for Declarations of Intent."
msgstr ""
#. module: l10n_it_edi_doi
#. odoo-python
#: code:addons/l10n_it_edi_doi/models/account_tax.py:0
#, python-format
msgid "You cannot delete the special tax for Declarations of Intent."
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_invoice_document
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_saleorder_document
msgid "Your Declaration of Intent number"
msgstr ""
#. module: l10n_it_edi_doi
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_invoice_document
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_doi.report_saleorder_document
msgid "from"
msgstr ""

View file

@ -0,0 +1,10 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account_chart_template
from . import account_fiscal_position
from . import account_move
from . import account_tax
from . import declaration_of_intent
from . import res_company
from . import res_partner
from . import sale_order
from . import sale_order_line

View file

@ -0,0 +1,23 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class AccountChartTemplate(models.AbstractModel):
_inherit = 'account.chart.template'
def _load(self, company):
res = super()._load(company)
if self == self.env.ref('l10n_it.l10n_it_chart_template_generic'):
doi_tax = self.env.ref(f'l10n_it_edi_doi.{company.id}_00di', raise_if_not_found=False)
if doi_tax:
doi_tax.write({
'l10n_it_has_exoneration': True,
'l10n_it_kind_exoneration': 'N3.5',
'l10n_it_law_reference': 'art. 8, c. 1, lett. c) D.P.R. 633/1972',
})
company.l10n_it_edi_doi_tax_id = doi_tax
doi_fiscal_position = self.env.ref(f'l10n_it_edi_doi.{company.id}_declaration_of_intent_fiscal_position', raise_if_not_found=False)
if doi_fiscal_position:
company.l10n_it_edi_doi_fiscal_position_id = doi_fiscal_position
return res

View file

@ -0,0 +1,14 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models, _
from odoo.exceptions import UserError
class AccountFiscalPosition(models.Model):
_inherit = 'account.fiscal.position'
@api.ondelete(at_uninstall=False)
def _never_unlink_declaration_of_intent_fiscal_position(self):
for fiscal_position in self:
if fiscal_position == fiscal_position.company_id.l10n_it_edi_doi_fiscal_position_id:
raise UserError(_('You cannot delete the special fiscal position for Declarations of Intent.'))

View file

@ -0,0 +1,212 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class AccountMove(models.Model):
_inherit = 'account.move'
l10n_it_edi_doi_date = fields.Date(
string="Date on which Declaration of Intent is applied",
compute='_compute_l10n_it_edi_doi_date',
)
l10n_it_edi_doi_use = fields.Boolean(
string="Use Declaration of Intent",
compute='_compute_l10n_it_edi_doi_use',
)
l10n_it_edi_doi_id = fields.Many2one(
string="Declaration of Intent",
compute='_compute_l10n_it_edi_doi_id',
store=True,
readonly=False,
precompute=True,
comodel_name='l10n_it_edi_doi.declaration_of_intent',
)
l10n_it_edi_doi_amount = fields.Monetary(
string='Declaration of Intent Amount',
compute='_compute_l10n_it_edi_doi_amount',
store=True,
readonly=True,
help="Total amount of sales under the Declaration of Intent of this document",
)
l10n_it_edi_doi_warning = fields.Text(
string="Declaration of Intent Threshold Warning",
compute='_compute_l10n_it_edi_doi_warning',
)
@api.depends('invoice_date')
def _compute_l10n_it_edi_doi_date(self):
for move in self:
move.l10n_it_edi_doi_date = move.invoice_date or fields.Date.context_today(self)
@api.depends('l10n_it_edi_doi_id', 'country_code', 'move_type')
def _compute_l10n_it_edi_doi_use(self):
sale_types = self.env['account.move'].get_sale_types()
for move in self:
move.l10n_it_edi_doi_use = (
move.l10n_it_edi_doi_id
or (move.country_code == "IT" and move.move_type in sale_types)
)
@api.depends('company_id', 'partner_id.commercial_partner_id', 'l10n_it_edi_doi_date', 'currency_id')
def _compute_l10n_it_edi_doi_id(self):
for move in self:
if not move.l10n_it_edi_doi_use or move.state != 'draft' and not move.l10n_it_edi_doi_id:
move.l10n_it_edi_doi_id = False
continue
partner = move.partner_id.commercial_partner_id
# Avoid a query or changing a manually set declaration of intent
# (if the declaration is still valid).
validity_warnings = move.l10n_it_edi_doi_id._get_validity_warnings(
move.company_id, partner, move.currency_id, move.l10n_it_edi_doi_date
)
if move.l10n_it_edi_doi_id and not validity_warnings:
continue
declaration = self.env['l10n_it_edi_doi.declaration_of_intent']\
._fetch_valid_declaration_of_intent(move.company_id, partner, move.currency_id, move.l10n_it_edi_doi_date)
move.l10n_it_edi_doi_id = declaration
@api.depends('l10n_it_edi_doi_id', 'tax_totals', 'move_type')
def _compute_l10n_it_edi_doi_amount(self):
"""
Consider all the lines in self that belong to declaration of intent `declaration`
and have the special declaration of intent tax applied.
This function computes the signed sum of the price_total of all those lines
(the tax amount of the lines is always 0).
The direction_sign determines the sign: 1 (-1) for inbound (outbound) types.
"""
for move in self:
tax = move.company_id.l10n_it_edi_doi_tax_id
if not tax or not move.l10n_it_edi_doi_id:
move.l10n_it_edi_doi_amount = 0
continue
declaration_lines = move.invoice_line_ids.filtered(
# The declaration tax cannot be used with other taxes on a single line
# (checked in `_post`)
lambda line: line.tax_ids.ids == tax.ids
)
move.l10n_it_edi_doi_amount = sum(declaration_lines.mapped('price_total')) * -move.direction_sign
@api.depends('l10n_it_edi_doi_id', 'l10n_it_edi_doi_amount', 'state')
def _compute_l10n_it_edi_doi_warning(self):
for move in self:
move.l10n_it_edi_doi_warning = ''
declaration = move.l10n_it_edi_doi_id
show_warning = (
declaration
and move.is_sale_document(include_receipts=False)
and move.state != 'cancel'
)
if not show_warning:
continue
declaration_invoiced = declaration.invoiced
declaration_not_yet_invoiced = declaration.not_yet_invoiced
if move.state != 'posted': # exactly the 'posted' invoices are included in declaration.invoiced
# Here we replicate what would happen when posting the invoice.
# Note: lines manually added to a move linked to a sales order are not added to the sales order
declaration_invoiced += move.l10n_it_edi_doi_amount
additional_invoiced_qty = {}
linked_orders = self.env['sale.order']
for invoice_line in move.invoice_line_ids:
for sale_line in invoice_line.sale_line_ids:
order = sale_line.order_id
if order.l10n_it_edi_doi_id == declaration:
linked_orders |= order
qty_invoiced = invoice_line.product_uom_id._compute_quantity(invoice_line.quantity, sale_line.product_uom) * -move.direction_sign
sale_line_id = sale_line.ids[0] # do not just use `id` in case of NewId
additional_invoiced_qty[sale_line_id] = additional_invoiced_qty.get(sale_line_id, 0) + qty_invoiced
for order in linked_orders:
not_yet_invoiced = order.l10n_it_edi_doi_not_yet_invoiced
not_yet_invoiced_after_posting = order._l10n_it_edi_doi_get_amount_not_yet_invoiced(
declaration,
additional_invoiced_qty=additional_invoiced_qty,
)
declaration_not_yet_invoiced -= not_yet_invoiced - not_yet_invoiced_after_posting
validity_warnings = declaration._get_validity_warnings(
move.company_id, move.commercial_partner_id, move.currency_id, move.l10n_it_edi_doi_date,
invoiced_amount=declaration_invoiced,
)
threshold_warning = declaration._build_threshold_warning_message(declaration_invoiced, declaration_not_yet_invoiced)
move.l10n_it_edi_doi_warning = '{}\n\n{}'.format('\n'.join(validity_warnings), threshold_warning).strip()
@api.depends('l10n_it_edi_doi_id')
def _compute_fiscal_position_id(self):
super()._compute_fiscal_position_id()
for move in self:
declaration_fiscal_position = move.company_id.l10n_it_edi_doi_fiscal_position_id
if declaration_fiscal_position and move.l10n_it_edi_doi_id:
move.fiscal_position_id = declaration_fiscal_position
def copy_data(self, default=None):
data_list = super().copy_data(default)
for move, data in zip(self, data_list):
date = fields.Date.context_today(self)
validity_warnings = move.l10n_it_edi_doi_id._get_validity_warnings(
move.company_id, move.commercial_partner_id, move.currency_id, date,
only_blocking=True,
)
if validity_warnings:
del data['l10n_it_edi_doi_id']
del data['fiscal_position_id']
return data_list
@api.constrains('l10n_it_edi_doi_id')
def _check_l10n_it_edi_doi_id(self):
for move in self:
validity_errors = move.l10n_it_edi_doi_id._get_validity_errors(
move.company_id, move.partner_id.commercial_partner_id, move.currency_id
)
if validity_errors:
raise UserError('\n'.join(validity_errors))
def _post(self, soft=True):
errors = []
for move in self:
declaration = move.l10n_it_edi_doi_id
if declaration:
validity_warnings = declaration._get_validity_warnings(
move.company_id, move.commercial_partner_id, move.currency_id, move.l10n_it_edi_doi_date,
invoiced_amount=move.l10n_it_edi_doi_amount,
only_blocking=True
)
errors.extend(validity_warnings)
declaration_of_intent_tax = move.company_id.l10n_it_edi_doi_tax_id
if not declaration_of_intent_tax:
continue
declaration_lines = move.invoice_line_ids.filtered(
lambda line: declaration_of_intent_tax in line.tax_ids
)
if declaration_lines and not declaration:
errors.append(_('Given the tax %s is applied, there should be a Declaration of Intent selected.',
declaration_of_intent_tax.name))
if any(line.tax_ids != declaration_of_intent_tax for line in declaration_lines):
errors.append(_('A line using tax %s should not contain any other taxes',
declaration_of_intent_tax.name))
if errors:
raise UserError('\n'.join(errors))
return super()._post(soft)
def action_open_declaration_of_intent(self):
self.ensure_one()
return {
'name': _("Declaration of Intent for %s", self.display_name),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'l10n_it_edi_doi.declaration_of_intent',
'res_id': self.l10n_it_edi_doi_id.id,
}

View file

@ -0,0 +1,12 @@
from odoo import api, models, _
from odoo.exceptions import UserError
class AccountTax(models.Model):
_inherit = 'account.tax'
@api.ondelete(at_uninstall=False)
def _never_unlink_declaration_of_intent_tax(self):
for tax in self:
if tax == tax.company_id.l10n_it_edi_doi_tax_id:
raise UserError(_('You cannot delete the special tax for Declarations of Intent.'))

View file

@ -0,0 +1,311 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools.misc import formatLang
class L10nItDeclarationOfIntent(models.Model):
_name = "l10n_it_edi_doi.declaration_of_intent"
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = "Declaration of Intent"
_order = 'protocol_number_part1, protocol_number_part2'
state = fields.Selection([
('draft', 'Draft'),
('active', 'Active'),
('revoked', 'Revoked'),
('terminated', 'Terminated'),
],
string="State",
tracking=True,
default='draft',
required=True,
readonly=True,
help="The state of this Declaration of Intent. \n"
"- 'Draft' means that the Declaration of Intent still needs to be confirmed before being usable. \n"
"- 'Active' means that the Declaration of Intent is usable. \n"
"- 'Terminated' designates that the Declaration of Intent has been marked as not to use anymore without invalidating usages of it. \n"
"- 'Revoked' means the Declaration of Intent should not have been used. You will probably need to revert previous usages of it, if any.\n")
company_id = fields.Many2one(
comodel_name='res.company',
string='Company',
index=True,
required=True,
default=lambda self: self.env.company,
)
partner_id = fields.Many2one(
comodel_name='res.partner',
string='Partner',
index=True,
required=True,
domain="['|', ('is_company', '=', True), ('parent_id', '=', False)]",
)
currency_id = fields.Many2one(
comodel_name='res.currency',
string='Currency',
default=lambda self: self.env.ref('base.EUR', raise_if_not_found=False).id,
required=True,
readonly=True,
)
issue_date = fields.Date(
string='Date of Issue',
required=True,
copy=False,
default=fields.Date.context_today,
help="Date on which the Declaration of Intent was issued",
)
start_date = fields.Date(
string='Start Date',
required=True,
copy=False,
help="First date on which the Declaration of Intent is valid",
)
end_date = fields.Date(
string='End Date',
required=True,
copy=False,
help="Last date on which the Declaration of Intent is valid",
)
threshold = fields.Monetary(
string='Threshold',
required=True,
help="Total amount of allowed sales without VAT under this Declaration of Intent",
)
invoiced = fields.Monetary(
string='Invoiced',
compute='_compute_invoiced',
store=True,
readonly=True,
help="Total amount of sales under this Declaration of Intent",
)
not_yet_invoiced = fields.Monetary(
string='Not Yet Invoiced',
compute='_compute_not_yet_invoiced',
store=True,
readonly=True,
help="Total amount of planned sales under this Declaration of Intent (i.e. current quotation and sales orders) that can still be invoiced",
)
remaining = fields.Monetary(
string='Remaining',
compute='_compute_remaining',
store=True,
readonly=True,
help="Remaining amount after deduction of the Invoiced and Not Yet Invoiced amounts.",
)
protocol_number_part1 = fields.Char(
string='Protocol 1',
required=True,
readonly=False,
copy=False,
)
protocol_number_part2 = fields.Char(
string='Protocol 2',
required=True,
readonly=False,
copy=False,
)
invoice_ids = fields.One2many(
'account.move',
'l10n_it_edi_doi_id',
string="Invoices / Refunds",
copy=False,
readonly=True,
)
sale_order_ids = fields.One2many(
'sale.order',
'l10n_it_edi_doi_id',
string="Sales Orders / Quotations",
copy=False,
readonly=True,
)
_sql_constraints = [
('protocol_number_unique',
'unique(protocol_number_part1, protocol_number_part2)',
"The Protocol Number of a Declaration of Intent must be unique! Please choose another one."),
('threshold_positive',
'CHECK(threshold > 0)',
"The Threshold of a Declaration of Intent must be positive."),
]
def name_get(self):
return [(record.id, f"{record.protocol_number_part1}-{record.protocol_number_part2}") for record in self]
@api.depends('invoice_ids', 'invoice_ids.state', 'invoice_ids.l10n_it_edi_doi_amount')
def _compute_invoiced(self):
for declaration in self:
relevant_invoices = declaration.invoice_ids.filtered(
lambda invoice: invoice.state == 'posted'
)
declaration.invoiced = sum(relevant_invoices.mapped('l10n_it_edi_doi_amount'))
@api.depends('sale_order_ids', 'sale_order_ids.state', 'sale_order_ids.l10n_it_edi_doi_not_yet_invoiced')
def _compute_not_yet_invoiced(self):
for declaration in self:
relevant_orders = declaration.sale_order_ids.filtered(
lambda order: order.state == 'sale'
)
declaration.not_yet_invoiced = sum(relevant_orders.mapped('l10n_it_edi_doi_not_yet_invoiced'))
@api.depends('threshold', 'not_yet_invoiced', 'invoiced')
def _compute_remaining(self):
for record in self:
record.remaining = record.threshold - record.invoiced - record.not_yet_invoiced
def _build_threshold_warning_message(self, invoiced, not_yet_invoiced):
"""
Build a warning message that will be displayed in a yellow banner on top of a document
if the `remaining` of the Declaration of Intent is less than 0 when including the document
or the Declaration of Intent is revoked
:param float invoiced: The `declaration.invoiced` amount when including the document.
:param float not_yet_invoiced: The `declaration.not_yet_invoiced` amount when including the document.
:return str: The warning message to be shown.
"""
self.ensure_one()
updated_remaining = self.threshold - invoiced - not_yet_invoiced
if self.currency_id.compare_amounts(updated_remaining, 0) >= 0:
return ''
return _(
'Pay attention, the threshold of your Declaration of Intent %s of %s is exceeded by %s, this document included.\n'
'Invoiced: %s; Not Yet Invoiced: %s',
self.display_name,
formatLang(self.env, self.threshold, currency_obj=self.currency_id),
formatLang(self.env, - updated_remaining, currency_obj=self.currency_id),
formatLang(self.env, invoiced, currency_obj=self.currency_id),
formatLang(self.env, not_yet_invoiced, currency_obj=self.currency_id),
)
def _get_validity_errors(self, company, partner, currency):
"""
Check whether all declarations of intent in self are valid for the specified `company`, `partner`, `date` and `currency'.
Violating these constraints leads to errors in the feature. They should not be ignored.
Return all errors as a list of strings.
"""
errors = []
for declaration in self:
if not company or declaration.company_id != company:
errors.append(_("The Declaration of Intent belongs to company %s, not %s.",
declaration.company_id.name, company.name))
if not currency or declaration.currency_id != currency:
errors.append(_("The Declaration of Intent uses currency %s, not %s.",
declaration.currency_id.name, currency.name))
if not partner or declaration.partner_id != partner.commercial_partner_id:
errors.append(_("The Declaration of Intent belongs to partner %s, not %s.",
declaration.partner_id.name, partner.commercial_partner_id.name))
return errors
def _get_validity_warnings(self, company, partner, currency, date, invoiced_amount=0, only_blocking=False, sales_order=False):
"""
Check whether all declarations of intent in self are valid for the specified `company`, `partner`, `date` and `currency'.
The checks for `date` and state of the declaration (except draft) are not considered blocking in case `invoiced_amount` is not positive.
All other checks are considered blocking (prevent posting).
Includes all checks from `_get_validity_errors`.
The checks are different for invoices and sales orders (toggled via kwarg `sales_order`).
I.e. we do not care about the date for sales orders.
Return all errors as a list of strings.
"""
errors = []
for declaration in self:
errors.extend(declaration._get_validity_errors(company, partner, currency))
if declaration.state == 'draft':
errors.append(_("The Declaration of Intent is in draft."))
if declaration.currency_id.compare_amounts(invoiced_amount, 0) > 0 or not only_blocking:
if declaration.state != 'active':
errors.append(_("The Declaration of Intent must be active."))
if not sales_order and (not date or declaration.start_date > date or declaration.end_date < date):
errors.append(_("The Declaration of Intent is valid from %s to %s, not on %s.",
declaration.start_date, declaration.end_date, date))
return errors
@api.model
def _fetch_valid_declaration_of_intent(self, company, partner, currency, date):
"""
Fetch a declaration of intent that is valid for the specified `company`, `partner`, `date` and `currency`
and has not reached the threshold yet.
"""
return self.search([
('state', '=', 'active'),
('company_id', '=', company.id),
('currency_id', '=', currency.id),
('partner_id', '=', partner.commercial_partner_id.id),
('start_date', '<=', date),
('end_date', '>=', date),
('remaining', '>', 0),
], limit=1)
@api.ondelete(at_uninstall=False)
def _unlink_except_linked_to_document(self):
if self.invoice_ids or self.sale_order_ids:
raise UserError(_('You cannot delete Declarations of Intents that are already used on at least one Invoice or Sales Order.'))
def action_validate(self):
""" Move a 'draft' Declaration of Intent to 'active'."""
for record in self:
if record.state == 'draft':
record.state = 'active'
def action_reset_to_draft(self):
""" Resets an 'active' Declaration of Intent back to 'draft'."""
for record in self:
if record.state == 'active':
record.state = 'draft'
def action_reactivate(self):
""" Resets a not 'active' Declaration of Intent back to 'active'."""
for record in self:
if record.state != 'active':
record.state = 'active'
def action_revoke(self):
""" Called by the 'revoke' button of the form view."""
for record in self:
record.state = 'revoked'
def action_terminate(self):
""" Called by the 'terminated' button of the form view."""
for record in self:
if record.state != 'revoked':
record.state = 'terminated'
def action_open_sale_order_ids(self):
self.ensure_one()
return {
'name': _("Sales Orders using Declaration of Intent %s", self.display_name),
'type': 'ir.actions.act_window',
'res_model': 'sale.order',
'domain': [('id', 'in', self.sale_order_ids.ids)],
'views': [(self.env.ref('l10n_it_edi_doi.view_quotation_tree').id, 'tree'), (False, 'form')],
'search_view_id': [self.env.ref('sale.sale_order_view_search_inherit_quotation').id],
'context': {
'search_default_sales': 1,
},
}
def action_open_invoice_ids(self):
self.ensure_one()
return {
'name': _("Invoices using Declaration of Intent %s", self.display_name),
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'domain': [('id', 'in', self.invoice_ids.ids)],
'views': [(self.env.ref('l10n_it_edi_doi.view_move_tree').id, 'tree'), (False, 'form')],
'search_view_id': [self.env.ref('account.view_account_invoice_filter').id],
'context': {
'search_default_posted': 1,
},
}

View file

@ -0,0 +1,17 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class ResCompany(models.Model):
_inherit = 'res.company'
l10n_it_edi_doi_tax_id = fields.Many2one(
comodel_name='account.tax',
string="Declaration of Intent Tax",
)
l10n_it_edi_doi_fiscal_position_id = fields.Many2one(
comodel_name='account.fiscal.position',
string="Declaration of Intent Fiscal Position",
)

View file

@ -0,0 +1,28 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, _
class ResPartner(models.Model):
_inherit = 'res.partner'
l10n_it_edi_doi_ids = fields.One2many(
'l10n_it_edi_doi.declaration_of_intent',
'partner_id',
string="Available Declarations of Intent of this partner",
domain=lambda self: [('company_id', '=', self.env.company.id)],
)
def l10n_it_edi_doi_action_open_declarations(self):
self.ensure_one()
return {
'name': _("Declaration of Intent of %s", self.display_name),
'type': 'ir.actions.act_window',
'res_model': 'l10n_it_edi_doi.declaration_of_intent',
'domain': [('partner_id', '=', self.commercial_partner_id.id)],
'views': [(self.env.ref('l10n_it_edi_doi.view_l10n_it_edi_doi_tree').id, 'tree'),
(self.env.ref('l10n_it_edi_doi.view_l10n_it_edi_doi_form').id, 'form')],
'context': {
'default_partner_id': self.id,
},
}

View file

@ -0,0 +1,256 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
class SaleOrder(models.Model):
_inherit = 'sale.order'
l10n_it_edi_doi_date = fields.Date(
string="Date on which Declaration of Intent is applied",
compute='_compute_l10n_it_edi_doi_date',
)
l10n_it_edi_doi_use = fields.Boolean(
string="Use Declaration of Intent",
compute='_compute_l10n_it_edi_doi_use',
)
l10n_it_edi_doi_id = fields.Many2one(
string="Declaration of Intent",
compute='_compute_l10n_it_edi_doi_id',
store=True,
readonly=False,
precompute=True,
comodel_name='l10n_it_edi_doi.declaration_of_intent',
)
l10n_it_edi_doi_not_yet_invoiced = fields.Monetary(
string='Declaration of Intent Amount Not Yet Invoiced',
compute='_compute_l10n_it_edi_doi_not_yet_invoiced',
store=True,
readonly=True,
help="Total under the Declaration of Intent of this document that can still be invoiced",
)
l10n_it_edi_doi_warning = fields.Text(
string="Declaration of Intent Threshold Warning",
compute='_compute_l10n_it_edi_doi_warning',
)
@api.depends('date_order')
def _compute_l10n_it_edi_doi_date(self):
for order in self:
order.l10n_it_edi_doi_date = order.date_order or fields.Date.context_today(self)
@api.depends('l10n_it_edi_doi_id', 'country_code')
def _compute_l10n_it_edi_doi_use(self):
for order in self:
order.l10n_it_edi_doi_use = order.l10n_it_edi_doi_id \
or order.country_code == "IT"
@api.depends('company_id', 'partner_id.commercial_partner_id', 'l10n_it_edi_doi_date', 'currency_id')
def _compute_l10n_it_edi_doi_id(self):
for order in self:
if not order.l10n_it_edi_doi_use or order.state != 'draft' and not order.l10n_it_edi_doi_id:
order.l10n_it_edi_doi_id = False
continue
partner = order.partner_id.commercial_partner_id
# Avoid a query or changing a manually set declaration of intent
# (if the declaration is still valid).
validity_warnings = order.l10n_it_edi_doi_id._get_validity_warnings(
order.company_id, partner, order.currency_id, order.l10n_it_edi_doi_date, sales_order=True
)
if order.l10n_it_edi_doi_id and not validity_warnings:
continue
declaration = self.env['l10n_it_edi_doi.declaration_of_intent']\
._fetch_valid_declaration_of_intent(order.company_id, partner, order.currency_id, order.l10n_it_edi_doi_date)
order.l10n_it_edi_doi_id = declaration
@api.depends('l10n_it_edi_doi_id', 'tax_totals', 'order_line', 'order_line.qty_invoiced_posted')
def _compute_l10n_it_edi_doi_not_yet_invoiced(self):
for order in self:
declaration = order.l10n_it_edi_doi_id
order.l10n_it_edi_doi_not_yet_invoiced = order._l10n_it_edi_doi_get_amount_not_yet_invoiced(declaration)
@api.depends('l10n_it_edi_doi_id', 'l10n_it_edi_doi_id.remaining', 'state', 'tax_totals')
def _compute_l10n_it_edi_doi_warning(self):
for order in self:
order.l10n_it_edi_doi_warning = ''
declaration = order.l10n_it_edi_doi_id
show_warning = declaration and order.state != 'cancelled'
if not show_warning:
continue
declaration_not_yet_invoiced = declaration.not_yet_invoiced
# Exactly the confirmed SOs (state == 'sale') are included in `declaration.not_yet_invoiced`.
# The amount of `declaration.not_yet_invoiced` may change due to confirming or saving `order`.
# * An unconfirmed order is being confirmed:
# We have to add the order amount to `declaration.not_yet_invoiced`.
# * A confirmed SO is being edited:
# The field `declaration.not_yet_invoiced` will be updated when saving.
# But we want to update the warning during the editing already (before saving).
# We first have to remove the "old amount" from `declaration.not_yet_invoiced`
# before adding the current amount.
if order.state == 'sale':
old_order_state = order._origin
declaration_not_yet_invoiced -= old_order_state.l10n_it_edi_doi_not_yet_invoiced
declaration_not_yet_invoiced += order.l10n_it_edi_doi_not_yet_invoiced
validity_warnings = declaration._get_validity_warnings(
order.company_id, order.partner_id.commercial_partner_id, order.currency_id, order.l10n_it_edi_doi_date,
sales_order=True
)
threshold_warning = declaration._build_threshold_warning_message(declaration.invoiced, declaration_not_yet_invoiced)
order.l10n_it_edi_doi_warning = '{}\n\n{}'.format('\n'.join(validity_warnings), threshold_warning).strip()
@api.depends('l10n_it_edi_doi_id')
def _compute_fiscal_position_id(self):
super()._compute_fiscal_position_id()
for order in self:
declaration_fiscal_position = order.company_id.l10n_it_edi_doi_fiscal_position_id
if declaration_fiscal_position and order.l10n_it_edi_doi_id:
order.fiscal_position_id = declaration_fiscal_position
def _prepare_invoice(self):
"""
Prepare the dict of values to create the new invoice for a sales order. This method may be
overridden to implement custom invoice generation (making sure to call super() to establish
a clean extension chain).
"""
vals = super()._prepare_invoice()
declaration = self.l10n_it_edi_doi_id
if declaration:
date = fields.Date.context_today(self)
validity_warnings = declaration._get_validity_warnings(
self.company_id, self.partner_id.commercial_partner_id, self.currency_id, date, sales_order=True
)
if not validity_warnings:
vals['l10n_it_edi_doi_id'] = declaration.id
return vals
def copy_data(self, default=None):
data_list = super().copy_data(default)
for order, data in zip(self, data_list):
partner = order.partner_id.commercial_partner_id
date = fields.Date.context_today(self)
if order.l10n_it_edi_doi_id._get_validity_warnings(order.company_id, partner, order.currency_id, date, sales_order=True):
del data['l10n_it_edi_doi_id']
del data['fiscal_position_id']
return data_list
def _l10n_it_edi_doi_check_configuration(self):
"""
Raise a UserError in case the configuration of the sale order is invalid.
"""
errors = []
for order in self:
declaration = order.l10n_it_edi_doi_id
if declaration:
validity_warnings = declaration._get_validity_warnings(
order.company_id, order.partner_id.commercial_partner_id, order.currency_id, order.l10n_it_edi_doi_date,
only_blocking=True, sales_order=True,
)
errors.extend(validity_warnings)
declaration_of_intent_tax = order.company_id.l10n_it_edi_doi_tax_id
if not declaration_of_intent_tax:
continue
declaration_tax_lines = order.order_line.filtered(
lambda line: declaration_of_intent_tax in line.tax_id
)
if declaration_tax_lines and not order.l10n_it_edi_doi_id:
errors.append(_('Given the tax %s is applied, there should be a Declaration of Intent selected.',
declaration_of_intent_tax.name))
if any(line.tax_id != declaration_of_intent_tax for line in declaration_tax_lines):
errors.append(_('A line using tax %s should not contain any other taxes',
declaration_of_intent_tax.name))
if errors:
raise UserError('\n'.join(errors))
def action_quotation_send(self):
self._l10n_it_edi_doi_check_configuration()
return super().action_quotation_send()
def action_quotation_sent(self):
self._l10n_it_edi_doi_check_configuration()
return super().action_quotation_sent()
def action_confirm(self):
self._l10n_it_edi_doi_check_configuration()
return super().action_confirm()
@api.constrains('l10n_it_edi_doi_id')
def _check_l10n_it_edi_doi_id(self):
for order in self:
declaration = order.l10n_it_edi_doi_id
if not declaration:
return
partner = order.partner_id.commercial_partner_id
errors = declaration._get_validity_warnings(
order.company_id, partner, order.currency_id, order.l10n_it_edi_doi_date, only_blocking=True, sales_order=True
)
if errors:
raise ValidationError('\n'.join(errors))
def action_open_declaration_of_intent(self):
self.ensure_one()
return {
'name': _("Declaration of Intent for %s", self.display_name),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'l10n_it_edi_doi.declaration_of_intent',
'res_id': self.l10n_it_edi_doi_id.id,
}
def _l10n_it_edi_doi_get_amount_not_yet_invoiced(self, declaration, additional_invoiced_qty=None):
"""
Consider sales orders in self that use declaration of intent `declaration`.
For each sales order we compute the amount that is tax exempt due to the declaration of intent
(line has special declaration of intent tax applied) but not yet invoiced.
For each line of the SO we i.e. use the not yet invoiced quantity to compute this amount.
The aforementioned quantity is computed from field `qty_invoiced_posted` and parameter `additional_invoiced_qty`
Return the sum of all these amounts on the SOs.
:param declaration: We only consider sales orders using Declaration of Intent `declaration`.
:param additional_invoiced_qty: Dictionary (sale order line id -> float)
The float represents additional invoiced amount qty for the sale order.
This can i.e. be used to simulate posting an already linked invoice.
"""
if not declaration:
return 0
if additional_invoiced_qty is None:
additional_invoiced_qty = {}
tax = declaration.company_id.l10n_it_edi_doi_tax_id
if not tax:
return 0
not_yet_invoiced = 0
for order in self:
if declaration != order.l10n_it_edi_doi_id:
continue
order_lines = order.order_line.filtered(
# The declaration tax cannot be used with other taxes on a single line
# (checked in `action_confirm`)
lambda line: line.tax_id.ids == tax.ids
)
order_not_yet_invoiced = 0
for line in order_lines:
price_reduce = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
qty_invoiced = line.qty_invoiced_posted
if line.ids and additional_invoiced_qty:
qty_invoiced += additional_invoiced_qty.get(line.ids[0], 0)
qty_to_invoice = line.product_uom_qty - qty_invoiced
order_not_yet_invoiced += price_reduce * qty_to_invoice
if declaration.currency_id.compare_amounts(order_not_yet_invoiced, 0) > 0:
not_yet_invoiced += order_not_yet_invoiced
return not_yet_invoiced

View file

@ -0,0 +1,31 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
qty_invoiced_posted = fields.Float(
string="Invoiced Quantity (posted)",
compute='_compute_qty_invoiced_posted',
digits='Product Unit of Measure',
store=True,
)
@api.depends('invoice_lines.move_id.state', 'invoice_lines.quantity')
def _compute_qty_invoiced_posted(self):
"""
This method is almost identical to '_compute_qty_invoiced()'. The only difference lies in the fact that
for accounting purposes, we only want the quantities of the posted invoices.
We need a dedicated computation because the triggers are different and could lead to incorrect values for
'qty_invoiced' when computed together.
"""
for line in self:
qty_invoiced_posted = 0.0
for invoice_line in line._get_invoice_lines():
if invoice_line.move_id.state == 'posted' or invoice_line.move_id.payment_state == 'invoicing_legacy':
qty_unsigned = invoice_line.product_uom_id._compute_quantity(invoice_line.quantity, line.product_uom)
qty_signed = qty_unsigned * -invoice_line.move_id.direction_sign
qty_invoiced_posted += qty_signed
line.qty_invoiced_posted = qty_invoiced_posted

View file

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
l10n_it_edi_doi.access_l10n_it_edi_doi_declaration_of_intent_readonly,access_l10n_it_edi_doi_declaration_of_intent,l10n_it_edi_doi.model_l10n_it_edi_doi_declaration_of_intent,account.group_account_readonly,1,0,0,0
l10n_it_edi_doi.access_l10n_it_edi_doi_declaration_of_intent_invoice,access_l10n_it_edi_doi_declaration_of_intent,l10n_it_edi_doi.model_l10n_it_edi_doi_declaration_of_intent,account.group_account_invoice,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 l10n_it_edi_doi.access_l10n_it_edi_doi_declaration_of_intent_readonly access_l10n_it_edi_doi_declaration_of_intent l10n_it_edi_doi.model_l10n_it_edi_doi_declaration_of_intent account.group_account_readonly 1 0 0 0
3 l10n_it_edi_doi.access_l10n_it_edi_doi_declaration_of_intent_invoice access_l10n_it_edi_doi_declaration_of_intent l10n_it_edi_doi.model_l10n_it_edi_doi_declaration_of_intent account.group_account_invoice 1 1 1 1

View file

@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import common
from . import test_amounts_and_warnings

View file

@ -0,0 +1,32 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import tagged
from odoo.addons.l10n_it_edi.tests.common import TestItEdi
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestItEdiDoi(TestItEdi):
@classmethod
def setUpClass(cls, chart_template_ref='l10n_it.l10n_it_chart_template_generic'):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.declaration_1000 = cls.env['l10n_it_edi_doi.declaration_of_intent'].create({
'company_id': cls.company.id,
'partner_id': cls.italian_partner_a.id,
'issue_date': '2019-01-01',
'start_date': '2019-01-01',
'end_date': '2019-12-31',
'threshold': 1000,
'protocol_number_part1': 'test 2019',
'protocol_number_part2': 'threshold 1000',
})
cls.declaration_1000.action_validate()
cls.product_1 = cls.env['product.product'].create([{'name': 'test product 1'}])
cls.pricelist = cls.env['product.pricelist'].with_company(cls.company).create({
'name': 'EUR pricelist',
'currency_id': cls.company.currency_id.id,
'company_id': False,
})

View file

@ -0,0 +1,531 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from freezegun import freeze_time
from odoo import Command
from odoo.addons.l10n_it_edi_doi.tests.common import TestItEdiDoi
from odoo.tests import tagged, Form
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestItEdiDoiRemaining(TestItEdiDoi):
def create_invoice(self, declaration, invoice_line_vals):
return self.env['account.move'].create({
'move_type': 'out_invoice',
'company_id': self.company.id,
'partner_id': declaration.partner_id.id,
'invoice_date': declaration.start_date,
'l10n_it_edi_doi_id': declaration.id,
'invoice_line_ids': invoice_line_vals,
})
def get_sale_order_vals(self, declaration, order_line_vals):
return {
'company_id': self.company.id,
'partner_id': declaration.partner_id.id,
'date_order': declaration.start_date,
'pricelist_id': self.pricelist.id,
'l10n_it_edi_doi_id': declaration.id,
'order_line': order_line_vals,
}
def create_sale_order(self, declaration, order_line_vals):
sale_order_vals = self.get_sale_order_vals(declaration, order_line_vals)
return self.env['sale.order'].create(sale_order_vals)
def test_invoice_line_edit(self):
"""
Ensure the warnings are computed correctly when editing line values on an invoice.
"""
declaration = self.declaration_1000
declaration_tax = declaration.company_id.l10n_it_edi_doi_tax_id
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 0.0,
'remaining': 1000.0,
}])
invoice = self.create_invoice(declaration, [
Command.create({
'name': 'declaration line',
'quantity': 2,
'price_unit': 1000.0, # == declaration.threshold
'tax_ids': [Command.set(declaration_tax.ids)],
}),
])
with Form(invoice) as invoice_form:
with invoice_form.invoice_line_ids.edit(0) as line_form:
line_form.price_unit = 2000
line_form.save()
self.assertEqual(
invoice_form.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 3,000.00\xa0€, this document included.\n"
"Invoiced: 4,000.00\xa0€; Not Yet Invoiced: 0.00\xa0"
)
with invoice_form.invoice_line_ids.edit(0) as line_form:
line_form.quantity = 1
line_form.save()
self.assertEqual(
invoice_form.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 1,000.00\xa0€, this document included.\n"
"Invoiced: 2,000.00\xa0€; Not Yet Invoiced: 0.00\xa0"
)
def test_sale_order_line_edit(self):
"""
Ensure the warnings are computed correctly when editing line values on a quotation or sale order.
"""
declaration = self.declaration_1000
declaration_tax = declaration.company_id.l10n_it_edi_doi_tax_id
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 0.0,
'remaining': 1000.0,
}])
order = self.create_sale_order(declaration, [
Command.create({
'name': 'declaration line',
'product_id': self.product_1.id,
'price_unit': 1000.0, # == declaration.threshold
'product_uom_qty': 2,
'tax_id': [Command.set(declaration_tax.ids)],
}),
])
with Form(order) as order_form:
with order_form.order_line.edit(0) as line_form:
line_form.price_unit = 2000
line_form.save()
self.assertEqual(
order_form.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 3,000.00\xa0€, this document included.\n"
"Invoiced: 0.00\xa0€; Not Yet Invoiced: 4,000.00\xa0"
)
with order_form.order_line.edit(0) as line_form:
line_form.product_uom_qty = 1
line_form.price_unit = 2000
line_form.save()
self.assertEqual(
order_form.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 1,000.00\xa0€, this document included.\n"
"Invoiced: 0.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
order_form.save()
order.action_confirm()
# unchanged warning
self.assertEqual(
order.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 1,000.00\xa0€, this document included.\n"
"Invoiced: 0.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
with Form(order) as order_form:
with order_form.order_line.edit(0) as line_form:
line_form.price_unit = 3000
line_form.save()
self.assertEqual(
order_form.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 2,000.00\xa0€, this document included.\n"
"Invoiced: 0.00\xa0€; Not Yet Invoiced: 3,000.00\xa0"
)
with order_form.order_line.edit(0) as line_form:
line_form.product_uom_qty = 2
line_form.price_unit = 3000
line_form.save()
self.assertEqual(
order_form.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 5,000.00\xa0€, this document included.\n"
"Invoiced: 0.00\xa0€; Not Yet Invoiced: 6,000.00\xa0"
)
def test_invoice(self):
"""
Ensure the amounts and warnings are computed correctly in the following flow:
We create a single invoice and post it.
"""
declaration = self.declaration_1000
declaration_tax = declaration.company_id.l10n_it_edi_doi_tax_id
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 0.0,
'remaining': 1000.0,
}])
invoice = self.create_invoice(declaration, [
Command.create({
'name': 'declaration line',
'quantity': 1,
'price_unit': 1000.0, # == declaration.threshold
'tax_ids': [Command.set(declaration_tax.ids)],
}),
Command.create({
# The line should be ignored since it does not use the special tax
'name': 'not a declaration line',
'quantity': 1,
'price_unit': 2000.0, # > declaration.threshold; not counted
'tax_ids': [Command.set(self.company.account_sale_tax_id.ids)],
}),
])
# The amounts have not changed since the invoice has not been posted yet.
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 0.0,
'remaining': 1000.0,
}])
# There is no warning since posting the invoice would not exceed the threshold.
# (only lines with the special tax are counted)
self.assertEqual(invoice.l10n_it_edi_doi_warning, "")
# Update the declaration part of the invoice to exceed the threshold
invoice.invoice_line_ids[0].price_unit = 2000 # > declaration.threshold
# The amounts in the warning are the same as the amounts on the declaration after posting the invoice.
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 1,000.00\xa0€, this document included.\n"
"Invoiced: 2,000.00\xa0€; Not Yet Invoiced: 0.00\xa0"
)
invoice.action_post()
self.assertRecordValues(declaration, [{
'invoiced': 2000.0,
'not_yet_invoiced': 0.0,
'remaining': -1000.0,
}])
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 1,000.00\xa0€, this document included.\n"
"Invoiced: 2,000.00\xa0€; Not Yet Invoiced: 0.00\xa0"
)
def test_sale_order_and_independent_invoice(self):
"""
Ensure the amounts and warnings are computed correctly in the following flow:
* We create a quotation and confirm it to sales order.
* Then we create a single invoice independent of the sales order and post it.
I.e. the invoice should not influence the Not Yet Invoiced amount of the declaration.
"""
declaration = self.declaration_1000
declaration_tax = declaration.company_id.l10n_it_edi_doi_tax_id
order = self.create_sale_order(declaration, [
Command.create({
'name': 'declaration line',
'product_id': self.product_1.id,
'price_unit': 1000.0, # == declaration.threshold
'tax_id': [Command.set(declaration_tax.ids)],
}),
Command.create({
'name': 'not a declaration line',
'product_id': self.product_1.id,
'price_unit': 2000.0, # > declaration.threshold; not counted
'tax_id': False,
}),
])
# There is no warning since confirming the sale order would not exceed the threshold.
# (only lines with the special tax are counted)
self.assertEqual(order.l10n_it_edi_doi_warning, "")
# We only count sales orders not quotations
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 0.0,
'remaining': 1000.0,
}])
# Update the declaration part of `order` to exceed the threshold
order.order_line[0].price_unit = 2000 # > declaration.threshold
# Now we show the warning
self.assertEqual(
order.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 1,000.00\xa0€, this document included.\n"
"Invoiced: 0.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
order.action_confirm()
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 2000.0,
'remaining': -1000.0,
}])
invoice = self.create_invoice(declaration, [
Command.create({
'name': 'declaration line',
'quantity': 1,
'price_unit': 1000.0,
'tax_ids': [Command.set(declaration_tax.ids)],
}),
Command.create({
# The line should be ignored since it does not use the special tax
'name': 'none declaration line',
'quantity': 1,
'price_unit': 2000.0, # > declaration.threshold; not counted
'tax_ids': [Command.set(self.company.account_sale_tax_id.ids)],
}),
])
# The amounts have not changed since the invoice has not been posted yet.
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 2000.0,
'remaining': -1000.0,
}])
# The warning has the updated values though
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 2,000.00\xa0€, this document included.\n"
"Invoiced: 1,000.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
invoice.action_post()
self.assertRecordValues(declaration, [{
'invoiced': 1000.0,
'not_yet_invoiced': 2000.0,
'remaining': -2000.0,
}])
@freeze_time('2019-12-31') # declaration.end_date
def test_overinvoiced_sale_order_and_credit_note(self):
"""
Ensure the amounts and warnings are computed correctly in the following flow:
* We create a quotation and confirm it to sales order.
* Then we invoice the sales order in 2 downpayment invoices of 50% each.
I.e. the Invoiced amount should be transferred correctly from Not Yet Invoiced to Invoiced
* We increase the amount on one of the invoices s.t. it exceeds the sales order amount.
I.e. the Invoiced amount increases more than the Not Yet Invoiced amount is lowered
* We reverse the invoice exceeding the sales order amount by creating a credit note.
I.e. check the amounts are computed correctly on the warning.
"""
declaration = self.declaration_1000
declaration_tax = declaration.company_id.l10n_it_edi_doi_tax_id
# Add an order that is not used in the rest of this test.
# This way we can always show the warning and that this amount will not be removed from Not Yet Invoiced.
independent_order = self.create_sale_order(declaration, [
Command.create({
'name': 'declaration line',
'product_id': self.product_1.id,
'price_unit': 2000.0, # > declaration.threshold
'tax_id': [Command.set(declaration_tax.ids)],
}),
Command.create({
'name': 'not a declaration line',
'product_id': self.product_1.id,
'price_unit': 2000.0, # > declaration.threshold; not counted
'tax_id': [Command.set(self.company.account_sale_tax_id.ids)],
}),
])
independent_order.action_confirm()
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 2000.0, # 2000 "base" from independent_order
'remaining': -1000.0,
}])
order = self.create_sale_order(declaration, [
Command.create({
'name': 'declaration line',
'product_id': self.product_1.id,
'price_unit': 1000.0, # == declaration.threshold
'tax_id': [Command.set(declaration_tax.ids)],
}),
Command.create({
'name': 'not a declaration line',
'product_id': self.product_1.id,
'price_unit': 2000.0, # > declaration.threshold; not counted
'tax_id': [Command.set(self.company.account_sale_tax_id.ids)],
}),
])
order.action_confirm()
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 3000.0, # 2000 "base" + 1000 from `order`
'remaining': -2000.0,
}])
downpayment_product = self.env['product.product'].create({
'name': 'Down Payment',
'taxes_id': [Command.set(self.company.account_sale_tax_id.copy({'price_include': True}).ids)],
'type': 'service',
})
self.env['ir.config_parameter'].sudo().set_param('sale.default_deposit_product_id', downpayment_product.id)
for i in range(2):
self.env['sale.advance.payment.inv'].with_context({
'active_model': 'sale.order',
'active_ids': [order.id],
'active_id': order.id,
'default_journal_id': self.company_data_2['default_journal_sale'].id,
}).create({
'advance_payment_method': 'percentage',
'amount': 50,
'deposit_account_id': self.company_data_2['default_account_revenue'].id,
}).create_invoices()
invoice = order.invoice_ids[0]
# The invoice just moves amount from `not_invoiced_yet` to `invoiced`.
# It does not lower the remaining ammount.
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 2,000.00\xa0€, this document included.\n"
"Invoiced: 500.00\xa0€; Not Yet Invoiced: 2,500.00\xa0"
)
invoice.invoice_line_ids.filtered(lambda l: l.tax_ids.ids == declaration_tax.ids).price_unit = 2000 # 1000 more than the sales order declaration amount
# Changing an invoice line does not affect the not yet invoiced amount of sale order lines not linked to that line
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 3,500.00\xa0€, this document included.\n"
"Invoiced: 2,000.00\xa0€; Not Yet Invoiced: 2,500.00\xa0"
)
invoice.action_post()
self.assertRecordValues(declaration, [{
'invoiced': 2000.0, # 2000 from invoice
'not_yet_invoiced': 2000.0, # 2000 "base"
'remaining': -3000.0,
}])
invoice2 = order.invoice_ids[1]
invoice2.action_post()
self.assertEqual(
invoice2.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 3,500.00\xa0€, this document included.\n"
"Invoiced: 2,500.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
self.assertRecordValues(declaration, [{
'invoiced': 2500.0, # 2000 + 500 from the 2 downpayment invoices
'not_yet_invoiced': 2000.0, # 2000 "base"
'remaining': -3500.0,
}])
# Reverse the invoice via a credit note
self.env['account.move.reversal'].with_company(self.company).create(
{
'move_ids': [Command.set((invoice.id,))],
'date': '2019-12-31',
'journal_id': invoice.journal_id.id,
}
).reverse_moves()
# The invoice we reversed invoiced more than the sales order amount.
credit_note = invoice.reversal_move_id
self.assertEqual(
credit_note.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 2,000.00\xa0€, this document included.\n"
"Invoiced: 500.00\xa0€; Not Yet Invoiced: 2,500.00\xa0"
)
credit_note.action_post()
self.assertRecordValues(declaration, [{
'invoiced': 500, # 1 downpayment of 50% on 1000 sale order
'not_yet_invoiced': 2500, # 2000 ("base") + 500 (left on sale order)
'remaining': -2000,
}])
@freeze_time('2019-12-31') # declaration.end_date
def test_consolidated_billing(self):
"""
Ensure the amounts and warnings are computed correctly in the following flow:
1. We create multiple quotations with 1 line each with qty 2 and confirm them all to sales order.
2. We create a single invoice for the SOs from the previous step.
There is one line per SO.
3. We change the amount on the one of the invoice lines without changing the qty.
4. We increase the qty on one line.
5. We decrease the qty on another line (not from step 4)
I.e. we check that:
* The not yet invoiced amount on the SO linked to the line from step (3) is still 0.
* The lines from step (4) and (5) do not affect each other
* Increasing the qty on line (5) to be higher than the SO amount does not lead to a negative amount on the linked SO.
"""
declaration = self.declaration_1000
declaration_tax = declaration.company_id.l10n_it_edi_doi_tax_id
orders = self.env['sale.order'].create([
self.get_sale_order_vals(declaration, [
Command.create({
'name': 'declaration line',
'product_id': self.product_1.id,
'product_uom_qty': 2,
'price_unit': 2000.0, # > declaration.threshold
'tax_id': [Command.set(declaration_tax.ids)],
}),
]) for dummy in range(3)
])
orders.action_confirm()
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 12000.0,
'remaining': -11000.0,
}])
invoice = orders._create_invoices()
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 12000.0,
'remaining': -11000.0,
}])
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 11,000.00\xa0€, this document included.\n"
"Invoiced: 12,000.00\xa0€; Not Yet Invoiced: 0.00\xa0"
)
invoice.invoice_line_ids[0].price_unit = 1000
# in the warning:
# * invoiced amount decreases by 2000 (since we reduced the price_unit by 1000)
# * not yet invoiced amount stays the same (all quantities still invoiced)
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 9,000.00\xa0€, this document included.\n"
"Invoiced: 10,000.00\xa0€; Not Yet Invoiced: 0.00\xa0"
)
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 12000.0,
'remaining': -11000.0,
}])
invoice.invoice_line_ids[1].quantity = 1
# in the warning: 1 qty (2000 €) moves from invoiced to net yet invoiced
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 9,000.00\xa0€, this document included.\n"
"Invoiced: 8,000.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 12000.0,
'remaining': -11000.0,
}])
invoice.invoice_line_ids[2].quantity = 3
# in the warning:
# * invoiced amount increases by 2000 (since we increase the quantity by 1)
# * not yet invoiced amount stays the same (all quantities still invoiced)
self.assertEqual(
invoice.l10n_it_edi_doi_warning,
"Pay attention, the threshold of your Declaration of Intent test 2019-threshold 1000 of 1,000.00\xa0€ is exceeded by 11,000.00\xa0€, this document included.\n"
"Invoiced: 10,000.00\xa0€; Not Yet Invoiced: 2,000.00\xa0"
)
self.assertRecordValues(declaration, [{
'invoiced': 0.0,
'not_yet_invoiced': 12000.0,
'remaining': -11000.0,
}])
invoice.action_post()
# Same values as in the last warning
self.assertRecordValues(declaration, [{
'invoiced': 10000.0,
'not_yet_invoiced': 2000.0,
'remaining': -11000.0,
}])

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_account_invoice_filter" model="ir.ui.view">
<field name="name">account.invoice.select</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="arch" type="xml">
<xpath expr="//search/field[@name='journal_id']" position="after">
<field name="l10n_it_edi_doi_id"/>
</xpath>
<xpath expr="//filter[@name='to_check']" position="after">
<filter string="Exceeded Declaration of Intent"
name="l10n_it_edi_doi_declaration_of_intent_exceeded"
domain="[('l10n_it_edi_doi_id.remaining','&lt;', 0)]"/>
</xpath>
<xpath expr="//group" position="inside">
<filter string="Declaration of Intent"
name="l10n_it_edi_doi_declaration_of_intent"
context="{'group_by':'l10n_it_edi_doi_id'}"/>
</xpath>
</field>
</record>
<record id="view_move_tree" model="ir.ui.view">
<field name="name">account.move.tree</field>
<field name="model">account.move</field>
<field name="arch" type="xml">
<tree string="Invoices" sample="1" decoration-info="state == 'draft'">
<field name="made_sequence_hole" attrs="{'column_invisible': True}"/>
<field name="name" decoration-bf="1" decoration-danger="made_sequence_hole"/>
<field name="invoice_partner_display_name" string="Customer"/>
<field name="invoice_date" string="Invoice Date"/>
<field name="date" string="Accounting Date" optional="hidden"/>
<field name="currency_id" attrs="{'column_invisible': True}"/>
<field name="state" widget="badge" decoration-info="state == 'draft'" decoration-success="state == 'posted'"/>
<field name="l10n_it_edi_doi_amount" decoration-bf="1" sum="Total" string="Tax excluded"/>
</tree>
</field>
</record>
<record id="view_move_form" model="ir.ui.view">
<field name="name">account.move.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button groups="account.group_account_invoice"
type="object"
class="oe_stat_button"
name="action_open_declaration_of_intent"
icon="fa-list"
attrs="{'invisible': [('l10n_it_edi_doi_id', '=', False)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">Declaration of Intent</span>
</div>
</button>
</div>
<xpath expr="//header" position="after">
<div class="alert alert-warning mb-0" role="alert"
attrs="{'invisible': [('l10n_it_edi_doi_warning', '=', '')]}">
<field name="l10n_it_edi_doi_warning"/>
</div>
</xpath>
<xpath expr="//field[@name='fiscal_position_id']" position="before">
<field name="l10n_it_edi_doi_use" invisible="True"/>
<field name="l10n_it_edi_doi_id"
attrs="{'invisible': [('l10n_it_edi_doi_use', '=', False)], 'readonly': [('state', '!=', 'draft')]}"
options='{"no_quick_create": True}'
domain="[
('state', '!=', 'draft'),
('company_id', '=', company_id),
('currency_id', '=', currency_id),
('partner_id', '=', commercial_partner_id)]"/>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_l10n_it_edi_doi_tree" model="ir.ui.view">
<field name="name">l10n_it_edi_doi.declaration_of_intent.tree</field>
<field name="model">l10n_it_edi_doi.declaration_of_intent</field>
<field name="arch" type="xml">
<tree decoration-info="state == 'draft'"
decoration-muted="state == 'terminated'"
decoration-danger="state == 'revoked'">
<control>
<create name="add_line_control" string="Add a Declaration of Intent"/>
</control>
<field name="currency_id" attrs="{'column_invisible': True}"/>
<field name="partner_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="company_id" groups="base.group_multi_company" optional="hidden"/>
<field name="protocol_number_part1" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="protocol_number_part2" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="issue_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="start_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="end_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="threshold" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="not_yet_invoiced" optional="hidden"/>
<field name="invoiced" optional="hidden"/>
<field name="remaining"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_l10n_it_edi_doi_form" model="ir.ui.view">
<field name="name">l10n_it_edi_doi.declaration_of_intent.form</field>
<field name="model">l10n_it_edi_doi.declaration_of_intent</field>
<field name="arch" type="xml">
<form>
<header>
<field name="state" widget="statusbar" statusbar_visible="draft,active"/>
<button string="Validate" attrs="{'invisible': [('state', '!=', 'draft')]}" class="btn-primary"
type="object" name="action_validate"/>
<button string="Terminate" attrs="{'invisible': [('state', '!=', 'active')]}" class="btn-primary"
type="object" name="action_terminate"/>
<button string="Reset to Draft" attrs="{'invisible': [('state', '!=', 'active')]}" class="btn-secondary"
type="object" name="action_reset_to_draft"/>
<button string="Reactivate" attrs="{'invisible': [('state', 'not in', ('terminated', 'revoked'))]}" class="btn-secondary"
type="object" name="action_reactivate"/>
<button string="Revoke" attrs="{'invisible': [('state', '!=', 'active')]}" class="btn-secondary"
type="object" name="action_revoke"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<field name="invoice_ids" invisible="True"/>
<field name="sale_order_ids" invisible="True"/>
<button type="object"
class="oe_stat_button"
name="action_open_invoice_ids"
icon="fa-pencil-square-o"
attrs="{'invisible': [('invoice_ids', '=', False)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">Invoices</span>
</div>
</button>
<button type="object"
class="oe_stat_button"
name="action_open_sale_order_ids"
icon="fa-pencil-square-o"
attrs="{'invisible': [('sale_order_ids', '=', False)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">Sale Orders</span>
</div>
</button>
</div>
<group name="main_group">
<group name="left_column">
<field name="partner_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="company_id" groups="base.group_multi_company" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<label for="protocol_number_part1" string="Protocol Number"/>
<div name="protocol_div" class="d-flex">
<field name="protocol_number_part1" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<span class="o_form_label mx-3">/</span>
<field name="protocol_number_part2" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</div>
<field name="issue_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<label string="Date Range" for="start_date"/>
<div name="date_range_div" class="d-flex">
<field name="start_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<span class="o_form_label mx-3"> to </span>
<field name="end_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</div>
</group>
<group name="right_column">
<div colspan="2" class="o_wrap_label">
<span class="o_form_label">Amounts:</span>
</div>
<field name="currency_id" invisible="True"/>
<field name="threshold" widget="monetary" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="not_yet_invoiced" widget="monetary"/>
<field name="invoiced" widget="monetary"/>
<field name="remaining" widget="monetary"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" groups="base.group_user"/>
<field name="message_ids"/>
<field name="activity_ids"/>
</div>
</form>
</field>
</record>
<record id="view_l10n_it_edi_doi_declaration_of_intent_search" model="ir.ui.view">
<field name="name">l10n_it_edi_doi.declaration_of_intent.search</field>
<field name="model">l10n_it_edi_doi.declaration_of_intent</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search>
<field name="protocol_number_part1"/>
<field name="protocol_number_part2"/>
<filter name="l10n_it_edi_doi_declaration_of_intent_active_filter"
string="Active"
domain="[('state','=', 'active')]"
help="Show active declarations of intent"/>
<filter name="l10n_it_edi_doi_declaration_of_intent_draft_filter"
string="Draft"
domain="[('state','=', 'draft')]"
help="Show draft declarations of intent"/>
<filter name="l10n_it_edi_doi_declaration_of_intent_terminated_filter"
string="Terminated / Revoked"
domain="[('state','in', ['terminated', 'revoked'])]"
help="Show terminated or revoked Declarations of Intent"/>
</search>
</field>
</record>
</odoo>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_invoice_document" inherit_id="account.report_invoice_document">
<div name="comment" position="before">
<div t-if="o.l10n_it_edi_doi_id">
<span>Your Declaration of Intent number <span t-field="o.l10n_it_edi_doi_id"/> from <span t-field="o.l10n_it_edi_doi_id.issue_date"/>.</span>
</div>
</div>
</template>
</odoo>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="res_partner_view_search" model="ir.ui.view">
<field name="name">res.partner.search.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.res_partner_view_search"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='supplier']" position="after">
<filter string="Exceeded Declaration of Intent"
name="l10n_it_edi_doi_declaration_of_intent_exceeded"
domain="[('l10n_it_edi_doi_ids','any', [('remaining', '&lt;', 0)])]"/>
</xpath>
</field>
</record>
<record id="view_partner_l10n_form" model="ir.ui.view">
<field name="name">view_partner_l10n_form</field>
<field name="inherit_id" ref="base_vat.view_partner_base_vat_form"/>
<field name="model">res.partner</field>
<field name="priority">100</field>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button groups="account.group_account_invoice"
type="object"
class="oe_stat_button"
name="l10n_it_edi_doi_action_open_declarations"
icon="fa-list"
attrs="{'invisible': [('country_code', '!=', 'IT')]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">Declarations of Intent</span>
</div>
</button>
</div>
</field>
</record>
</odoo>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_saleorder_document" inherit_id="sale.report_saleorder_document">
<p id="fiscal_position_remark" position="after">
<div t-if="doc.l10n_it_edi_doi_id">
<span>Your Declaration of Intent number <span t-field="doc.l10n_it_edi_doi_id"/> from <span t-field="doc.l10n_it_edi_doi_id.issue_date"/>.</span>
</div>
</p>
</template>
</odoo>

View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_sales_order_filter" model="ir.ui.view">
<field name="name">sale.order.list.select</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
<field name="arch" type="xml">
<filter name="my_sale_orders_filter" position="after">
<filter string="Exceeded Declaration of Intent"
name="l10n_it_edi_doi_declaration_of_intent_exceeded"
domain="[('l10n_it_edi_doi_id.remaining','&lt;', 0)]"/>
</filter>
<xpath expr="//search/group" position="inside">
<filter string="Declaration of Intent"
name="l10n_it_edi_doi_declaration_of_intent"
domain="" context="{'group_by':'l10n_it_edi_doi_id'}"/>
</xpath>
</field>
</record>
<record id="view_quotation_tree" model="ir.ui.view">
<field name="name">sale.order.tree</field>
<field name="model">sale.order</field>
<field name="priority">1000</field>
<field name="arch" type="xml">
<tree class="o_sale_order"
string="Sales Orders"
sample="1"
decoration-muted="state == 'cancel'">
<field name="name" string="Number"/>
<field name="date_order" widget="date"/>
<field name="partner_id"/>
<field name="currency_id" attrs="{'column_invisible': True}"/>
<field name="state"
decoration-success="state == 'sale'"
decoration-info="state == 'draft'"
decoration-primary="state == 'sent'"
widget="badge"/>
<field name="l10n_it_edi_doi_not_yet_invoiced" decoration-bf="1" sum="Total" string="Not Yet Invoiced Amount"/>
</tree>
</field>
</record>
<record id="view_order_form" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button groups="account.group_account_invoice"
type="object"
class="oe_stat_button"
name="action_open_declaration_of_intent"
icon="fa-list"
attrs="{'invisible': [('l10n_it_edi_doi_id', '=', False)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">Declaration of Intent</span>
</div>
</button>
</div>
<xpath expr="//header" position="after">
<div class="alert alert-warning mb-0" role="alert"
attrs="{'invisible': [('l10n_it_edi_doi_warning', '=', '')]}">
<field name="l10n_it_edi_doi_warning"/>
</div>
</xpath>
<xpath expr="//label[@for='fiscal_position_id']" position="before">
<field name="l10n_it_edi_doi_use" invisible="True"/>
<field name="l10n_it_edi_doi_id"
attrs="{'invisible': [('l10n_it_edi_doi_use', '=', False)]}"
options='{"no_quick_create": True}'
domain="[
('state', '!=', 'draft'),
('company_id', '=', company_id),
('currency_id', '=', currency_id),
('partner_id', 'parent_of', partner_id)]"/>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import sale_make_invoice_advance

View file

@ -0,0 +1,93 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
from odoo.fields import Command
class SaleAdvancePaymentInv(models.TransientModel):
_inherit = 'sale.advance.payment.inv'
def _create_invoices(self, sale_orders):
"""Extend to create a dedicated down payment line for the declaration of intent amount."""
invoice = super()._create_invoices(sale_orders)
if self.advance_payment_method == 'delivered':
return invoice
order = self.sale_order_ids # super calls ensure_one
doi_tax = order.l10n_it_edi_doi_id.company_id.l10n_it_edi_doi_tax_id
if not doi_tax:
# Includes the case where there is no order.l10n_it_edi_doi_id
return invoice
doi_total = 0
for line in order.order_line:
if line.tax_id.ids != doi_tax.ids:
continue
price_reduce = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
doi_total += price_reduce * line.product_uom_qty
# The tax on the down payment product was possibly mapped by the doi fiscal position
# Here we do a custom mapping that does not map taxes that will be mapped to the special doi tax
doi_fiscal_position = order.l10n_it_edi_doi_id.company_id.l10n_it_edi_doi_fiscal_position_id
advance_product_taxes = self.product_id.taxes_id.filtered(lambda tax: tax.company_id == order.company_id)
if advance_product_taxes and doi_fiscal_position and order.fiscal_position_id == doi_fiscal_position:
custom_mapped_taxes = self.env['account.tax']
for tax in advance_product_taxes:
mapped_tax = doi_fiscal_position.map_tax(tax)
custom_mapped_taxes |= tax if mapped_tax == doi_tax else mapped_tax
advance_product_taxes = custom_mapped_taxes
for invoice_line in invoice.invoice_line_ids:
if not invoice_line.is_downpayment:
continue
downpayment_line = invoice_line.sale_line_ids.filtered(lambda line: line.is_downpayment)
if len(downpayment_line) != 1:
continue
if advance_product_taxes:
downpayment_line.tax_id = advance_product_taxes
invoice_line.tax_ids = advance_product_taxes
if order.currency_id.is_zero(doi_total):
# The order has no lines contributing to the declaration of intent
continue
# Split the down payment amount into 2: doi amount and other amount
down_total = downpayment_line.price_unit
if all(advance_product_taxes.mapped('price_include')):
amount_total = order.amount_total
else:
amount_total = order.amount_untaxed
doi_down = order.currency_id.round(doi_total / amount_total * down_total)
other_down = down_total - doi_down
if order.currency_id.is_zero(amount_total - doi_total):
# The whole order amount is under doi_tax
# We just have to add the tax information on the lines
downpayment_line.tax_id = doi_tax
invoice_line.tax_ids = doi_tax
continue
# The order amount is partially not under doi_tax
# Split the down payment line into 2: one for the doi amount and one for the other amount
downpayment_line.price_unit = other_down
doi_so_line_values = {
**self._prepare_so_line_values(order),
'price_unit': doi_down,
'tax_id': [Command.set(doi_tax.ids)],
}
doi_down_payment_so_line = self.env['sale.order.line'].create(doi_so_line_values)
# Split the invoice line into 2: one for the doi amount and one for the other amount
invoice.invoice_line_ids = [
Command.create(doi_down_payment_so_line._prepare_invoice_line(
name=self._get_down_payment_description(order),
quantity=1.0,
)),
Command.update(invoice_line.id, {
'price_unit': other_down,
}),
]
return invoice

View file

@ -0,0 +1,43 @@
[project]
name = "odoo-bringout-oca-ocb-l10n_it_edi_doi"
version = "16.0.0"
description = "Italy - Declaration of Intent - Odoo addon"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-ocb-l10n_it_edi>=16.0.0",
"odoo-bringout-oca-ocb-sale>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["l10n_it_edi_doi"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]