[PATCH] Upstream patch - 14072023

This commit is contained in:
Parthiv Patel
2023-07-14 08:36:02 +00:00
parent 95785ac7c7
commit cbc1cfbc86
24 changed files with 659 additions and 49 deletions

View File

@@ -73,8 +73,7 @@ def update_taxes_from_templates(cr, chart_template_xmlid):
_avoid_name_conflict(company, template)
templates_to_create += template
new_template2tax_company = templates_to_create._generate_tax(company, accounts_exist=True)['tax_template_to_tax']
return [(env['account.tax.template'].browse(template_id), env['account.tax'].browse(tax_id))
for template_id, tax_id in new_template2tax_company.items()]
return new_template2tax_company.items()
def _update_taxes_from_template(template2tax_mapping):
""" Update the taxes' tags (and only tags!) based on their corresponding template values.

View File

@@ -32,6 +32,8 @@ class Partner(models.Model):
@api.model
def _fields_view_get_address(self, arch):
arch = super(Partner, self)._fields_view_get_address(arch)
if self.env.context.get('no_address_format'):
return arch
# render the partner address accordingly to address_view_id
doc = etree.fromstring(arch)
if doc.xpath("//field[@name='city_id']"):

View File

@@ -179,7 +179,7 @@ class Contract(models.Model):
for contract in contract_ids:
next_contract = self.search([
('employee_id', '=', contract.employee_id.id),
('state', 'not in', ['cancel', 'new']),
('state', 'not in', ['cancel', 'draft']),
('date_start', '>', contract.date_start)
], order="date_start asc", limit=1)
if next_contract:

View File

@@ -2,7 +2,7 @@
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
import re
from lxml import etree
from flectra.tools.float_utils import float_compare
from flectra import models, fields, api, _
from flectra.exceptions import UserError, ValidationError, RedirectWarning
@@ -143,7 +143,7 @@ class Task(models.Model):
if (task.planned_hours > 0.0):
task_total_hours = task.effective_hours + task.subtask_effective_hours
task.overtime = max(task_total_hours - task.planned_hours, 0)
if task_total_hours > task.planned_hours:
if float_compare(task_total_hours, task.planned_hours, precision_digits=2) >= 0:
task.progress = 100
else:
task.progress = round(100.0 * task_total_hours / task.planned_hours, 2)

View File

@@ -256,6 +256,15 @@
<field name="sequence">15</field>
</record>
<record id="tax_report_F9" model="account.tax.report.line">
<field name="name">F9 - Opérations internes réalisées entre membres d'un assujetti unique</field>
<field name="tag_name">F9</field>
<field name="code">box_F9</field>
<field name="parent_id" ref="tax_report_op_non_imposables"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">16</field>
</record>
<!-- DÉCOMPTE DE LA TVA À PAYER -->
<record id="tax_report_decompte_tva" model="account.tax.report.line">
<field name="name">B. Décompte de la TVA à payer</field>
@@ -385,13 +394,126 @@
<field name="formula">None</field>
</record>
<record id="tax_report_T1_base" model="account.tax.report.line">
<field name="name">T1 - Opérations réalisées dans les DOM et imposables au taux de 1,75% (base)</field>
<field name="tag_name">T1_base</field>
<field name="code">box_T1_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
</record>
<record id="tax_report_T1_taxe" model="account.tax.report.line">
<field name="name">T1 - Opérations réalisées dans les DOM et imposables au taux de 1,75% (taxe)</field>
<field name="tag_name">T1_taxe</field>
<field name="code">box_T1_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
</record>
<record id="tax_report_T2_base" model="account.tax.report.line">
<field name="name">T2 - Opérations réalisées dans les DOM et imposables au taux de 1,05% (base)</field>
<field name="tag_name">T2_base</field>
<field name="code">box_T2_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
</record>
<record id="tax_report_T2_taxe" model="account.tax.report.line">
<field name="name">T2 - Opérations réalisées dans les DOM et imposables au taux de 1,05% (taxe)</field>
<field name="tag_name">T2_taxe</field>
<field name="code">box_T2_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
</record>
<record id="tax_report_T3_base" model="account.tax.report.line">
<field name="name">T3 - Opérations réalisées en Corse et imposables au taux de 10% (base)</field>
<field name="tag_name">T3_base</field>
<field name="code">box_T3_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">5</field>
</record>
<record id="tax_report_T3_taxe" model="account.tax.report.line">
<field name="name">T3 - Opérations réalisées en Corse et imposables au taux de 10% (taxe)</field>
<field name="tag_name">T3_taxe</field>
<field name="code">box_T3_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">6</field>
</record>
<record id="tax_report_T4_base" model="account.tax.report.line">
<field name="name">T4 - Opérations réalisées en Corse et imposables au taux de 2,1% (base)</field>
<field name="tag_name">T4_base</field>
<field name="code">box_T4_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">7</field>
</record>
<record id="tax_report_T4_taxe" model="account.tax.report.line">
<field name="name">T4 - Opérations réalisées en Corse et imposables au taux de 2,1% (taxe)</field>
<field name="tag_name">T4_taxe</field>
<field name="code">box_T4_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">8</field>
</record>
<record id="tax_report_T5_base" model="account.tax.report.line">
<field name="name">T5 - Opérations réalisées en Corse et imposables au taux de 0,9% (base)</field>
<field name="tag_name">T5_base</field>
<field name="code">box_T5_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">9</field>
</record>
<record id="tax_report_T5_taxe" model="account.tax.report.line">
<field name="name">T5 - Opérations réalisées en Corse et imposables au taux de 0,9% (taxe)</field>
<field name="tag_name">T5_taxe</field>
<field name="code">box_T5_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">10</field>
</record>
<record id="tax_report_T6_base" model="account.tax.report.line">
<field name="name">T6 - Opérations réalisées en France continentale au taux de 2,1% (base)</field>
<field name="tag_name">T6_base</field>
<field name="code">box_T6_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">11</field>
</record>
<record id="tax_report_T6_taxe" model="account.tax.report.line">
<field name="name">T6 - Opérations réalisées en France continentale au taux de 2,1% (taxe)</field>
<field name="tag_name">T6_taxe</field>
<field name="code">box_T6_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">12</field>
</record>
<record id="tax_report_T7_base" model="account.tax.report.line">
<field name="name">T7 - Retenue de TVA sur droits d'auteur (base)</field>
<field name="tag_name">T7_base</field>
<field name="code">box_T7_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">13</field>
</record>
<record id="tax_report_T7_taxe" model="account.tax.report.line">
<field name="name">T7 - Retenue de TVA sur droits d'auteur (taxe)</field>
<field name="tag_name">T7_taxe</field>
<field name="code">box_T7_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">14</field>
</record>
<record id="tax_report_13_base" model="account.tax.report.line">
<field name="name">13 - Anciens taux (base)</field>
<field name="tag_name">13_base</field>
<field name="code">box_13_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">11</field>
<field name="sequence">15</field>
</record>
<record id="tax_report_13_taxe" model="account.tax.report.line">
<field name="name">13 - Anciens taux (taxe)</field>
@@ -399,7 +521,7 @@
<field name="code">box_13_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">12</field>
<field name="sequence">16</field>
</record>
<record id="tax_report_14_base" model="account.tax.report.line">
@@ -408,7 +530,7 @@
<field name="code">box_14_base</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">13</field>
<field name="sequence">17</field>
</record>
<record id="tax_report_14_taxe" model="account.tax.report.line">
<field name="name">14 - Opérations imposables à un taux particulier (taxe)</field>
@@ -416,7 +538,7 @@
<field name="code">box_14_taxe</field>
<field name="parent_id" ref="tax_report_tva_brute_autre"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">14</field>
<field name="sequence">18</field>
</record>
<!-- Produits pétroliers -->
@@ -614,7 +736,7 @@
<field name="report_id" ref="tax_report"/>
<field name="sequence">33</field>
<field name="formula">
box_08_taxe + box_09_taxe + box_9B_taxe + box_10_taxe + box_11_taxe + box_13_taxe + box_14_taxe + box_P1_taxe + box_P2_taxe + box_I1_taxe + box_I2_taxe + box_I3_taxe + box_I4_taxe + box_I5_taxe + box_I6_taxe + box_15 + box_5B
box_08_taxe + box_09_taxe + box_9B_taxe + box_10_taxe + box_11_taxe + box_13_taxe + box_14_taxe + box_T1_taxe + box_T2_taxe + box_T3_taxe + box_T4_taxe + box_T5_taxe + box_T6_taxe + box_T7_taxe + box_P1_taxe + box_P2_taxe + box_I1_taxe + box_I2_taxe + box_I3_taxe + box_I4_taxe + box_I5_taxe + box_I6_taxe + box_15 + box_5B
</field>
</record>
@@ -717,14 +839,14 @@
<field name="sequence">9</field>
</record>
<!-- TVA due ou crédit de TVA -->
<record id="tax_report_credit" model="account.tax.report.line">
<field name="name">Crédit</field>
<field name="name">TVA due ou crédit de TVA</field>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
<field name="formula">None</field>
</record>
<!-- CREDIT -->
<record id="tax_report_25" model="account.tax.report.line">
<field name="name">25 - Crédit de TVA</field>
<field name="code">box_25</field>
@@ -734,11 +856,198 @@
<field name="formula">box_23 - box_16 if box_23 - box_16 > 0 else 0</field>
</record>
<record id="tax_report_TD" model="account.tax.report.line">
<field name="name">TD - TVA Due</field>
<field name="code">box_TD</field>
<field name="parent_id" ref="tax_report_credit"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
<field name="formula">box_16 - box_23 if box_16 - box_23 > 0 else 0</field>
</record>
<!-- Régularisation des taxes intérieures de consommation (TIC) -->
<record id="tax_report_regularisation" model="account.tax.report.line">
<field name="name">Régularisation des taxes intérieures de consommation (TIC)</field>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
</record>
<!-- Crédit constaté -->
<record id="tax_report_credit_constate" model="account.tax.report.line">
<field name="name">Crédit constaté</field>
<field name="parent_id" ref="tax_report_regularisation"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
</record>
<record id="tax_report_TICFE" model="account.tax.report.line">
<field name="name">TICFE</field>
<field name="code">box_TICFE</field>
<field name="tag_name">TICFE_constate</field>
<field name="parent_id" ref="tax_report_credit_constate"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
</record>
<record id="tax_report_TICGN" model="account.tax.report.line">
<field name="name">TICGN</field>
<field name="code">box_TICGN</field>
<field name="tag_name">TICGN_constate</field>
<field name="parent_id" ref="tax_report_credit_constate"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
</record>
<record id="tax_report_TICC" model="account.tax.report.line">
<field name="name">TICC</field>
<field name="code">box_TICC</field>
<field name="tag_name">TICC_constate</field>
<field name="parent_id" ref="tax_report_credit_constate"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
</record>
<record id="tax_report_TIC_total" model="account.tax.report.line">
<field name="name">Total</field>
<field name="code">box_TIC_total</field>
<field name="parent_id" ref="tax_report_credit_constate"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<field name="formula">box_TICFE + box_TICGN + box_TICC</field>
</record>
<!-- Crédit imputé -->
<record id="tax_report_credit_impute" model="account.tax.report.line">
<field name="name">Crédit imputé</field>
<field name="parent_id" ref="tax_report_regularisation"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
</record>
<record id="tax_report_X1" model="account.tax.report.line">
<field name="name">X1</field>
<field name="tag_name">X1</field>
<field name="code">box_X1</field>
<field name="parent_id" ref="tax_report_credit_impute"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
</record>
<record id="tax_report_X2" model="account.tax.report.line">
<field name="name">X2</field>
<field name="tag_name">X2</field>
<field name="code">box_X2</field>
<field name="parent_id" ref="tax_report_credit_impute"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
</record>
<record id="tax_report_X3" model="account.tax.report.line">
<field name="name">X3</field>
<field name="tag_name">X3</field>
<field name="code">box_X3</field>
<field name="parent_id" ref="tax_report_credit_impute"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
</record>
<record id="tax_report_X4" model="account.tax.report.line">
<field name="name">X4</field>
<field name="code">box_X4</field>
<field name="parent_id" ref="tax_report_credit_impute"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<field name="formula">box_X1 + box_X2 + box_X3</field>
</record>
<!-- Reliquat de crédit à rembourser -->
<record id="tax_report_reliquat" model="account.tax.report.line">
<field name="name">Reliquat de crédit à rembourser</field>
<field name="parent_id" ref="tax_report_regularisation"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
</record>
<record id="tax_report_Y1" model="account.tax.report.line">
<field name="name">Y1</field>
<field name="code">box_Y1</field>
<field name="parent_id" ref="tax_report_reliquat"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
<field name="formula">box_TICFE - box_X1</field>
</record>
<record id="tax_report_Y2" model="account.tax.report.line">
<field name="name">Y2</field>
<field name="code">box_Y2</field>
<field name="parent_id" ref="tax_report_reliquat"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
<field name="formula">box_TICGN - box_X2</field>
</record>
<record id="tax_report_Y3" model="account.tax.report.line">
<field name="name">Y3</field>
<field name="code">box_Y3</field>
<field name="parent_id" ref="tax_report_reliquat"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
<field name="formula">box_TICC - box_X3</field>
</record>
<record id="tax_report_Y4" model="account.tax.report.line">
<field name="name">Y4</field>
<field name="code">box_Y4</field>
<field name="parent_id" ref="tax_report_reliquat"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<field name="formula">box_Y1 + box_Y2 + box_Y3</field>
</record>
<!-- Taxe due -->
<record id="tax_report_tic_tax" model="account.tax.report.line">
<field name="name">Taxe due</field>
<field name="parent_id" ref="tax_report_regularisation"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
</record>
<record id="tax_report_Z1" model="account.tax.report.line">
<field name="name">Z1</field>
<field name="tag_name">Z1</field>
<field name="code">box_Z1</field>
<field name="parent_id" ref="tax_report_tic_tax"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
</record>
<record id="tax_report_Z2" model="account.tax.report.line">
<field name="name">Z2</field>
<field name="tag_name">Z2</field>
<field name="code">box_Z2</field>
<field name="parent_id" ref="tax_report_tic_tax"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
</record>
<record id="tax_report_Z3" model="account.tax.report.line">
<field name="name">Z3</field>
<field name="tag_name">Z3</field>
<field name="code">box_Z3</field>
<field name="parent_id" ref="tax_report_tic_tax"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
</record>
<record id="tax_report_Z4" model="account.tax.report.line">
<field name="name">Z4</field>
<field name="code">box_Z4</field>
<field name="parent_id" ref="tax_report_tic_tax"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<field name="formula">box_Z1 + box_Z2 + box_Z3</field>
</record>
<!-- Détermination du montant à payer et/ou des crédits de TVA et/ou de TIC-->
<record id="tax_report_determination" model="account.tax.report.line">
<field name="name">Détermination du montant à payer et/ou des crédits de TVA et/ou de TIC</field>
<field name="report_id" ref="tax_report"/>
<field name="sequence">5</field>
</record>
<record id="tax_report_26" model="account.tax.report.line">
<field name="name">26 - Remboursement de crédit demandé sur formulaire n°3519 joint</field>
<field name="tag_name">26</field>
<field name="code">box_26</field>
<field name="parent_id" ref="tax_report_credit"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
</record>
@@ -749,7 +1058,7 @@
</field>
<field name="tag_name">AA</field>
<field name="code">box_AA</field>
<field name="parent_id" ref="tax_report_credit"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
</record>
@@ -757,36 +1066,64 @@
<record id="tax_report_27" model="account.tax.report.line">
<field name="name">27 - Crédit à reporter</field>
<field name="code">box_27</field>
<field name="parent_id" ref="tax_report_credit"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<field name="formula">box_25 - box_26 - box_AA if box_25 - box_26 - box_AA > 0 else 0</field>
</record>
<record id="tax_report_taxes_a_payer" model="account.tax.report.line">
<field name="name">Taxe à Payer</field>
<record id="tax_report_Y5" model="account.tax.report.line">
<field name="name">Y5 - Remboursement de reliquat de TIC demandé (report de la ligne Y4)</field>
<field name="code">box_Y5</field>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<field name="formula">None</field>
<field name="sequence">5</field>
<field name="formula">box_Y4</field>
</record>
<record id="tax_report_Y6" model="account.tax.report.line">
<field name="name">Y6 - Crédit de TIC transféré à la société tête de groupe sur la déclaration récapitulative
3310-CA3G (report de la ligne Y4)</field>
<field name="code">box_Y6</field>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">5</field>
</record>
<record id="tax_report_X5" model="account.tax.report.line">
<field name="name">X5 - Crédit de TIC imputé sur la TVA (report de la ligne X4)</field>
<field name="code">box_X5</field>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">6</field>
<field name="formula">box_X4</field>
</record>
<!-- TAXE A PAYER -->
<record id="tax_report_28" model="account.tax.report.line">
<field name="name">28 - TVA nette due</field>
<field name="code">box_28</field>
<field name="parent_id" ref="tax_report_taxes_a_payer"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">1</field>
<field name="formula">box_16 - box_23 if box_16 - box_23 > 0 else 0</field>
<field name="sequence">7</field>
<field name="formula">box_TD - box_X5 if box_TD - box_X5 > 0 else 0</field>
</record>
<record id="tax_report_29" model="account.tax.report.line">
<field name="name">29 - Taxes assimilées calculées sur annexe n°3310-A-SD</field>
<field name="tag_name">29</field>
<field name="code">box_29</field>
<field name="parent_id" ref="tax_report_taxes_a_payer"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">2</field>
<field name="sequence">8</field>
</record>
<record id="tax_report_Z5" model="account.tax.report.line">
<field name="name">Z5 - Total des taxes intérieures de consommation dues (report de la ligne Z4)</field>
<field name="code">box_Z5</field>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">9</field>
<field name="formula">box_Z4</field>
</record>
<record id="tax_report_AB" model="account.tax.report.line">
@@ -794,9 +1131,9 @@
3310-CA3G
</field>
<field name="code">box_AB</field>
<field name="parent_id" ref="tax_report_taxes_a_payer"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">3</field>
<field name="sequence">10</field>
<!--According to the trustee, it's very rare that a company fill this box-->
<field name="formula">None</field>
</record>
@@ -804,11 +1141,11 @@
<record id="tax_report_32" model="account.tax.report.line">
<field name="name">32 - Total à payer</field>
<field name="code">box_32</field>
<field name="parent_id" ref="tax_report_taxes_a_payer"/>
<field name="parent_id" ref="tax_report_determination"/>
<field name="report_id" ref="tax_report"/>
<field name="sequence">4</field>
<!--The real formula is "box_28 + box_29 - box_AB" but box_AB not zero is a rare edge case -->
<field name="formula">box_28 + box_29</field>
<field name="sequence">11</field>
<!--Omit "... - box_AB" in the formula because box_AB not zero is a rare edge case -->
<field name="formula">box_28 + box_29 + box_Z5</field>
</record>
</flectra>

View File

@@ -5,6 +5,11 @@ from flectra.tests import common
class TestMailRenderMixin(common.TransactionCase):
def setUp(self):
super().setUp()
r = self.patch_requests()
r.side_effect=NotImplementedError
def test_shorten_links(self):
test_links = [
'<a href="https://gitlab.com" title="title" fake="fake">test_label</a>',

View File

@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, models
from flectra import api, models, _
from flectra.exceptions import ValidationError
class IrConfigParameter(models.Model):
@@ -12,10 +13,24 @@ class IrConfigParameter(models.Model):
for vals in vals_list:
if vals.get('key') in ['mail.bounce.alias', 'mail.catchall.alias']:
vals['value'] = self.env['mail.alias']._clean_and_check_unique(vals.get('value'))
elif vals.get('key') == 'mail.catchall.domain.allowed':
vals['value'] = vals.get('value') and self._clean_and_check_mail_catchall_allowed_domains(vals['value'])
return super().create(vals_list)
def write(self, vals):
for parameter in self:
if 'value' in vals and parameter.key in ['mail.bounce.alias', 'mail.catchall.alias'] and vals['value'] != parameter.value:
vals['value'] = self.env['mail.alias']._clean_and_check_unique(vals.get('value'))
elif 'value' in vals and parameter.key == 'mail.catchall.domain.allowed' and vals['value'] != parameter.value:
vals['value'] = vals['value'] and self._clean_and_check_mail_catchall_allowed_domains(vals['value'])
return super().write(vals)
def _clean_and_check_mail_catchall_allowed_domains(self, value):
""" The purpose of this system parameter is to avoid the creation
of records from incoming emails with a domain != alias_domain
but that have a pattern matching an internal mail.alias . """
value = [domain.strip().lower() for domain in value.split(',') if domain.strip()]
if not value:
raise ValidationError(_("Value for `mail.catchall.domain.allowed` cannot be validated.\n"
"It should be a comma separated list of domains e.g. example.com,example.org."))
return ",".join(value)

View File

@@ -851,9 +851,16 @@ class Channel(models.Model):
if channel_partner.fetched_message_id.id == last_message_id:
# last message fetched by user is already up-to-date
return
channel_partner.write({
'fetched_message_id': last_message_id,
})
# Avoid serialization error when multiple tabs are opened.
query = """
UPDATE mail_channel_partner
SET fetched_message_id = %s
WHERE id IN (
SELECT id FROM mail_channel_partner WHERE id = %s
FOR NO KEY UPDATE SKIP LOCKED
)
"""
self.env.cr.execute(query, (last_message_id, channel_partner.id))
data = {
'id': channel_partner.id,
'info': 'channel_fetched',

View File

@@ -888,6 +888,10 @@ class MailThread(models.AbstractModel):
if not isinstance(message, EmailMessage):
raise TypeError('message must be an email.message.EmailMessage at this point')
catchall_alias = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.alias")
catchall_domain_lowered = self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain", "").strip().lower()
catchall_domains_allowed = self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain.allowed")
if catchall_domain_lowered and catchall_domains_allowed:
catchall_domains_allowed = catchall_domains_allowed.split(',') + [catchall_domain_lowered]
bounce_alias = self.env['ir.config_parameter'].sudo().get_param("mail.bounce.alias")
bounce_alias_static = tools.str2bool(self.env['ir.config_parameter'].sudo().get_param("mail.bounce.alias.static", "False"))
fallback_model = model
@@ -917,10 +921,11 @@ class MailThread(models.AbstractModel):
]
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
rcpt_tos_localparts = [
e.split('@')[0].lower()
for e in tools.email_split(message_dict['recipients'])
]
rcpt_tos_localparts = []
for recipient in tools.email_split(message_dict['recipients']):
to_local, to_domain = recipient.split('@', maxsplit=1)
if not catchall_domains_allowed or to_domain.lower() in catchall_domains_allowed:
rcpt_tos_localparts.append(to_local.lower())
rcpt_tos_valid_localparts = [to for to in rcpt_tos_localparts]
# 0. Handle bounce: verify whether this is a bounced email and use it to collect bounce data and update notifications for customers

View File

@@ -15,6 +15,7 @@ Bridge module adding UX requirements to ease SMS marketing o, event attendees.
'depends': [
'event',
'mass_mailing',
'mass_mailing_event',
'mass_mailing_sms',
'sms',
],

View File

@@ -393,7 +393,7 @@ class MrpWorkorder(models.Model):
@api.onchange('date_planned_finished')
def _onchange_date_planned_finished(self):
if self.date_planned_start and self.date_planned_finished:
if self.date_planned_start and self.date_planned_finished and self.workcenter_id:
self.duration_expected = self._calculate_duration_expected()
def _calculate_duration_expected(self, date_planned_start=False, date_planned_finished=False):
@@ -728,7 +728,7 @@ class MrpWorkorder(models.Model):
@api.depends('qty_production', 'qty_produced')
def _compute_qty_remaining(self):
for wo in self:
wo.qty_remaining = float_round(wo.qty_production - wo.qty_produced, precision_rounding=wo.production_id.product_uom_id.rounding)
wo.qty_remaining = max(float_round(wo.qty_production - wo.qty_produced, precision_rounding=wo.production_id.product_uom_id.rounding), 0)
def _get_duration_expected(self, alternative_workcenter=False, ratio=1):
self.ensure_one()

View File

@@ -201,7 +201,7 @@ class CustomerPortal(CustomerPortal):
elif groupby == 'stage':
grouped_tasks = [request.env['project.task'].concat(*g) for k, g in groupbyelem(tasks, itemgetter('stage_id'))]
else:
grouped_tasks = [tasks]
grouped_tasks = [tasks] if tasks else []
values.update({
'date': date_begin,

View File

@@ -1139,8 +1139,10 @@ class Task(models.Model):
recurrence = self.env['project.task.recurrence'].create(rec_values)
task.recurrence_id = recurrence.id
if 'recurring_task' in vals and not vals.get('recurring_task'):
if not vals.get('recurring_task', True) and self.recurrence_id:
tasks_in_recurrence = self.recurrence_id.task_ids
self.recurrence_id.unlink()
tasks_in_recurrence.write({'recurring_task': False})
tasks = self
recurrence_update = vals.pop('recurrence_update', 'this')

View File

@@ -554,3 +554,33 @@ class TestProjectrecurrence(SavepointCase):
self.env.user.lang = None
task._compute_recurrence_message()
def test_disabling_recurrence(self):
"""
Disabling the recurrence of one task in a recurrence suite should disable *all*
recurrences option on the tasks linked to that recurrence
"""
with freeze_time("2020-01-01"):
self.env['project.task'].create({
'name': 'test recurring task',
'project_id': self.project_recurring.id,
'recurring_task': True,
'repeat_interval': 1,
'repeat_unit': 'week',
'repeat_type': 'after',
'repeat_number': 2,
'mon': True,
})
with freeze_time("2020-01-06"):
self.env['project.task.recurrence']._cron_create_recurring_tasks()
with freeze_time("2020-01-13"):
self.env['project.task.recurrence']._cron_create_recurring_tasks()
task_c, task_b, task_a = self.env['project.task'].search([('project_id', '=', self.project_recurring.id)])
task_b.recurring_task = False
self.assertFalse(any((task_a + task_b + task_c).mapped('recurring_task')),
"All tasks in the recurrence should have their recurrence disabled")

View File

@@ -13,13 +13,15 @@ class ResPartner(models.Model):
purchase_line_ids = fields.One2many('purchase.order.line', 'partner_id', string="Purchase Lines")
on_time_rate = fields.Float(
"On-Time Delivery Rate", compute='_compute_on_time_rate',
help="Over the past 12 months; the number of products received on time divided by the number of ordered products.")
help="Over the past x days; the number of products received on time divided by the number of ordered products."\
"x is either the System Parameter purchase_stock.on_time_delivery_days or the default 365")
@api.depends('purchase_line_ids')
def _compute_on_time_rate(self):
date_order_days_delta = int(self.env['ir.config_parameter'].sudo().get_param('purchase_stock.on_time_delivery_days', default='365'))
order_lines = self.env['purchase.order.line'].search([
('partner_id', 'in', self.ids),
('date_order', '>', fields.Date.today() - timedelta(365)),
('date_order', '>', fields.Date.today() - timedelta(date_order_days_delta)),
('qty_received', '!=', 0),
('order_id.state', 'in', ['done', 'purchase']),
('product_id', 'in', self.env['product.product'].sudo()._search([('type', '!=', 'service')]))

View File

@@ -234,7 +234,7 @@ class Orderpoint(models.Model):
'product.supplierinfo', string='Vendor', check_company=True,
domain="['|', ('product_id', '=', product_id), '&', ('product_id', '=', False), ('product_tmpl_id', '=', product_tmpl_id)]")
@api.depends('product_id.purchase_order_line_ids', 'product_id.purchase_order_line_ids.state')
@api.depends('product_id.purchase_order_line_ids.product_qty', 'product_id.purchase_order_line_ids.state')
def _compute_qty(self):
""" Extend to add more depends values """
return super()._compute_qty()

View File

@@ -276,6 +276,64 @@ class TestReorderingRule(SavepointCase):
move = move.move_dest_ids
self.assertFalse(move)
def test_reordering_rule_5(self):
"""
A product P wth RR 0-0-1.
Confirm a delivery with 1 x P -> PO created for it.
Confirm a second delivery, with 1 x P again:
- The PO should be updated
- The qty to order of the RR should be zero
"""
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1)
stock_location = warehouse.lot_stock_id
out_type = warehouse.out_type_id
customer_location = self.env.ref('stock.stock_location_customers')
rr = self.env['stock.warehouse.orderpoint'].create({
'location_id': stock_location.id,
'product_id': self.product_01.id,
'product_min_qty': 0,
'product_max_qty': 0,
'qty_multiple': 1,
})
delivery = self.env['stock.picking'].create({
'picking_type_id': out_type.id,
'location_id': stock_location.id,
'location_dest_id': customer_location.id,
'move_lines': [(0, 0, {
'name': self.product_01.name,
'product_id': self.product_01.id,
'product_uom_qty': 1,
'product_uom': self.product_01.uom_id.id,
'location_id': stock_location.id,
'location_dest_id': customer_location.id,
})]
})
delivery.action_confirm()
pol = self.env['purchase.order.line'].search([('product_id', '=', self.product_01.id)])
self.assertEqual(pol.product_qty, 1.0)
self.assertEqual(rr.qty_to_order, 0.0)
delivery = self.env['stock.picking'].create({
'picking_type_id': out_type.id,
'location_id': stock_location.id,
'location_dest_id': customer_location.id,
'move_lines': [(0, 0, {
'name': self.product_01.name,
'product_id': self.product_01.id,
'product_uom_qty': 1,
'product_uom': self.product_01.uom_id.id,
'location_id': stock_location.id,
'location_dest_id': customer_location.id,
})]
})
delivery.action_confirm()
self.assertEqual(pol.product_qty, 2.0)
self.assertEqual(rr.qty_to_order, 0.0)
def test_replenish_report_1(self):
"""Tests the auto generation of manual orderpoints.

View File

@@ -171,6 +171,23 @@ class TestMailAlias(TestMailCommon):
with self.assertRaises(exceptions.ValidationError):
record.write({'alias_defaults': "{'custom_field': brokendict"})
def test_alias_domain_allowed_validation(self):
""" Check the validation of `mail.catchall.domain.allowed` system parameter"""
for value in [',', ',,', ', ,']:
with self.assertRaises(exceptions.ValidationError,
msg="The value '%s' should not be allowed" % value):
self.env['ir.config_parameter'].set_param('mail.catchall.domain.allowed', value)
for value, expected in [
('', False),
('hello.com', 'hello.com'),
('hello.com,,', 'hello.com'),
('hello.com,bonjour.com', 'hello.com,bonjour.com'),
('hello.COM, BONJOUR.com', 'hello.com,bonjour.com'),
]:
self.env['ir.config_parameter'].set_param('mail.catchall.domain.allowed', value)
self.assertEqual(self.env['ir.config_parameter'].get_param('mail.catchall.domain.allowed'), expected)
def test_alias_setup(self):
alias = self.env['mail.alias'].create({
'alias_model_id': self.env['ir.model']._get('mail.test.container').id,
@@ -801,6 +818,66 @@ class TestMailgateway(TestMailCommon):
new_simple = self.env['mail.test.gateway'].search([('name', '=', 'Test Subject')])
self.assertEqual(len(new_simple), 1, 'message_process: a new mail.test should have been created')
@mute_logger('flectra.addons.mail.models.mail_thread', 'flectra.models')
def test_message_route_alias_with_allowed_domains(self):
""" Incoming email: check that if domains are set in the
optional system parameter `mail.catchall.domain.allowed`,
only incoming emails from these domains will generate records."""
MailTestGatewayModel = self.env['mail.test.gateway']
MailTestContainerModel = self.env['mail.test.container']
allowed_domain = 'hello.com'
not_allowed_domain = 'bonjour.com'
# test@.. will cause the creation of new mail.test
new_alias_2 = self.env['mail.alias'].create({
'alias_name': 'test',
'alias_user_id': False,
'alias_model_id': self.env['ir.model']._get('mail.test.container').id,
'alias_contact': 'everyone',
})
for subject, gateway_created, container_created, alias2_domain, sys_param in [
# Test with 'mail.catchall.domain.allowed' not set in system parameters
# and with a domain not allowed
('Test Subject 1', True, True, not_allowed_domain, ""),
# Test with 'mail.catchall.domain.allowed' set in system parameters
# and with a domain not allowed
('Test Subject 2', True, False, not_allowed_domain, allowed_domain),
# Test with 'mail.catchall.domain.allowed' set in system parameters
# and with a domain allowed
('Test Subject 3', True, True, allowed_domain, allowed_domain),
]:
with self.subTest(subject=subject, gateway_created=gateway_created,
container_created=container_created, alias2_domain=alias2_domain,
sys_param=sys_param):
self.env['ir.config_parameter'].set_param('mail.catchall.domain.allowed', sys_param)
email_to = '%s@%s, %s@%s' % (
self.alias.alias_name, self.alias_domain,
new_alias_2.alias_name, alias2_domain,
)
self.format_and_process(
MAIL_TEMPLATE, self.partner_1.email_formatted, email_to,
subject=subject,
target_model=self.alias.alias_model_id.model
)
res_alias_1 = MailTestGatewayModel.search([('name', '=', subject)])
res_alias_2 = MailTestContainerModel.search([('name', '=', subject)])
self.assertEqual(
bool(res_alias_1), gateway_created,
'message_process (%s): a new mail.test.gateway %s have been created' %
(subject, 'should' if gateway_created else "should not")
)
self.assertEqual(
bool(res_alias_2), container_created,
'message_process (%s): a new mail.test.container %s have been created' %
(subject, 'should' if container_created else "should not")
)
# --------------------------------------------------
# Email Management
# --------------------------------------------------

View File

@@ -2,6 +2,7 @@ flectra.define('wysiwyg.widgets.media', function (require) {
'use strict';
var concurrency = require('web.concurrency');
const config = require('web.config');
var core = require('web.core');
var Dialog = require('web.Dialog');
var dom = require('web.dom');
@@ -872,6 +873,38 @@ var ImageWidget = FileWidget.extend({
.addClass("o_we_attachment_selected");
});
},
/**
* @override
*/
_getAttachmentsDomain(needle) {
const domain = this._super(...arguments);
// Optimized images (meaning they are related to an `original_id`) can
// only be shown in debug mode as the toggler to make those images
// appear is hidden when not in debug mode.
// There is thus no point to fetch those optimized images outside debug
// mode. Worst, it leads to bugs: it might fetch only optimized images
// when clicking on "load more" which will look like it's bugged as no
// images will appear on screen (they all will be hidden).
if (!config.isDebug()) {
const subDomain = [false];
// Particular exception: if the edited image is an optimized
// image, we need to fetch it too so it's displayed as the
// selected image when opening the media dialog.
// We might get a few more optimized image than necessary if the
// original image has multiple optimized images but it's not a
// big deal.
const originalId = this.$media.length && this.$media[0].dataset.originalId;
if (originalId) {
subDomain.push(originalId);
}
domain.push(['original_id', 'in', subDomain]);
}
return domain;
},
//--------------------------------------------------------------------------
// Handlers

View File

@@ -65,7 +65,16 @@ flectra.define('website_form.s_website_form', function (require) {
// Because, using t-att- inside form make it non-editable
var $values = $('[data-for=' + this.$target.attr('id') + ']');
if ($values.length) {
var values = JSON.parse($values.data('values').replace('False', '""').replace('None', '""').replace(/'/g, '"'));
const values = JSON.parse($values.data('values')
// replaces `True` by `true` if they are after `,` or `:` or `[`
.replace(/([,:\[]\s*)True/g, '$1true')
// replaces `False` and `None` by `""` if they are after `,` or `:` or `[`
.replace(/([,:\[]\s*)(False|None)/g, '$1""')
// replaces the `'` by `"` if they are before `,` or `:` or `]` or `}`
.replace(/'(\s*[,:\]}])/g, '"$1')
// replaces the `'` by `"` if they are after `{` or `[` or `,` or `:`
.replace(/([{\[:,]\s*)'/g, '$1"')
);
var fields = _.pluck(this.$target.serializeArray(), 'name');
_.each(fields, function (field) {
if (_.has(values, field)) {

View File

@@ -35,7 +35,5 @@ class ResCountry(models.Model):
states = res
break
states |= carrier.state_ids
if not states:
states = states.search([('country_id', '=', self.id)])
res = res & states
return res

View File

@@ -2,3 +2,4 @@
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import test_ui
from . import test_delivery

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from flectra.addons.website_sale.controllers.main import WebsiteSale
from flectra.tests import tagged, HttpCase
@tagged('post_install', '-at_install')
class TestDelivery(HttpCase):
def test_address_states(self):
US = self.env.ref('base.us')
MX = self.env.ref('base.mx')
# Set all carriers to mexico
self.env['delivery.carrier'].sudo().search([('website_published', '=', True)]).country_ids = [(6, 0, [MX.id])]
# Create a new carrier to only one state in mexico
self.env['delivery.carrier'].create({
'name': "One_state",
'product_id': self.env['product.product'].create({'name': "delivery product"}).id,
'website_published': True,
'country_ids': [(6, 0, [MX.id])],
'state_ids': [(6, 0, [MX.state_ids.ids[0]])]
})
country_info = WebsiteSale().country_infos(country=MX, mode="shipping")
self.assertEqual(len(country_info['states']), len(MX.state_ids))
country_info = WebsiteSale().country_infos(country=US, mode="shipping")
self.assertEqual(len(country_info['states']), 0)

View File

@@ -1125,6 +1125,8 @@ class WebsiteSlides(WebsiteProfile):
# try accessing slide, and display to corresponding template
try:
slide = request.env['slide.slide'].browse(slide_id)
if not slide.active:
raise werkzeug.exceptions.NotFound()
if is_embedded:
request.env['slide.embed'].sudo()._add_embed_url(slide.id, referrer_url)
values = self._get_slide_detail(slide)