[MERGE] forward port branch 10.0 up to dcce040a63
This commit is contained in:
@@ -916,8 +916,7 @@ class AccountInvoice(models.Model):
|
|||||||
subtype_id=self.env.ref('mail.mt_note').id)
|
subtype_id=self.env.ref('mail.mt_note').id)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@api.multi
|
def _check_invoice_reference(self):
|
||||||
def invoice_validate(self):
|
|
||||||
for invoice in self.filtered(lambda invoice: invoice.partner_id not in invoice.message_partner_ids):
|
for invoice in self.filtered(lambda invoice: invoice.partner_id not in invoice.message_partner_ids):
|
||||||
invoice.message_subscribe([invoice.partner_id.id])
|
invoice.message_subscribe([invoice.partner_id.id])
|
||||||
|
|
||||||
@@ -927,6 +926,10 @@ class AccountInvoice(models.Model):
|
|||||||
if invoice.type in ('in_invoice', 'in_refund') and invoice.reference:
|
if invoice.type in ('in_invoice', 'in_refund') and invoice.reference:
|
||||||
if self.search([('type', '=', invoice.type), ('reference', '=', invoice.reference), ('company_id', '=', invoice.company_id.id), ('commercial_partner_id', '=', invoice.commercial_partner_id.id), ('id', '!=', invoice.id)]):
|
if self.search([('type', '=', invoice.type), ('reference', '=', invoice.reference), ('company_id', '=', invoice.company_id.id), ('commercial_partner_id', '=', invoice.commercial_partner_id.id), ('id', '!=', invoice.id)]):
|
||||||
raise UserError(_("Duplicated vendor reference detected. You probably encoded twice the same vendor bill/refund."))
|
raise UserError(_("Duplicated vendor reference detected. You probably encoded twice the same vendor bill/refund."))
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def invoice_validate(self):
|
||||||
|
self._check_invoice_reference()
|
||||||
return self.write({'state': 'open'})
|
return self.write({'state': 'open'})
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ def migrate_tags_on_taxes(cr, registry):
|
|||||||
if len(tax_id.ids) == 1:
|
if len(tax_id.ids) == 1:
|
||||||
tax_id.sudo().write({'tag_ids': [(6, 0, tax_template.tag_ids.ids)]})
|
tax_id.sudo().write({'tag_ids': [(6, 0, tax_template.tag_ids.ids)]})
|
||||||
|
|
||||||
|
def preserve_existing_tags_on_taxes(cr, registry, module):
|
||||||
|
''' This is a utility function used to preserve existing previous tags during upgrade of the module.'''
|
||||||
|
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||||
|
xml_records = env['ir.model.data'].search([('model', '=', 'account.account.tag'), ('module', 'like', module)])
|
||||||
|
if xml_records:
|
||||||
|
cr.execute("update ir_model_data set noupdate = 't' where id in %s", [tuple(xml_records.ids)])
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# Account Templates: Account, Tax, Tax Code and chart. + Wizard
|
# Account Templates: Account, Tax, Tax Code and chart. + Wizard
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|||||||
@@ -473,6 +473,8 @@ class AccountAssetDepreciationLine(models.Model):
|
|||||||
created_moves = self.env['account.move']
|
created_moves = self.env['account.move']
|
||||||
prec = self.env['decimal.precision'].precision_get('Account')
|
prec = self.env['decimal.precision'].precision_get('Account')
|
||||||
for line in self:
|
for line in self:
|
||||||
|
if line.move_id:
|
||||||
|
raise UserError(_('This depreciation is already linked to a journal entry! Please post or delete it.'))
|
||||||
category_id = line.asset_id.category_id
|
category_id = line.asset_id.category_id
|
||||||
depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
|
depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
|
||||||
company_currency = line.asset_id.company_id.currency_id
|
company_currency = line.asset_id.company_id.currency_id
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ var WidgetOnButton = core.list_widget_registry.get('field').extend({
|
|||||||
}
|
}
|
||||||
return $('<div/>').append((this.parent_state === 'open')? $('<button/>', {
|
return $('<div/>').append((this.parent_state === 'open')? $('<button/>', {
|
||||||
type: 'button',
|
type: 'button',
|
||||||
title: (this.has_value)? _t('Posted') : _t('Unposted'),
|
title: (this.is_posted)? _t('Posted') : _t('Unposted'),
|
||||||
disabled: !!this.has_value,
|
disabled: row_data.move_check.value,
|
||||||
'class': 'btn btn-sm btn-link fa fa-circle o_widgetonbutton ' + class_color,
|
'class': 'btn btn-sm btn-link fa fa-circle o_widgetonbutton ' + class_color,
|
||||||
}) : '').html();
|
}) : '').html();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,3 +4,8 @@
|
|||||||
# Copyright (c) 2008 JAILLET Simon - CrysaLEAD - www.crysalead.fr
|
# Copyright (c) 2008 JAILLET Simon - CrysaLEAD - www.crysalead.fr
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_fr')
|
||||||
|
|||||||
@@ -39,4 +39,5 @@ configuration of their taxes and fiscal positions manually.
|
|||||||
'data/account_reconcile_model_template.xml',
|
'data/account_reconcile_model_template.xml',
|
||||||
'data/account_chart_template_data.yml',
|
'data/account_chart_template_data.yml',
|
||||||
],
|
],
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_lu')
|
||||||
|
|||||||
@@ -39,4 +39,5 @@ Notes:
|
|||||||
'data/account.chart.template.csv',
|
'data/account.chart.template.csv',
|
||||||
'data/account_chart_template_data.yml',
|
'data/account_chart_template_data.yml',
|
||||||
],
|
],
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_no')
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ Updated for Odoo 9 by Bringsvor Consulting AS <www.bringsvor.com>
|
|||||||
'data/account_tax_data.xml',
|
'data/account_tax_data.xml',
|
||||||
'data/account_chart_template_data.yml'],
|
'data/account_chart_template_data.yml'],
|
||||||
"active": False,
|
"active": False,
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_pl')
|
||||||
|
|||||||
@@ -28,4 +28,5 @@ Wewnętrzny numer wersji OpenGLOBE 1.02
|
|||||||
'data/res_country_state_data.xml',
|
'data/res_country_state_data.xml',
|
||||||
'data/account_chart_template_data.yml'
|
'data/account_chart_template_data.yml'
|
||||||
],
|
],
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,8 @@
|
|||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
# Copyright (C) 2014 Tech Receptives (<http://techreceptives.com>).
|
# Copyright (C) 2014 Tech Receptives (<http://techreceptives.com>).
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_sg')
|
||||||
|
|||||||
@@ -32,4 +32,5 @@ After installing this module, the Configuration wizard for accounting is launche
|
|||||||
'data/account_tax_data.xml',
|
'data/account_tax_data.xml',
|
||||||
'data/account_chart_template_data.yml',
|
'data/account_chart_template_data.yml',
|
||||||
],
|
],
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_th')
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ Thai accounting chart and localization.
|
|||||||
'data/l10n_th_chart_data.xml',
|
'data/l10n_th_chart_data.xml',
|
||||||
'data/account_chart_template_data.yml',
|
'data/account_chart_template_data.yml',
|
||||||
],
|
],
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,8 @@
|
|||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
# This module is Copyright (c) 2009-2013 General Solutions (http://gscom.vn) All Rights Reserved.
|
# This module is Copyright (c) 2009-2013 General Solutions (http://gscom.vn) All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
|
def _preserve_tag_on_taxes(cr, registry):
|
||||||
|
from odoo.addons.account.models.chart_template import preserve_existing_tags_on_taxes
|
||||||
|
preserve_existing_tags_on_taxes(cr, registry, 'l10n_vn')
|
||||||
|
|||||||
@@ -28,5 +28,6 @@ with Chart of account under Circular No. 200/2014/TT-BTC
|
|||||||
'data/l10n_vn_chart_data.xml',
|
'data/l10n_vn_chart_data.xml',
|
||||||
'data/account_tax_data.xml',
|
'data/account_tax_data.xml',
|
||||||
'data/account_chart_template_data.yml',
|
'data/account_chart_template_data.yml',
|
||||||
]
|
],
|
||||||
|
'post_init_hook': '_preserve_tag_on_taxes',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<strong>Product:</strong><br/>
|
<strong>Product:</strong><br/>
|
||||||
<span t-field="o.product_id.code"/>
|
<span t-field="o.product_id"/>
|
||||||
<span t-field="o.product_id.name"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<strong>Quantity:</strong><br/>
|
<strong>Quantity:</strong><br/>
|
||||||
|
|||||||
@@ -235,10 +235,12 @@ var PosDB = core.Class.extend({
|
|||||||
for(var i = 0, len = partners.length; i < len; i++){
|
for(var i = 0, len = partners.length; i < len; i++){
|
||||||
partner = partners[i];
|
partner = partners[i];
|
||||||
|
|
||||||
if ( this.partner_write_date &&
|
var local_partner_date = (this.partner_write_date || '').replace(/^(\d{4}-\d{2}-\d{2}) ((\d{2}:?){3})$/, '$1T$2Z');
|
||||||
|
var dist_partner_date = (partner.write_date || '').replace(/^(\d{4}-\d{2}-\d{2}) ((\d{2}:?){3})$/, '$1T$2Z');
|
||||||
|
if ( this.partner_write_date &&
|
||||||
this.partner_by_id[partner.id] &&
|
this.partner_by_id[partner.id] &&
|
||||||
new Date(this.partner_write_date).getTime() + 1000 >=
|
new Date(local_partner_date).getTime() + 1000 >=
|
||||||
new Date(partner.write_date).getTime() ) {
|
new Date(dist_partner_date).getTime() ) {
|
||||||
// FIXME: The write_date is stored with milisec precision in the database
|
// FIXME: The write_date is stored with milisec precision in the database
|
||||||
// but the dates we get back are only precise to the second. This means when
|
// but the dates we get back are only precise to the second. This means when
|
||||||
// you read partners modified strictly after time X, you get back partners that were
|
// you read partners modified strictly after time X, you get back partners that were
|
||||||
|
|||||||
@@ -566,7 +566,7 @@ class ProductProduct(models.Model):
|
|||||||
history = self.env['product.price.history'].search([
|
history = self.env['product.price.history'].search([
|
||||||
('company_id', '=', company_id),
|
('company_id', '=', company_id),
|
||||||
('product_id', 'in', self.ids),
|
('product_id', 'in', self.ids),
|
||||||
('datetime', '<=', date or fields.Datetime.now())], limit=1)
|
('datetime', '<=', date or fields.Datetime.now())], order='datetime desc,id desc', limit=1)
|
||||||
return history.cost or 0.0
|
return history.cost or 0.0
|
||||||
|
|
||||||
def _need_procurement(self):
|
def _need_procurement(self):
|
||||||
|
|||||||
@@ -890,7 +890,7 @@ class ProcurementOrder(models.Model):
|
|||||||
date=procurement.purchase_line_id.order_id.date_order and procurement.purchase_line_id.order_id.date_order[:10],
|
date=procurement.purchase_line_id.order_id.date_order and procurement.purchase_line_id.order_id.date_order[:10],
|
||||||
uom_id=procurement.purchase_line_id.product_uom)
|
uom_id=procurement.purchase_line_id.product_uom)
|
||||||
|
|
||||||
price_unit = self.env['account.tax']._fix_tax_included_price_company(seller.price, procurement.purchase_line_id.product_id.supplier_taxes_id, procurement.purchase_line_id.taxes_id, self.company_id) if seller else 0.0
|
price_unit = self.env['account.tax']._fix_tax_included_price_company(seller.price, procurement.purchase_line_id.product_id.supplier_taxes_id, procurement.purchase_line_id.taxes_id, procurement.company_id) if seller else 0.0
|
||||||
if price_unit and seller and procurement.purchase_line_id.order_id.currency_id and seller.currency_id != procurement.purchase_line_id.order_id.currency_id:
|
if price_unit and seller and procurement.purchase_line_id.order_id.currency_id and seller.currency_id != procurement.purchase_line_id.order_id.currency_id:
|
||||||
price_unit = seller.currency_id.compute(price_unit, procurement.purchase_line_id.order_id.currency_id)
|
price_unit = seller.currency_id.compute(price_unit, procurement.purchase_line_id.order_id.currency_id)
|
||||||
|
|
||||||
|
|||||||
@@ -700,7 +700,7 @@ class SaleOrderLine(models.Model):
|
|||||||
def create(self, values):
|
def create(self, values):
|
||||||
values.update(self._prepare_add_missing_fields(values))
|
values.update(self._prepare_add_missing_fields(values))
|
||||||
line = super(SaleOrderLine, self).create(values)
|
line = super(SaleOrderLine, self).create(values)
|
||||||
if line.state == 'sale':
|
if line.order_id.state == 'sale':
|
||||||
line._action_procurement_create()
|
line._action_procurement_create()
|
||||||
msg = _("Extra line with %s ") % (line.product_id.display_name,)
|
msg = _("Extra line with %s ") % (line.product_id.display_name,)
|
||||||
line.order_id.message_post(body=msg)
|
line.order_id.message_post(body=msg)
|
||||||
|
|||||||
@@ -241,6 +241,7 @@
|
|||||||
|
|
||||||
<template id="template_location">
|
<template id="template_location">
|
||||||
<t t-call="website_event.layout">
|
<t t-call="website_event.layout">
|
||||||
|
<div class="oe_structure"/>
|
||||||
<section class="container">
|
<section class="container">
|
||||||
<h1 class="text-center">Event Location</h1>
|
<h1 class="text-center">Event Location</h1>
|
||||||
</section>
|
</section>
|
||||||
@@ -249,6 +250,7 @@
|
|||||||
"widget": "contact",
|
"widget": "contact",
|
||||||
"fields": ["name", "address", "phone", "mobile", "fax"]
|
"fields": ["name", "address", "phone", "mobile", "fax"]
|
||||||
}'/>
|
}'/>
|
||||||
|
<div class="oe_structure"/>
|
||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
<template id="agenda">
|
<template id="agenda">
|
||||||
<t t-call="website_event.layout">
|
<t t-call="website_event.layout">
|
||||||
|
<div class="oe_structure"/>
|
||||||
<section class="container">
|
<section class="container">
|
||||||
<h1 class="text-center" t-field="event.name"/>
|
<h1 class="text-center" t-field="event.name"/>
|
||||||
<div class="form-inline pull-right">
|
<div class="form-inline pull-right">
|
||||||
@@ -104,12 +105,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
<div class="oe_structure"/>
|
||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template id="tracks">
|
<template id="tracks">
|
||||||
<t t-call="website_event.event_details">
|
<t t-call="website_event.event_details">
|
||||||
|
<div class="oe_structure"/>
|
||||||
<div id="left_column">
|
<div id="left_column">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
@@ -148,6 +151,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="oe_structure"/>
|
||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -245,12 +245,13 @@ class Website(models.Model):
|
|||||||
:param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo)
|
:param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo)
|
||||||
:returns: pricelist recordset
|
:returns: pricelist recordset
|
||||||
"""
|
"""
|
||||||
website = request and request.website or None
|
website = request and hasattr(request, 'website') and request.website or None
|
||||||
if not website:
|
if not website:
|
||||||
if self.env.context.get('website_id'):
|
if self.env.context.get('website_id'):
|
||||||
website = self.browse(self.env.context['website_id'])
|
website = self.browse(self.env.context['website_id'])
|
||||||
else:
|
else:
|
||||||
website = self.search([], limit=1)
|
# In the weird case we are coming from the backend (https://github.com/odoo/odoo/issues/20245)
|
||||||
|
website = len(self) == 1 and self or self.search([], limit=1)
|
||||||
isocountry = request and request.session.geoip and request.session.geoip.get('country_code') or False
|
isocountry = request and request.session.geoip and request.session.geoip.get('country_code') or False
|
||||||
partner = self.env.user.partner_id
|
partner = self.env.user.partner_id
|
||||||
order_pl = partner.last_website_so_id and partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id
|
order_pl = partner.last_website_so_id and partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
<!-- PDF Viewer Body : contains the canvas, the loader, or the image-->
|
<!-- PDF Viewer Body : contains the canvas, the loader, or the image-->
|
||||||
<div id="PDFSlideViewer" style="position:relative;"
|
<div id="PDFSlideViewer" style="position:relative;"
|
||||||
t-attf-data-slideid="#{slide.id}"
|
t-attf-data-slideid="#{slide.id}"
|
||||||
t-attf-data-slideurl="/slides/slide/#{slide.id}/pdf_content"
|
t-attf-data-slideurl="/slides/slide/#{slug(slide)}/pdf_content"
|
||||||
t-attf-data-downloadable="#{slide.download_security}"
|
t-attf-data-downloadable="#{slide.download_security}"
|
||||||
t-att-data-defaultpage="page">
|
t-att-data-defaultpage="page">
|
||||||
<t t-if="is_embedded">
|
<t t-if="is_embedded">
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-4 text-center"></div>
|
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-4 text-center"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2 pull-right text-right">
|
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2 pull-right text-right">
|
||||||
<a t-if="slide.download_security and not is_embedded" target="_top" t-attf-href="/slides/slide/#{slide.id}/download" title="Download" id="download">
|
<a t-if="slide.download_security and not is_embedded" target="_top" t-attf-href="/slides/slide/#{slug(slide)}/download" title="Download" id="download">
|
||||||
<i class="fa fa-download fa-2x"></i>
|
<i class="fa fa-download fa-2x"></i>
|
||||||
</a>
|
</a>
|
||||||
<span id="fullscreen" title="View fullscreen">
|
<span id="fullscreen" title="View fullscreen">
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ Possible children elements of the list view are:
|
|||||||
filled, and a cross if it is not
|
filled, and a cross if it is not
|
||||||
``handle``
|
``handle``
|
||||||
for ``sequence`` fields, instead of displaying the field's value
|
for ``sequence`` fields, instead of displaying the field's value
|
||||||
just displays a dra&drop icon
|
just displays a drag&drop icon
|
||||||
``sum``, ``avg``
|
``sum``, ``avg``
|
||||||
displays the corresponding aggregate at the bottom of the column. The
|
displays the corresponding aggregate at the bottom of the column. The
|
||||||
aggregation is only computed on *currently displayed* records. The
|
aggregation is only computed on *currently displayed* records. The
|
||||||
@@ -1153,7 +1153,7 @@ Possible children elements of the search view are:
|
|||||||
fields don't generate domains.
|
fields don't generate domains.
|
||||||
|
|
||||||
.. note:: the domain and context are inclusive and both are generated
|
.. note:: the domain and context are inclusive and both are generated
|
||||||
if if a ``context`` is specified. To only generate context
|
if a ``context`` is specified. To only generate context
|
||||||
values, set ``filter_domain`` to an empty list:
|
values, set ``filter_domain`` to an empty list:
|
||||||
``filter_domain="[]"``
|
``filter_domain="[]"``
|
||||||
``groups``
|
``groups``
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import odoo
|
|||||||
from odoo import api, fields, models, modules, tools, _
|
from odoo import api, fields, models, modules, tools, _
|
||||||
from odoo.exceptions import AccessDenied, UserError
|
from odoo.exceptions import AccessDenied, UserError
|
||||||
from odoo.tools.parse_version import parse_version
|
from odoo.tools.parse_version import parse_version
|
||||||
|
from odoo.tools.misc import topological_sort
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -763,7 +764,13 @@ class Module(models.Model):
|
|||||||
filter_lang = [lang.code for lang in langs]
|
filter_lang = [lang.code for lang in langs]
|
||||||
elif not isinstance(filter_lang, (list, tuple)):
|
elif not isinstance(filter_lang, (list, tuple)):
|
||||||
filter_lang = [filter_lang]
|
filter_lang = [filter_lang]
|
||||||
mod_names = [mod.name for mod in self if mod.state in ('installed', 'to install', 'to upgrade')]
|
|
||||||
|
update_mods = self.filtered(lambda r: r.state in ('installed', 'to install', 'to upgrade'))
|
||||||
|
mod_dict = {
|
||||||
|
mod.name: mod.dependencies_id.mapped('name')
|
||||||
|
for mod in update_mods
|
||||||
|
}
|
||||||
|
mod_names = topological_sort(mod_dict)
|
||||||
self.env['ir.translation'].load_module_terms(mod_names, filter_lang)
|
self.env['ir.translation'].load_module_terms(mod_names, filter_lang)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
|||||||
@@ -304,13 +304,12 @@ class test_m2o(CreatorCase):
|
|||||||
[[False]])
|
[[False]])
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
""" Exported value is the name_get of the related object
|
""" Exported value is empty
|
||||||
"""
|
"""
|
||||||
record = self.env['export.integer'].create({'value': 42})
|
record = self.env['export.integer'].create({'value': 42})
|
||||||
name = dict(record.name_get())[record.id]
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(record.id),
|
self.export(record.id),
|
||||||
[[name]])
|
[['']])
|
||||||
|
|
||||||
def test_path(self):
|
def test_path(self):
|
||||||
""" Can recursively export fields of m2o via path
|
""" Can recursively export fields of m2o via path
|
||||||
@@ -352,14 +351,13 @@ class test_o2m(CreatorCase):
|
|||||||
def test_single(self):
|
def test_single(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export([(0, False, {'value': 42})]),
|
self.export([(0, False, {'value': 42})]),
|
||||||
# name_get result
|
[['']])
|
||||||
[[u'export.one2many.child:42']])
|
|
||||||
|
|
||||||
def test_single_subfield(self):
|
def test_single_subfield(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export([(0, False, {'value': 42})],
|
self.export([(0, False, {'value': 42})],
|
||||||
fields=['value', 'value/value']),
|
fields=['value', 'value/value']),
|
||||||
[[u'export.one2many.child:42', u'42']])
|
[['', u'42']])
|
||||||
|
|
||||||
def test_integrate_one_in_parent(self):
|
def test_integrate_one_in_parent(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -381,9 +379,13 @@ class test_o2m(CreatorCase):
|
|||||||
def test_multiple_records_name(self):
|
def test_multiple_records_name(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(self.commands, fields=['const', 'value']),
|
self.export(self.commands, fields=['const', 'value']),
|
||||||
[[
|
[
|
||||||
u'4', u','.join(self.names)
|
[u'4', ''],
|
||||||
]])
|
['', ''],
|
||||||
|
['', ''],
|
||||||
|
['', ''],
|
||||||
|
['', ''],
|
||||||
|
])
|
||||||
|
|
||||||
def test_multiple_records_id(self):
|
def test_multiple_records_id(self):
|
||||||
export = self.export(self.commands, fields=['const', 'value/.id'])
|
export = self.export(self.commands, fields=['const', 'value/.id'])
|
||||||
@@ -401,14 +403,18 @@ class test_o2m(CreatorCase):
|
|||||||
def test_multiple_records_with_name_before(self):
|
def test_multiple_records_with_name_before(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(self.commands, fields=['const', 'value', 'value/value']),
|
self.export(self.commands, fields=['const', 'value', 'value/value']),
|
||||||
[[ # exports sub-fields of very first o2m
|
[
|
||||||
u'4', u','.join(self.names), u'4'
|
[u'4', '', u'4'],
|
||||||
]])
|
['', '', u'42'],
|
||||||
|
['', '', u'36'],
|
||||||
|
['', '', u'4'],
|
||||||
|
['', '', u'13'],
|
||||||
|
])
|
||||||
|
|
||||||
def test_multiple_records_with_name_after(self):
|
def test_multiple_records_with_name_after(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(self.commands, fields=['const', 'value/value', 'value']),
|
self.export(self.commands, fields=['const', 'value/value', 'value']),
|
||||||
[ # completely ignores name_get request
|
[
|
||||||
[u'4', u'4', ''],
|
[u'4', u'4', ''],
|
||||||
['', u'42', ''],
|
['', u'42', ''],
|
||||||
['', u'36', ''],
|
['', u'36', ''],
|
||||||
@@ -459,16 +465,16 @@ class test_o2m_multiple(CreatorCase):
|
|||||||
def test_single_per_side(self):
|
def test_single_per_side(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(child1=False, child2=[(0, False, {'value': 42})]),
|
self.export(child1=False, child2=[(0, False, {'value': 42})]),
|
||||||
[[False, u'export.one2many.child.2:42']])
|
[[False, '']])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(child1=[(0, False, {'value': 43})], child2=False),
|
self.export(child1=[(0, False, {'value': 43})], child2=False),
|
||||||
[[u'export.one2many.child.1:43', False]])
|
[['', False]])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(child1=[(0, False, {'value': 43})],
|
self.export(child1=[(0, False, {'value': 43})],
|
||||||
child2=[(0, False, {'value': 42})]),
|
child2=[(0, False, {'value': 42})]),
|
||||||
[[u'export.one2many.child.1:43', u'export.one2many.child.2:42']])
|
[['', '']])
|
||||||
|
|
||||||
def test_single_integrate_subfield(self):
|
def test_single_integrate_subfield(self):
|
||||||
fields = ['const', 'child1/value', 'child2/value']
|
fields = ['const', 'child1/value', 'child2/value']
|
||||||
@@ -555,14 +561,13 @@ class test_m2m(CreatorCase):
|
|||||||
def test_single(self):
|
def test_single(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export([(0, False, {'value': 42})]),
|
self.export([(0, False, {'value': 42})]),
|
||||||
# name_get result
|
[['']])
|
||||||
[[u'export.many2many.other:42']])
|
|
||||||
|
|
||||||
def test_single_subfield(self):
|
def test_single_subfield(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export([(0, False, {'value': 42})],
|
self.export([(0, False, {'value': 42})],
|
||||||
fields=['value', 'value/value']),
|
fields=['value', 'value/value']),
|
||||||
[[u'export.many2many.other:42', u'42']])
|
[['', u'42']])
|
||||||
|
|
||||||
def test_integrate_one_in_parent(self):
|
def test_integrate_one_in_parent(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -584,10 +589,13 @@ class test_m2m(CreatorCase):
|
|||||||
def test_multiple_records_name(self):
|
def test_multiple_records_name(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.export(self.commands, fields=['const', 'value']),
|
self.export(self.commands, fields=['const', 'value']),
|
||||||
[[ # FIXME: hardcoded comma, import uses config.csv_internal_sep
|
[
|
||||||
# resolution: remove configurable csv_internal_sep
|
[u'4', ''],
|
||||||
u'4', u','.join(self.names)
|
['', ''],
|
||||||
]])
|
['', ''],
|
||||||
|
['', ''],
|
||||||
|
['', ''],
|
||||||
|
])
|
||||||
|
|
||||||
# essentially same as o2m, so boring
|
# essentially same as o2m, so boring
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -805,14 +805,8 @@ class BaseModel(object):
|
|||||||
for j, val in enumerate(lines2[0]):
|
for j, val in enumerate(lines2[0]):
|
||||||
if val or isinstance(val, bool):
|
if val or isinstance(val, bool):
|
||||||
current[j] = val
|
current[j] = val
|
||||||
# check value of current field
|
# append the other lines at the end
|
||||||
if not current[i] and not isinstance(current[i], bool):
|
lines += lines2[1:]
|
||||||
# assign xml_ids, and forget about remaining lines
|
|
||||||
xml_ids = [item[1] for item in value.name_get()]
|
|
||||||
current[i] = ','.join(xml_ids)
|
|
||||||
else:
|
|
||||||
# append the other lines at the end
|
|
||||||
lines += lines2[1:]
|
|
||||||
else:
|
else:
|
||||||
current[i] = False
|
current[i] = False
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user