[MERGE] forward port branch saas-14 up to f3ac68ed29

This commit is contained in:
Christophe Simonis
2017-10-20 17:24:15 +02:00
29 changed files with 161 additions and 41 deletions
@@ -72,13 +72,13 @@ from ${object.company_id.name}.
% set record = ctx.get('record') % set record = ctx.get('record')
% set company = record and record.company_id or user.company_id % set company = record and record.company_id or user.company_id
<body style="margin: 0; padding: 0;"> <body style="margin: 0; padding: 0;">
<table border="0" width="100%" cellpadding="0" bgcolor="#ededed" style="padding: 20px; background-color: #ededed" summary="o_mail_notification"> <table border="0" width="100%" cellpadding="0" bgcolor="#ededed" style="padding: 20px; background-color: #ededed; border-collapse:separate;" summary="o_mail_notification">
<tbody> <tbody>
<!-- HEADER --> <!-- HEADER -->
<tr> <tr>
<td align="center" style="min-width: 590px;"> <td align="center" style="min-width: 590px;">
<table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px;"> <table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px; border-collapse:separate;">
<tr> <tr>
<td valign="middle"> <td valign="middle">
<span style="font-size:20px; color:white; font-weight: bold;"> <span style="font-size:20px; color:white; font-weight: bold;">
@@ -96,7 +96,7 @@ from ${object.company_id.name}.
<!-- CONTENT --> <!-- CONTENT -->
<tr> <tr>
<td align="center" style="min-width: 590px;"> <td align="center" style="min-width: 590px;">
<table width="590" border="0" cellpadding="0" bgcolor="#ffffff" style="min-width: 590px; background-color: rgb(255, 255, 255); padding: 20px;"> <table width="590" border="0" cellpadding="0" bgcolor="#ffffff" style="min-width: 590px; background-color: rgb(255, 255, 255); padding: 20px; border-collapse:separate;">
<tbody> <tbody>
<td valign="top" style="font-family:Arial,Helvetica,sans-serif; color: #555; font-size: 14px;"> <td valign="top" style="font-family:Arial,Helvetica,sans-serif; color: #555; font-size: 14px;">
${object.body | safe} ${object.body | safe}
@@ -109,7 +109,7 @@ from ${object.company_id.name}.
<!-- FOOTER --> <!-- FOOTER -->
<tr> <tr>
<td align="center" style="min-width: 590px;"> <td align="center" style="min-width: 590px;">
<table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px;"> <table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px; border-collapse:separate;">
<tr> <tr>
<td valign="middle" align="left" style="color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;"> <td valign="middle" align="left" style="color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;">
${company.name}<br/> ${company.name}<br/>
+3 -3
View File
@@ -798,7 +798,7 @@ class AccountTax(models.Model):
# (145 - 15) / (1.0 + ((10 + 20) / 100.0)) = 130 / 1.3 = 100 # (145 - 15) / (1.0 + ((10 + 20) / 100.0)) = 130 / 1.3 = 100
if fixed_amount == 0.0 and percent_amount == 0.0: if fixed_amount == 0.0 and percent_amount == 0.0:
return base_amount return base_amount
return round((base_amount - fixed_amount) / (1.0 + percent_amount / 100.0), prec) return (base_amount - fixed_amount) / (1.0 + percent_amount / 100.0)
base = round(price_unit * quantity, prec) base = round(price_unit * quantity, prec)
@@ -862,7 +862,7 @@ class AccountTax(models.Model):
'id': tax.id, 'id': tax.id,
'name': tax.with_context(**{'lang': partner.lang} if partner else {}).name, 'name': tax.with_context(**{'lang': partner.lang} if partner else {}).name,
'amount': sign * tax_amount, 'amount': sign * tax_amount,
'base': sign * tax_base, 'base': round(sign * tax_base, prec),
'sequence': tax.sequence, 'sequence': tax.sequence,
'account_id': tax.account_id.id, 'account_id': tax.account_id.id,
'refund_account_id': tax.refund_account_id.id, 'refund_account_id': tax.refund_account_id.id,
@@ -873,7 +873,7 @@ class AccountTax(models.Model):
'taxes': taxes_vals, 'taxes': taxes_vals,
'total_excluded': sign * (currency.round(total_excluded) if round_total else total_excluded), 'total_excluded': sign * (currency.round(total_excluded) if round_total else total_excluded),
'total_included': sign * (currency.round(total_included) if round_total else total_included), 'total_included': sign * (currency.round(total_included) if round_total else total_included),
'base': sign * base, 'base': round(sign * base, prec),
} }
@api.model @api.model
+21
View File
@@ -28,6 +28,12 @@ class TestTax(AccountTestUsers):
'amount': 10, 'amount': 10,
'sequence': 3, 'sequence': 3,
}) })
self.percent_tax_bis = self.tax_model.create({
'name': "Percent tax bis",
'amount_type': 'percent',
'amount': 21,
'sequence': 3,
})
self.division_tax = self.tax_model.create({ self.division_tax = self.tax_model.create({
'name': "Division tax", 'name': "Division tax",
'amount_type': 'division', 'amount_type': 'division',
@@ -172,6 +178,21 @@ class TestTax(AccountTestUsers):
], ],
res_percent res_percent
) )
self.percent_tax_bis.price_include = True
self.percent_tax_bis.include_base_amount = True
res_percent = self.percent_tax_bis.compute_all(7.0)
self._check_compute_all_results(
7.0, # 'base'
7.0, # 'total_included'
5.79, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
# ---------------------------------------------------
(5.79, 1.21), # | 3 | 21% | t | t
# ---------------------------------------------------
],
res_percent
)
def test_tax_sequence_normalized_set(self): def test_tax_sequence_normalized_set(self):
self.division_tax.sequence = 1 self.division_tax.sequence = 1
@@ -12,6 +12,16 @@ import odoo.addons.decimal_precision as dp
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
_inherit = 'account.invoice' _inherit = 'account.invoice'
@api.model
def _refund_cleanup_lines(self, lines):
result = super(AccountInvoice, self)._refund_cleanup_lines(lines)
for i, line in enumerate(lines):
for name, field in line._fields.items():
if name == 'asset_category_id':
result[i][2][name] = False
break
return result
@api.multi @api.multi
def action_cancel(self): def action_cancel(self):
res = super(AccountInvoice, self).action_cancel() res = super(AccountInvoice, self).action_cancel()
+6 -1
View File
@@ -6,6 +6,7 @@ import logging
import json import json
import werkzeug.urls
import werkzeug.utils import werkzeug.utils
from werkzeug.exceptions import BadRequest from werkzeug.exceptions import BadRequest
@@ -148,7 +149,11 @@ class OAuthController(http.Controller):
url = '/web#action=%s' % action url = '/web#action=%s' % action
elif menu: elif menu:
url = '/web#menu_id=%s' % menu url = '/web#menu_id=%s' % menu
return login_and_redirect(*credentials, redirect_url=url) resp = login_and_redirect(*credentials, redirect_url=url)
# Since /web is hardcoded, verify user has right to land on it
if werkzeug.urls.url_parse(resp.location).path == '/web' and not request.env.user.has_group('base.group_user'):
resp.location = '/'
return resp
except AttributeError: except AttributeError:
# auth_signup is not installed # auth_signup is not installed
_logger.error("auth_signup not installed on database %s: oauth sign up cancelled." % (dbname,)) _logger.error("auth_signup not installed on database %s: oauth sign up cancelled." % (dbname,))
+20
View File
@@ -18,6 +18,12 @@ from odoo import api, models, _
from odoo.tools.misc import ustr from odoo.tools.misc import ustr
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
_eu_country_vat = {
'GR': 'EL'
}
_eu_country_vat_inverse = {v: k for k, v in _eu_country_vat.items()}
_ref_vat = { _ref_vat = {
'at': 'ATU12345675', 'at': 'ATU12345675',
'be': 'BE0477472701', 'be': 'BE0477472701',
@@ -79,6 +85,7 @@ class ResPartner(models.Model):
# Foreign companies that trade with non-enterprises in the EU # Foreign companies that trade with non-enterprises in the EU
# may have a VATIN starting with "EU" instead of a country code. # may have a VATIN starting with "EU" instead of a country code.
return True return True
country_code = _eu_country_vat_inverse.get(country_code, country_code)
return bool(self.env['res.country'].search([('code', '=ilike', country_code)])) return bool(self.env['res.country'].search([('code', '=ilike', country_code)]))
return check_func(vat_number) return check_func(vat_number)
@@ -96,6 +103,19 @@ class ResPartner(models.Model):
# country code or empty VAT number), so we fall back to the simple check. # country code or empty VAT number), so we fall back to the simple check.
return self.simple_vat_check(country_code, vat_number) return self.simple_vat_check(country_code, vat_number)
@api.model
def fix_eu_vat_number(self, country_id, vat):
europe = self.env.ref('base.europe')
country = self.env["res.country"].browse(country_id)
if not europe:
europe = self.env["res.country.group"].search([('name', '=', 'Europe')], limit=1)
if europe and country and country.id in europe.country_ids.ids:
vat = re.sub('[^A-Za-z0-9]', '', vat).upper()
country_code = _eu_country_vat.get(country.code, country.code).upper()
if vat[:2] != country_code:
vat = country_code + vat
return vat
@api.constrains('vat', 'commercial_partner_country_id') @api.constrains('vat', 'commercial_partner_country_id')
def check_vat(self): def check_vat(self):
if self.env.context.get('company_id'): if self.env.context.get('company_id'):
+1 -1
View File
@@ -9,7 +9,7 @@ class AccountInvoice(models.Model):
@api.multi @api.multi
def action_invoice_paid(self): def action_invoice_paid(self):
""" When an invoice linked to a sales order selling registrations is """ When an invoice linked to a sales order selling registrations is
paid confirm attendees. Attendees should indeed not be confirmed before paid confirm attendees. Attendees should indeed not be confirmed before
full payment. """ full payment. """
res = super(AccountInvoice, self).action_invoice_paid() res = super(AccountInvoice, self).action_invoice_paid()
+4 -4
View File
@@ -17,9 +17,9 @@ _logger = logging.getLogger(__name__)
# Those are the builtin raspberry pi USB modules, they should # Those are the builtin raspberry pi USB modules, they should
# not appear in the list of connected devices. # not appear in the list of connected devices.
BANNED_DEVICES = set([ BANNED_DEVICES = set([
"0424:9514", # Standard Microsystem Corp. Builtin Ethernet module "0424:9514", # Standard Microsystem Corp. Builtin Ethernet module
"1d6b:0002", # Linux Foundation 2.0 root hub "1d6b:0002", # Linux Foundation 2.0 root hub
"0424:ec00", # Standard Microsystem Corp. Other Builtin Ethernet module "0424:ec00", # Standard Microsystem Corp. Other Builtin Ethernet module
]) ])
@@ -106,7 +106,7 @@ class Proxy(http.Controller):
device_name = device[device.find('ID')+2:] device_name = device[device.find('ID')+2:]
device_id = device_name.split()[0] device_id = device_name.split()[0]
if not (device_id in BANNED_DEVICES): if not (device_id in BANNED_DEVICES):
resp+= "<div class='device' data-device='"+device+"'>"+device_name+"</div>\n" resp+= "<div class='device' data-device='"+device+"'>"+device_name+"</div>\n"
count += 1 count += 1
if count == 0: if count == 0:
+2 -1
View File
@@ -71,6 +71,7 @@
<field name="model_id" ref="mail.model_mail_message"/> <field name="model_id" ref="mail.model_mail_message"/>
<field name="auto_delete" eval="True"/> <field name="auto_delete" eval="True"/>
<field name="body_html"><![CDATA[ <field name="body_html"><![CDATA[
% set company = ctx.get('company', user.company_id)
<div> <div>
% if ctx.get('has_button_access'): % if ctx.get('has_button_access'):
<div itemscope itemtype="http://schema.org/EmailMessage"> <div itemscope itemtype="http://schema.org/EmailMessage">
@@ -110,7 +111,7 @@
% endif % endif
</td> </td>
<td valign="center" align="right"> <td valign="center" align="right">
<img src="/logo.png" style="padding: 0px; margin: 0px; height: auto; max-width: 80px; max-height: 40px;" alt="${user.company_id.name}"> <img src="/logo.png?company=${company.id}" style="padding: 0px; margin: 0px; height: auto; max-width: 80px; max-height: 40px;" alt="${company.name}">
</td> </td>
</tr> </tr>
<tr> <tr>
+6 -1
View File
@@ -53,7 +53,6 @@ class Partner(models.Model):
website_url = 'http://%s' % user.company_id.website if not user.company_id.website.lower().startswith(('http:', 'https:')) else user.company_id.website website_url = 'http://%s' % user.company_id.website if not user.company_id.website.lower().startswith(('http:', 'https:')) else user.company_id.website
else: else:
website_url = False website_url = False
company_name = user.company_id.name
model_name = False model_name = False
if message.model: if message.model:
@@ -73,9 +72,15 @@ class Partner(models.Model):
if message.res_id and message.model in self.env: if message.res_id and message.model in self.env:
record = self.env[message.model].browse(message.res_id) record = self.env[message.model].browse(message.res_id)
company = user.company_id;
if record and hasattr(record, 'company_id'):
company = record.company_id;
company_name = company.name;
return { return {
'signature': signature, 'signature': signature,
'website_url': website_url, 'website_url': website_url,
'company': company,
'company_name': company_name, 'company_name': company_name,
'model_name': model_name, 'model_name': model_name,
'record': record, 'record': record,
@@ -28,6 +28,9 @@
<field name="body_html" widget="html" readonly="1" <field name="body_html" widget="html" readonly="1"
nolabel="1" options='{"safe": True}'/> nolabel="1" options='{"safe": True}'/>
<field name="attachment_ids" widget="many2many_binary" readonly="1"/> <field name="attachment_ids" widget="many2many_binary" readonly="1"/>
<footer>
<button string="Discard" class="btn-default" special="cancel"/>
</footer>
</form> </form>
</field> </field>
</record> </record>
+2 -1
View File
@@ -307,7 +307,8 @@ class ProductProduct(models.Model):
for value in product.attribute_value_ids: for value in product.attribute_value_ids:
if value.attribute_id in attributes: if value.attribute_id in attributes:
raise ValidationError(_('Error! It is not allowed to choose more than one value for a given attribute.')) raise ValidationError(_('Error! It is not allowed to choose more than one value for a given attribute.'))
attributes |= value.attribute_id if value.attribute_id.create_variant:
attributes |= value.attribute_id
return True return True
@api.onchange('uom_id', 'uom_po_id') @api.onchange('uom_id', 'uom_po_id')
+2 -2
View File
@@ -19,6 +19,6 @@ def uninstall_hook(cr, registry):
if 'crm.team' in env: if 'crm.team' in env:
recs = env['crm.team'].search([]) recs = env['crm.team'].search([])
for rec in recs: for rec in recs:
rec._onchange_team_type() rec._onchange_team_type()
cr.after("commit", partial(update_dashboard_graph_model, cr.dbname)) cr.after("commit", partial(update_dashboard_graph_model, cr.dbname))
+4 -4
View File
@@ -71,13 +71,13 @@ from ${object.company_id.name}.
% set record = ctx.get('record') % set record = ctx.get('record')
% set company = record and record.company_id or user.company_id % set company = record and record.company_id or user.company_id
<body style="margin: 0; padding: 0;"> <body style="margin: 0; padding: 0;">
<table border="0" width="100%" cellpadding="0" bgcolor="#ededed" style="padding: 20px; background-color: #ededed" summary="o_mail_notification"> <table border="0" width="100%" cellpadding="0" bgcolor="#ededed" style="padding: 20px; background-color: #ededed; border-collapse:separate;" summary="o_mail_notification">
<tbody> <tbody>
<!-- HEADER --> <!-- HEADER -->
<tr> <tr>
<td align="center" style="min-width: 590px;"> <td align="center" style="min-width: 590px;">
<table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px;"> <table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px; border-collapse:separate;">
<tr> <tr>
<td valign="middle"> <td valign="middle">
<span style="font-size:20px; color:white; font-weight: bold;"> <span style="font-size:20px; color:white; font-weight: bold;">
@@ -95,7 +95,7 @@ from ${object.company_id.name}.
<!-- CONTENT --> <!-- CONTENT -->
<tr> <tr>
<td align="center" style="min-width: 590px;"> <td align="center" style="min-width: 590px;">
<table width="590" border="0" cellpadding="0" bgcolor="#ffffff" style="min-width: 590px; background-color: rgb(255, 255, 255); padding: 20px;"> <table width="590" border="0" cellpadding="0" bgcolor="#ffffff" style="min-width: 590px; background-color: rgb(255, 255, 255); padding: 20px; border-collapse:separate;">
<tbody> <tbody>
<td valign="top" style="font-family:Arial,Helvetica,sans-serif; color: #555; font-size: 14px;"> <td valign="top" style="font-family:Arial,Helvetica,sans-serif; color: #555; font-size: 14px;">
${object.body | safe} ${object.body | safe}
@@ -108,7 +108,7 @@ from ${object.company_id.name}.
<!-- FOOTER --> <!-- FOOTER -->
<tr> <tr>
<td align="center" style="min-width: 590px;"> <td align="center" style="min-width: 590px;">
<table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px;"> <table width="590" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px; border-collapse:separate;">
<tr> <tr>
<td valign="middle" align="left" style="color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;"> <td valign="middle" align="left" style="color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;">
${company.name}<br/> ${company.name}<br/>
+2 -1
View File
@@ -868,7 +868,8 @@ class SaleOrderLine(models.Model):
return price return price
else: else:
from_currency = self.order_id.company_id.currency_id from_currency = self.order_id.company_id.currency_id
return from_currency.compute(pricelist_item and product[pricelist_item.base] or product.lst_price, self.order_id.pricelist_id.currency_id) product_price = product[pricelist_item.base] if (pricelist_item and pricelist_item.base != 'pricelist') else product.lst_price
return from_currency.compute(product_price, self.order_id.pricelist_id.currency_id)
@api.multi @api.multi
@api.onchange('product_id') @api.onchange('product_id')
+2 -2
View File
@@ -14,5 +14,5 @@ class ProcurementOrder(models.Model):
return vals return vals
class ProcurementGroup(models.Model): class ProcurementGroup(models.Model):
_inherit = 'procurement.group' _inherit = 'procurement.group'
sale_order_id = fields.Many2one('sale.order', string='Sale Order') sale_order_id = fields.Many2one('sale.order', string='Sale Order')
+7 -5
View File
@@ -108,11 +108,13 @@ class SaleOrderLine(models.Model):
@api.multi @api.multi
@api.depends('product_id') @api.depends('product_id')
def _compute_qty_delivered_updateable(self): def _compute_qty_delivered_updateable(self):
for line in self: # prefetch field before filtering
if line.product_id.type not in ('consu', 'product'): self.mapped('product_id')
super(SaleOrderLine, line)._compute_qty_delivered_updateable() # on consumable or stockable products, qty_delivered_updateable defaults
else: # to False; on other lines use the original computation
line.qty_delivered_updateable = False lines = self.filtered(lambda line: line.product_id.type not in ('consu', 'product'))
lines = lines.with_prefetch(self._prefetch)
super(SaleOrderLine, lines)._compute_qty_delivered_updateable()
@api.onchange('product_id') @api.onchange('product_id')
def _onchange_product_id_set_customer_lead(self): def _onchange_product_id_set_customer_lead(self):
+2 -2
View File
@@ -267,10 +267,10 @@ class PackOperationLot(models.Model):
_description = "Lot/Serial number for pack ops" _description = "Lot/Serial number for pack ops"
operation_id = fields.Many2one('stock.pack.operation') operation_id = fields.Many2one('stock.pack.operation')
qty = fields.Float('Done', default=1.0) qty = fields.Float('Done', default=1.0, digits=dp.get_precision('Product Unit of Measure'))
lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number') lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
lot_name = fields.Char('Lot/Serial Number') lot_name = fields.Char('Lot/Serial Number')
qty_todo = fields.Float('To Do', default=0.0) qty_todo = fields.Float('To Do', default=0.0, digits=dp.get_precision('Product Unit of Measure'))
plus_visible = fields.Boolean(compute='_compute_plus_visible', default=True) plus_visible = fields.Boolean(compute='_compute_plus_visible', default=True)
_sql_constraints = [ _sql_constraints = [
@@ -505,6 +505,9 @@ var FieldDomain = common.AbstractField.extend(common.ReinitializeFieldMixin).ext
this.$errorMessage.toggleClass("hidden", this.valid); this.$errorMessage.toggleClass("hidden", this.valid);
}).bind(this)); }).bind(this));
}, },
is_false: function () {
return false;
},
is_syntax_valid: function() { is_syntax_valid: function() {
return this.field_manager.get("actual_mode") === "view" || this.valid; return this.field_manager.get("actual_mode") === "view" || this.valid;
}, },
+2
View File
@@ -52,6 +52,8 @@
.modal-body { .modal-body {
overflow: auto; overflow: auto;
// fix iOS issue https://github.com/scottjehl/Device-Bugs/issues/8
-webkit-transform: translate3d(0, 0, 0);
min-height: 0; min-height: 0;
&.o_dialog_error { &.o_dialog_error {
+1 -1
View File
@@ -199,7 +199,7 @@
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<title t-esc="title or 'Odoo'"/> <title t-esc="title or 'Odoo'"/>
<link type="image/x-icon" rel="shortcut icon" t-att-href="x_icon or '/web/static/src/img/favicon.ico'"/> <link type="image/x-icon" rel="shortcut icon" t-att-href="x_icon or '/web/static/src/img/favicon.ico'"/>
@@ -771,7 +771,7 @@ eventHandler.attach = function (oLayoutInfo, options) {
* Open Link Dialog on double click on a link/button. * Open Link Dialog on double click on a link/button.
* Shows a tooltip on click to say to the user he can double click. * Shows a tooltip on click to say to the user he can double click.
*/ */
create_dblclick_feature("a[href], .btn", function () { create_dblclick_feature("a[href], a.btn, button.btn", function () {
eventHandler.modules.linkDialog.show(oLayoutInfo); eventHandler.modules.linkDialog.show(oLayoutInfo);
}); });
+1 -1
View File
@@ -131,7 +131,7 @@
</div> </div>
<div class="col-xs-12 col-md-6 o_setting_box"> <div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane"> <div class="o_setting_left_pane">
<field name="module_website_version"/> <field name="module_website_version" widget="upgrade_boolean"/>
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="module_website_version"/> <label for="module_website_version"/>
+2
View File
@@ -487,6 +487,8 @@ class WebsiteSale(http.Controller):
# vat validation # vat validation
Partner = request.env['res.partner'] Partner = request.env['res.partner']
if data.get("vat") and hasattr(Partner, "check_vat"): if data.get("vat") and hasattr(Partner, "check_vat"):
if data.get("country_id"):
data["vat"] = Partner.fix_eu_vat_number(data.get("country_id"), data.get("vat"))
check_func = request.website.company_id.vat_check_vies and Partner.vies_vat_check or Partner.simple_vat_check check_func = request.website.company_id.vat_check_vies and Partner.vies_vat_check or Partner.simple_vat_check
vat_country, vat_number = Partner._split_vat(data.get("vat")) vat_country, vat_number = Partner._split_vat(data.get("vat"))
if not check_func(vat_country, vat_number): if not check_func(vat_country, vat_number):
+1
View File
@@ -4,4 +4,5 @@ import product
import sale_order import sale_order
import crm_team import crm_team
import res_config import res_config
import ir_model_fields
import website import website
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
# !! Attention, this is a hack of a hack, do not try this at home !!
# This is done because website_sale defines the website_description
# field which is also defined by website_quote, but these two modules
# are independent of each other, the part of the ORM that generates
# xmlids does not support this case therefore it only creates a single
# pair of xmlids for whichever module is installed first, therefore
# when uninstalling any of the two modules the website_descripion field
# will be deleted from the db and the other module won't be able to
# use this field, resulting in a crash and data-loss.
# See opw-776464 for more details.
#
# This is hotfixed by overriding the unlink method so as to not delete
# the website_description field if website_sale is uninstalled, it's
# an ugly hack but it works and big changes can't be done to the ORM
# in stable versions, Odoo v12+ will properly fix this
class IrModelFields(models.Model):
_inherit = "ir.model.fields"
@api.multi
def unlink(self):
# Prevent the deletion of the field "website_description"
self = self.filtered(
lambda rec: not (
rec.model in ('product.product', 'product.template') and
rec.name == 'website_description'
)
)
return super(IrModelFields, self).unlink()
+1
View File
@@ -25,3 +25,4 @@ Philippe Schmidt philippe.schmidt@acsone.eu https://github.com/phschmidt
Stéphane Bidoul stephane.bidoul@acsone.eu https://github.com/sbidoul Stéphane Bidoul stephane.bidoul@acsone.eu https://github.com/sbidoul
Thomas Binsfeld thomas.binsfeld@acsone.eu https://github.com/ThomasBinsfeld Thomas Binsfeld thomas.binsfeld@acsone.eu https://github.com/ThomasBinsfeld
Benjamin Willig benjamin.willig@acsone.eu https://github.com/benwillig Benjamin Willig benjamin.willig@acsone.eu https://github.com/benwillig
François Honoré francois.honore@acsone.eu https://github.com/acsonefho
+11 -6
View File
@@ -1,4 +1,4 @@
Canada, France, 2017-05-12 Canada, France, 2017-10-17
Savoir-faire Linux agrees to the terms of the Odoo Corporate Contributor License Savoir-faire Linux agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0. Agreement v1.0.
@@ -8,17 +8,22 @@ declaration.
Signed, Signed,
Jérome Boisvert-Chouinard jerome.boisvertchouinard@savoirfairelinux.com https://github.com/jbchouinard João Alfredo Gama Batista joao.gama@savoirfairelinux.com https://github.com/joaoalf
List of contributors: List of contributors:
Agathe Mollé agathe.molle@savoirfairelinux.com https://github.com/Ehtaga Agathe Mollé agathe.molle@savoirfairelinux.com https://github.com/Ehtaga
Bruno Joliveau bruno.joliveau@savoirfairelinux.com https://github.com/bjoliveau Bruno Joliveau bruno.joliveau@savoirfairelinux.com https://github.com/bjoliveau
David Dufresne david.dufresne@savoirfairelinux.com https://github.com/dufresnedavid David Dufresne david.dufresne@savoirfairelinux.com https://github.com/dufresnedavid
Jérome Boisvert-Chouinard jerome.boisvertchouinard@savoirfairelinux.com https://github.com/jbchouinard Istvan SZALAÏ istvan.szalai@savoirfairelinux.com https://github.com/ventilooo
Joao Alfredo Gama Batista joao.gama@savoirfairelinux.com https://github.com/joaoalf João Alfredo Gama Batista joao.gama@savoirfairelinux.com https://github.com/joaoalf
Julie Moussu julie.mousse@savoirfairelinux.com https://github.com/JulieSFL Julien Jezequel-Breard julien.jezequel-breard@savoirfairelinux.com https://github.com/jjbreard
Pierre Lamarche pierre.lamarche@savoirfairelinux.com https://github.com/plamarche Quentin Lavallée-Bourdeau quentin.lavallee@savoirfairelinux.com https://github.com/qtiplb
Rim Ben Dhaou rim.bendhaou@savoirfairelinux.com https://github.com/rimbendhaou
Yasmine El Mrini yasmine.elmrini@savoirfairelinux.com https://github.com/yasmineelmrini
Jérome Boisvert-Chouinard jerome.boisvertchouinard@savoirfairelinux.com https://github.com/jbchouinard (up to 2017-10-17)
Julie Moussu julie.mousse@savoirfairelinux.com https://github.com/JulieSFL (up to 2017-10-17)
Pierre Lamarche pierre.lamarche@savoirfairelinux.com https://github.com/plamarche (up to 2017-10-17)
David Cormier david.cormier@savoirfairelinux.com https://github.com/cormier (up to 2017-05-12) David Cormier david.cormier@savoirfairelinux.com https://github.com/cormier (up to 2017-05-12)
Davin Baragiotta davin.baragiotta@savoirfairelinux.com https://github.com/giotta (up to 2017-05-12) Davin Baragiotta davin.baragiotta@savoirfairelinux.com https://github.com/giotta (up to 2017-05-12)
El Hadji Dem elhadji.dem@savoirfairelinux.com https://github.com/ehdem (up to 2017-05-12) El Hadji Dem elhadji.dem@savoirfairelinux.com https://github.com/ehdem (up to 2017-05-12)
@@ -25,6 +25,8 @@ class TestPyLint(TransactionCase):
'E0601', # using variable before assignment 'E0601', # using variable before assignment
'W0123', # eval used 'W0123', # eval used
'W0101', # unreachable code 'W0101', # unreachable code
'mixed-indentation',
] ]
def _skip_test(self, reason): def _skip_test(self, reason):