Skip to content

Commit

Permalink
[MERGE] forward port branch saas-12.2 up to c9f832d
Browse files Browse the repository at this point in the history
closes #31790

Signed-off-by: Christophe Simonis <chs@odoo.com>
  • Loading branch information
KangOl committed Mar 13, 2019
2 parents bf69975 + c9f832d commit 44515bc
Show file tree
Hide file tree
Showing 281 changed files with 5,110 additions and 3,416 deletions.
5 changes: 4 additions & 1 deletion addons/account/models/account_bank_statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,9 +637,12 @@ def process_reconciliation(self, counterpart_aml_dicts=None, payment_aml_rec=Non

# Create The payment
payment = self.env['account.payment']
partner_id = self.partner_id or (aml_dict.get('move_line') and aml_dict['move_line'].partner_id) or self.env['res.partner']
if abs(total)>0.00001:
payment_vals = self._prepare_payment_vals(total)
if self.partner_id and len(account_types) == 1:
if not payment_vals['partner_id']:
payment_vals['partner_id'] = partner_id.id
if payment_vals['partner_id'] and len(account_types) == 1:
payment_vals['partner_type'] = 'customer' if account_types == receivable_account_type else 'supplier'
payment = payment.create(payment_vals)

Expand Down
12 changes: 7 additions & 5 deletions addons/account/models/account_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -1621,12 +1621,14 @@ def _amount_by_group(self):
fmt = partial(formatLang, invoice.with_context(lang=invoice.partner_id.lang).env, currency_obj=currency)
res = {}
for line in invoice.tax_line_ids:
res.setdefault(line.tax_id.tax_group_id, {'base': 0.0, 'amount': 0.0})
res[line.tax_id.tax_group_id]['amount'] += line.amount_total
res[line.tax_id.tax_group_id]['base'] += line.base
res = sorted(res.items(), key=lambda l: l[0].sequence)
tax = line.tax_id
group_key = (tax.tax_group_id, tax.amount_type, tax.amount)
res.setdefault(group_key, {'base': 0.0, 'amount': 0.0})
res[group_key]['amount'] += line.amount_total
res[group_key]['base'] += line.base
res = sorted(res.items(), key=lambda l: l[0][0].sequence)
invoice.amount_by_group = [(
r[0].name, r[1]['amount'], r[1]['base'],
r[0][0].name, r[1]['amount'], r[1]['base'],
fmt(r[1]['amount']), fmt(r[1]['base']),
len(res),
) for r in res]
Expand Down
2 changes: 1 addition & 1 deletion addons/account/models/account_journal_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def get_journal_dashboard_datas(self):
LEFT JOIN account_move move ON aml.move_id = move.id
WHERE aml.account_id in %%s
AND move.date <= %%s AND move.state = 'posted';""" % (amount_field,)
self.env.cr.execute(query, (account_ids, fields.Date.today(),))
self.env.cr.execute(query, (account_ids, fields.Date.context_today(self),))
query_results = self.env.cr.dictfetchall()
if query_results and query_results[0].get('sum') != None:
account_sum = query_results[0].get('sum')
Expand Down
10 changes: 7 additions & 3 deletions addons/account/models/account_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,14 @@ def _compute_payment_amount(self, invoices=None, currency=None):
currency = self.currency_id or self.journal_id.currency_id or self.journal_id.company_id.currency_id or invoices and invoices[0].currency_id

# Avoid currency rounding issues by summing the amounts according to the company_currency_id before
invoice_datas = invoices.read_group(
[('id', 'in', invoices.ids)],
['currency_id', 'type', 'residual_signed'],
['currency_id', 'type'], lazy=False)
total = 0.0
groups = groupby(invoices, lambda i: i.currency_id)
for payment_currency, payment_invoices in groups:
amount_total = sum([MAP_INVOICE_TYPE_PAYMENT_SIGN[i.type] * i.residual_signed for i in payment_invoices])
for invoice_data in invoice_datas:
amount_total = MAP_INVOICE_TYPE_PAYMENT_SIGN[invoice_data['type']] * invoice_data['residual_signed']
payment_currency = self.env['res.currency'].browse(invoice_data['currency_id'][0])
if payment_currency == currency:
total += amount_total
else:
Expand Down
2 changes: 1 addition & 1 deletion addons/account/models/account_reconcile_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ def _check_rule_propositions(self, statement_line, candidates):
if line_residual > total_residual:
amount_percentage = (total_residual / line_residual) * 100
else:
amount_percentage = (line_residual / total_residual) * 100
amount_percentage = (line_residual / total_residual) * 100 if total_residual else 0
return amount_percentage >= self.match_total_amount_param

@api.multi
Expand Down
22 changes: 7 additions & 15 deletions addons/account/models/reconciliation_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ def get_bank_statement_line_data(self, st_line_ids, excluded_ids=None):
else:
aml_ids = matching_amls[line.id]['aml_ids']
bank_statements_left += line.statement_id
target_currency = line.currency_id or line.journal_id.currency_id or line.journal_id.company_id.currency_id

amls = aml_ids and self.env['account.move.line'].browse(aml_ids)
line_vals = {
'st_line': self._get_statement_line(line),
'reconciliation_proposition': aml_ids and self._prepare_move_lines(amls) or [],
'reconciliation_proposition': aml_ids and self._prepare_move_lines(amls, target_currency=target_currency, target_date=line.date) or [],
'model_id': matching_amls[line.id].get('model') and matching_amls[line.id]['model'].id,
'write_off': matching_amls[line.id].get('status') == 'write_off',
}
Expand Down Expand Up @@ -486,21 +487,12 @@ def _domain_move_lines_for_reconciliation(self, st_line, aml_accounts, partner_i
('payment_id', '<>', False)
]

# Black lines = unreconciled & (not linked to a payment or open balance created by statement
domain_matching = [('reconciled', '=', False)]
if partner_id:
domain_matching = expression.AND([
domain_matching,
[('account_id.internal_type', 'in', ['payable', 'receivable'])]
])
else:
# TODO : find out what use case this permits (match a check payment, registered on a journal whose account type is other instead of liquidity)
domain_matching = expression.AND([
domain_matching,
[('account_id.reconcile', '=', True)]
])
# default domain matching
domain_matching = expression.AND([
[('reconciled', '=', False)],
[('account_id.reconcile', '=', True)]
])

# Let's add what applies to both
domain = expression.OR([domain_reconciliation, domain_matching])
if partner_id:
domain = expression.AND([domain, [('partner_id', '=', partner_id)]])
Expand Down
27 changes: 27 additions & 0 deletions addons/account/tests/test_reconciliation_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import odoo.tests
import time
import requests
from odoo.addons.account.tests.test_reconciliation import TestReconciliation

_logger = logging.getLogger(__name__)

Expand All @@ -27,3 +28,29 @@ def test_01_admin_bank_statement_reconciliation(self):
self.phantom_js(prep.url.replace('http://localhost','').replace('?','#'),
"odoo.__DEBUG__.services['web_tour.tour'].run('bank_statement_reconciliation')",
"odoo.__DEBUG__.services['web_tour.tour'].tours.bank_statement_reconciliation.ready", login="admin")


@odoo.tests.tagged('post_install', '-at_install')
class TestReconciliationWidget(TestReconciliation):

def test_statement_suggestion_other_currency(self):
# company currency is EUR
# payment in USD
invoice = self.create_invoice(invoice_amount=50, currency_id=self.currency_usd_id)

# journal currency in USD
bank_stmt = self.acc_bank_stmt_model.create({
'journal_id': self.bank_journal_usd.id,
'date': time.strftime('%Y-07-15'),
'name': 'payment %s' % invoice.number,
})

bank_stmt_line = self.acc_bank_stmt_line_model.create({'name': 'payment',
'statement_id': bank_stmt.id,
'partner_id': self.partner_agrolait_id,
'amount': 50,
'date': time.strftime('%Y-07-15'),
})

result = self.env['account.reconciliation.widget'].get_bank_statement_line_data(bank_stmt_line.ids)
self.assertEqual(result['lines'][0]['reconciliation_proposition'][0]['amount_str'], '$ 50.00')
4 changes: 2 additions & 2 deletions addons/account/views/account_move_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@
</div>
<div class="col-6">
<span class="float-right">
<field name="state" widget="kanban_label_selection" options="{'classes': {'draft': 'default', 'posted': 'success'}}"/>
<field name="state" widget="label_selection" options="{'classes': {'draft': 'default', 'posted': 'success'}}"/>
</span>
</div>
</div>
Expand Down Expand Up @@ -549,4 +549,4 @@
sequence="1"/>

</data>
</odoo>
</odoo>
2 changes: 1 addition & 1 deletion addons/account/views/account_payment_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
</div>
<div class="col-6">
<span class="float-right badge badge-secondary">
<field name="state" widget="kanban_label_selection" options="{'classes': {'draft': 'default', 'sent': 'success'}}"/>
<field name="state" widget="label_selection" options="{'classes': {'draft': 'default', 'sent': 'success'}}"/>
</span>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion addons/account/views/report_invoice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
<span t-field="line.uom_id" groups="uom.group_uom"/>
</td>
<td t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span t-field="line.price_unit" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
<span t-field="line.price_unit"/>
</td>
<td t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span t-field="line.discount"/>
Expand Down
5 changes: 4 additions & 1 deletion addons/analytic/models/analytic_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_ui
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
domain = ['|', '|', ('code', operator, name), ('name', operator, name), ('partner_id.name', operator, name)]
# `partner_id` is in auto_join and the searches using ORs with auto_join fields doesn't work
# we have to cut the search in two searches ... https://github.com/odoo/odoo/issues/25175
partner_ids = self.env['res.partner']._search([('name', operator, name)], limit=limit, access_rights_uid=name_get_uid)
domain = ['|', '|', ('code', operator, name), ('name', operator, name), ('partner_id', 'in', partner_ids)]
analytic_account_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(analytic_account_ids).name_get()

Expand Down
8 changes: 4 additions & 4 deletions addons/auth_signup/models/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ class ResPartner(models.Model):
signup_token = fields.Char(copy=False, groups="base.group_erp_manager")
signup_type = fields.Char(string='Signup Token Type', copy=False, groups="base.group_erp_manager")
signup_expiration = fields.Datetime(copy=False, groups="base.group_erp_manager")
signup_valid = fields.Boolean(compute='_compute_signup_valid', compute_sudo=True, string='Signup Token is Valid')
signup_valid = fields.Boolean(compute='_compute_signup_valid', string='Signup Token is Valid')
signup_url = fields.Char(compute='_compute_signup_url', string='Signup URL')

@api.multi
@api.depends('signup_token', 'signup_expiration')
def _compute_signup_valid(self):
dt = now()
for partner in self:
partner.signup_valid = bool(partner.signup_token) and \
(not partner.signup_expiration or dt <= partner.signup_expiration)
for partner, partner_sudo in zip(self, self.sudo()):
partner.signup_valid = bool(partner_sudo.signup_token) and \
(not partner_sudo.signup_expiration or dt <= partner_sudo.signup_expiration)

@api.multi
def _compute_signup_url(self):
Expand Down
15 changes: 15 additions & 0 deletions addons/base_automation/data/base_automation_demo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,19 @@ record['name'] = record.name + 'X'
</field>
</record>

<record id="test_mail_template_automation" model="mail.template">
<field name="name">Template Automation</field>
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
<field name="body_html">&lt;div&gt;Email automation&lt;/div&gt;</field>
</record>
<record id="test_rule_on_write_recompute_send_email" model="base.automation">
<field name="name">Base Automation: test send an email</field>
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
<field name="template_id" ref="base_automation.test_mail_template_automation"/>
<field name="state">email</field>
<field name="trigger">on_write</field>
<field name="active" eval="True"/>
<field name="filter_domain">[('deadline', '!=', False)]</field>
<field name="filter_pre_domain">[('deadline', '=', False)]</field>
</record>
</odoo>
19 changes: 14 additions & 5 deletions addons/base_automation/models/base_automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,17 @@ def _filter_pre(self, records):
return records

def _filter_post(self, records):
return self._filter_post_export_domain(records)[0]

def _filter_post_export_domain(self, records):
""" Filter the records that satisfy the postcondition of action ``self``. """
if self.filter_domain and records:
domain = [('id', 'in', records.ids)] + safe_eval(self.filter_domain, self._get_eval_context())
return records.search(domain)
return records.search(domain), domain
else:
return records
return records, None

def _process(self, records):
def _process(self, records, domain_post=None):
""" Process action ``self`` on the ``records`` that have not been done yet. """
# filter out the records on which self has already been done
action_done = self._context['__action_done']
Expand All @@ -198,7 +201,12 @@ def _process(self, records):
for record in records:
# we process the action if any watched field has been modified
if self._check_trigger_fields(record):
ctx = {'active_model': record._name, 'active_ids': record.ids, 'active_id': record.id}
ctx = {
'active_model': record._name,
'active_ids': record.ids,
'active_id': record.id,
'domain_post': domain_post,
}
self.action_server_id.with_context(**ctx).run()

def _check_trigger_fields(self, record):
Expand Down Expand Up @@ -274,7 +282,8 @@ def _write(self, vals, **kw):
_write.origin(records, vals, **kw)
# check postconditions, and execute actions on the records that satisfy them
for action in actions.with_context(old_values=old_values):
action._process(action._filter_post(pre[action]))
records, domain_post = action._filter_post_export_domain(pre[action])
action._process(records, domain_post=domain_post)
return True

return _write
Expand Down

0 comments on commit 44515bc

Please sign in to comment.