summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-01-10 13:52:44 +0100
committerChristophe Simonis <chs@odoo.com>2017-01-10 13:52:44 +0100
commita2c1df8b9ca731107dd2d67cc0b2dd39d0c7ad64 (patch)
tree5de4c414a1c137c674ca004fbec6a29fc1a10db5 /addons
parentd38e00031f975db4a3d3e80250d5142444a3239b (diff)
parent557feb950cb74656c92e59a62847c9e414c9b41f (diff)
[MERGE] forward port branch saas-14 up to 557feb950cb
Diffstat (limited to 'addons')
-rw-r--r--addons/account/models/chart_template.py36
-rw-r--r--addons/account/views/res_config_view.xml7
-rw-r--r--addons/account/views/web_planner_data.xml2
-rw-r--r--addons/account_accountant/views/res_config_view.xml2
-rw-r--r--addons/auth_ldap/views/auth_ldap_config_settings_views.xml2
-rw-r--r--addons/auth_oauth/views/res_config_views.xml4
-rw-r--r--addons/barcodes/static/src/js/form_view_barcode_handler.js48
-rw-r--r--addons/base_gengo/views/res_config_views.xml16
-rw-r--r--addons/google_calendar/models/google_calendar.py27
-rw-r--r--addons/l10n_es/data/account_account_template_data.xml30
-rw-r--r--addons/l10n_mx/__manifest__.py2
-rw-r--r--addons/l10n_mx/data/fiscal_position_data.xml115
-rw-r--r--addons/l10n_mx/models/__init__.py1
-rw-r--r--addons/l10n_mx/models/res_config.py9
-rw-r--r--addons/l10n_mx/views/res_config_view.xml23
-rw-r--r--addons/mrp/models/mrp_production.py4
-rw-r--r--addons/payment_paypal/models/payment.py14
-rw-r--r--addons/payment_paypal/tests/test_paypal.py2
-rw-r--r--addons/point_of_sale/static/src/js/screens.js1
-rw-r--r--addons/sale/models/sale.py6
-rw-r--r--addons/stock/models/stock_quant.py2
-rw-r--r--addons/web/static/src/js/framework/domain_utils.js19
-rw-r--r--addons/web/static/src/js/views/form_widgets.js19
-rw-r--r--addons/web/static/src/js/views/list_view_editable.js3
-rw-r--r--addons/web/static/src/js/views/search_view.js2
-rw-r--r--addons/web/static/src/js/widgets/domain_selector.js17
-rw-r--r--addons/web/static/src/js/widgets/domain_selector_dialog.js48
-rw-r--r--addons/web/static/src/less/domain_selector.less5
-rw-r--r--addons/web/static/src/less/form_view_layout.less16
-rw-r--r--addons/web/static/src/xml/base.xml17
-rw-r--r--addons/web/views/webclient_templates.xml2
-rw-r--r--addons/web_editor/static/src/js/backend.js10
-rw-r--r--addons/web_editor/static/src/js/rte.summernote.js22
-rw-r--r--addons/web_kanban/static/src/js/kanban_view.js43
-rw-r--r--addons/web_kanban/static/src/less/kanban_view.less4
-rw-r--r--addons/website_crm/views/website_crm_config_settings_views.xml2
-rw-r--r--addons/website_livechat/views/res_config.xml2
-rw-r--r--addons/website_mass_mailing/static/src/js/website_mass_mailing.js7
-rw-r--r--addons/website_portal_sale/controllers/main.py2
-rw-r--r--addons/website_sale_delivery/views/website_config_settings_views.xml2
-rw-r--r--addons/website_slides/view/res_config.xml2
-rw-r--r--addons/website_twitter/views/website_twitter_settings_views.xml2
42 files changed, 470 insertions, 129 deletions
diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py
index 2f5f40df280..37bcefb2675 100644
--- a/addons/account/models/chart_template.py
+++ b/addons/account/models/chart_template.py
@@ -350,6 +350,26 @@ class AccountChartTemplate(models.Model):
new_xml_id = str(company.id)+'_'+template_xmlid.name
return ir_model_data._update(model, template_xmlid.module, vals, xml_id=new_xml_id, store=True, noupdate=True, mode='init', res_id=False)
+ def _get_account_vals(self, company, account_template, code_acc, tax_template_ref):
+ """ This method generates a dictionnary of all the values for the account that will be created.
+ """
+ self.ensure_one()
+ tax_ids = []
+ for tax in account_template.tax_ids:
+ tax_ids.append(tax_template_ref[tax.id])
+ val = {
+ 'name': account_template.name,
+ 'currency_id': account_template.currency_id and account_template.currency_id.id or False,
+ 'code': code_acc,
+ 'user_type_id': account_template.user_type_id and account_template.user_type_id.id or False,
+ 'reconcile': account_template.reconcile,
+ 'note': account_template.note,
+ 'tax_ids': [(6, 0, tax_ids)],
+ 'company_id': company.id,
+ 'tag_ids': [(6, 0, [t.id for t in account_template.tag_ids])],
+ }
+ return val
+
@api.multi
def generate_account(self, tax_template_ref, acc_template_ref, code_digits, company):
""" This method for generating accounts from templates.
@@ -365,25 +385,11 @@ class AccountChartTemplate(models.Model):
account_tmpl_obj = self.env['account.account.template']
acc_template = account_tmpl_obj.search([('nocreate', '!=', True), ('chart_template_id', '=', self.id)], order='id')
for account_template in acc_template:
- tax_ids = []
- for tax in account_template.tax_ids:
- tax_ids.append(tax_template_ref[tax.id])
-
code_main = account_template.code and len(account_template.code) or 0
code_acc = account_template.code or ''
if code_main > 0 and code_main <= code_digits:
code_acc = str(code_acc) + (str('0'*(code_digits-code_main)))
- vals = {
- 'name': account_template.name,
- 'currency_id': account_template.currency_id and account_template.currency_id.id or False,
- 'code': code_acc,
- 'user_type_id': account_template.user_type_id and account_template.user_type_id.id or False,
- 'reconcile': account_template.reconcile,
- 'note': account_template.note,
- 'tax_ids': [(6, 0, tax_ids)],
- 'company_id': company.id,
- 'tag_ids': [(6, 0, [t.id for t in account_template.tag_ids])],
- }
+ vals = self._get_account_vals(company, account_template, code_acc, tax_template_ref)
new_account = self.create_record_with_xmlid(company, account_template, 'account.account', vals)
acc_template_ref[account_template.id] = new_account
return acc_template_ref
diff --git a/addons/account/views/res_config_view.xml b/addons/account/views/res_config_view.xml
index b387d32d3fe..14b4f4000a0 100644
--- a/addons/account/views/res_config_view.xml
+++ b/addons/account/views/res_config_view.xml
@@ -144,7 +144,7 @@
</div>
</div>
<h2>Invoicing</h2>
- <div class="row mt16 o_settings_container">
+ <div class="row mt16 o_settings_container" id="invoicing_settings">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="group_proforma_invoices"/>
@@ -176,11 +176,6 @@
<div class="text-muted">
Mail your invoices in one-click using <a href="https://www.docsaway.com/">Docsaway</a>
</div>
- <div id="print_docsway_message" class="content-group" attrs="{'invisible': [('module_print_docsaway', '=', False)]}">
- <div class="text-warning mt16 mb4">
- Save this page and come back here to set up the feature.
- </div>
- </div>
</div>
</div>
</div>
diff --git a/addons/account/views/web_planner_data.xml b/addons/account/views/web_planner_data.xml
index b3569deb76b..abd637d87d5 100644
--- a/addons/account/views/web_planner_data.xml
+++ b/addons/account/views/web_planner_data.xml
@@ -98,7 +98,7 @@
<th>Terms &amp; Conditions</th>
<td></td>
<td>
- <a class="fa fa-arrow-right" t-attf-href="#{prepare_backend_url('sales_team.action_sale_config', 'form')}&amp;id=#{company_id.id}" target="_blank">
+ <a class="fa fa-arrow-right" t-attf-href="#{prepare_backend_url('sales_team.action_sale_config', 'form')}" target="_blank">
Change
</a>
</td>
diff --git a/addons/account_accountant/views/res_config_view.xml b/addons/account_accountant/views/res_config_view.xml
index dff65902427..a356583bc93 100644
--- a/addons/account_accountant/views/res_config_view.xml
+++ b/addons/account_accountant/views/res_config_view.xml
@@ -66,7 +66,7 @@
<div class="o_setting_right_pane">
<label for="id" string="Cash Basis"/>
<div class="text-muted">
- Declare taxes at payment date.
+ Journal used to declare taxes at payment date
</div>
<field name="tax_cash_basis_journal_id"/>
</div>
diff --git a/addons/auth_ldap/views/auth_ldap_config_settings_views.xml b/addons/auth_ldap/views/auth_ldap_config_settings_views.xml
index 67d14215027..344aeda46b1 100644
--- a/addons/auth_ldap/views/auth_ldap_config_settings_views.xml
+++ b/addons/auth_ldap/views/auth_ldap_config_settings_views.xml
@@ -6,7 +6,7 @@
<field name="inherit_id" ref="base_setup.base_config_settings_view_form"/>
<field name="arch" type="xml">
<div name='auth_ldap_right_pane' position="inside">
- <div>
+ <div attrs="{'invisible': [('module_auth_ldap','=',False)]}">
<button type="action" name="%(auth_ldap.action_ldap_installer)d" string="LDAP Server" icon="fa-arrow-right" class="btn-link"/>
</div>
</div>
diff --git a/addons/auth_oauth/views/res_config_views.xml b/addons/auth_oauth/views/res_config_views.xml
index 4f0912afa18..0bc57df9127 100644
--- a/addons/auth_oauth/views/res_config_views.xml
+++ b/addons/auth_oauth/views/res_config_views.xml
@@ -6,14 +6,14 @@
<field name="inherit_id" ref="base_setup.base_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="msg_module_auth_oauth" position="replace">
- <div class="content-group">
+ <div class="content-group" attrs="{'invisible': [('module_auth_oauth','=',False)]}">
<div class="mt16">
<button type="action" name="%(auth_oauth.action_oauth_provider)d" string="OAuth Providers" icon="fa-arrow-right" class="btn-link"/>
</div>
</div>
</div>
<div id="module_auth_oauth" position="after">
- <div class="col-xs-12 col-md-6 o_setting_box">
+ <div class="col-xs-12 col-md-6 o_setting_box" attrs="{'invisible': [('module_auth_oauth','=',False)]}">
<div class="o_setting_left_pane">
<field name="auth_oauth_google_enabled"/>
</div>
diff --git a/addons/barcodes/static/src/js/form_view_barcode_handler.js b/addons/barcodes/static/src/js/form_view_barcode_handler.js
index 7f2614f0ef1..524ec1513c3 100644
--- a/addons/barcodes/static/src/js/form_view_barcode_handler.js
+++ b/addons/barcodes/static/src/js/form_view_barcode_handler.js
@@ -28,6 +28,8 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
this.__quantity_listener = _.bind(this._set_quantity_listener, this);
BarcodeHandlerMixin.init.apply(this, arguments);
+ this.process_barcode_mutex = new utils.Mutex();
+
return this._super.apply(this, arguments);
},
@@ -153,25 +155,35 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
else if (this.form_view.get('actual_mode') === 'view')
this._display_no_edit_mode_warning();
else {
- // Call hook method possibly implemented by subclass
- this.pre_onchange_hook(barcode).then(function(proceed) {
- if (proceed === true) {
- // Wait for hypothetical ongoing onchange to finish
- self.form_view.onchanges_mutex.exec(function() {
- // A real onchange is triggered when a value actually changes (which can correspond
- // to a widget's blur event per example). Commit the value of fields before
- // programmatically triggering an onchange to be consistent with this.
- var mutex_commit_value = new utils.Mutex();
- _.each(self.form_view.fields, function(field) {
- mutex_commit_value.exec(_.bind(field.commit_value, field));
- });
- return mutex_commit_value.def.then(function(){
- // Trigger the barcode onchange
- self.set_value(barcode);
- });
- });
+ var process_barcode = function () {
+ // this function can be passed to `Mutex.exec` in order to make sure
+ // that every ongoing onchanges in the form view are done
+ var form_onchanges_mutex = function () {
+ return self.form_view.onchanges_mutex.def;
}
- });
+
+ // before setting the barcode field with the received barcode, we commit
+ // every fields of the form view and we wait for their hypothetical ongoing
+ // onchanges to finish
+ var commit_mutex = new utils.Mutex();
+ _.each(self.form_view.fields, function (field) {
+ commit_mutex.exec(function () {
+ return field.commit_value();
+ });
+ commit_mutex.exec(form_onchanges_mutex);
+ });
+
+ return commit_mutex.def.then(function () {
+ return self.pre_onchange_hook(barcode).then(function (proceed) {
+ if (proceed) {
+ self.set_value(barcode); // set the barcode field with the received one
+ return form_onchanges_mutex(); // wait for its onchange to finish
+ }
+ });
+ });
+ };
+
+ this.process_barcode_mutex.exec(process_barcode);
}
},
diff --git a/addons/base_gengo/views/res_config_views.xml b/addons/base_gengo/views/res_config_views.xml
index a78bf51c07f..66546b2d1e5 100644
--- a/addons/base_gengo/views/res_config_views.xml
+++ b/addons/base_gengo/views/res_config_views.xml
@@ -7,32 +7,32 @@
<field name="arch" type="xml">
<xpath expr="//div[@name='base_gengo_right_pane']" position="inside">
<div name="base_gengo_right_pane" position="replace">
- <label for="id" string="Public Key"/>
- <div name="gengo_public_key">
+ <label for="id" string="Public Key" attrs="{'invisible': [('module_base_gengo','=',False)]}"/>
+ <div name="gengo_public_key" attrs="{'invisible': [('module_base_gengo','=',False)]}">
<div name="gengo_public_key">
<field name="gengo_public_key" nolabel="1" placeholder="Add Gengo login Public Key..."/>
</div>
</div>
- <label for="id" string="Private Key"/>
- <div name="gengo_private_key">
+ <label for="id" string="Private Key" attrs="{'invisible': [('module_base_gengo','=',False)]}"/>
+ <div name="gengo_private_key" attrs="{'invisible': [('module_base_gengo','=',False)]}">
<div name="gengo_private_key">
<field name="gengo_private_key" password="True" nolabel="1" placeholder="Add Gengo login Private Key..."/>
</div>
</div>
- <div name="gengo_auto_approve">
+ <div name="gengo_auto_approve" attrs="{'invisible': [('module_base_gengo','=',False)]}">
<div name="gengo_auto_approve">
<field name="gengo_auto_approve"/>
<label for="id" string="Auto Approve Translation"/>
</div>
</div>
- <div name="gengo_sandbox">
+ <div name="gengo_sandbox" attrs="{'invisible': [('module_base_gengo','=',False)]}">
<div name="gengo_sandbox">
<field name="gengo_sandbox"/>
<label for="id" string="Sandbox Mode"/>
</div>
</div>
- <label for="id" string="Comment"/>
- <div name="gengo_comment">
+ <label for="id" string="Comment" attrs="{'invisible': [('module_base_gengo','=',False)]}"/>
+ <div name="gengo_comment" attrs="{'invisible': [('module_base_gengo','=',False)]}">
<div name="gengo_comment">
<field name="gengo_comment" nolabel="1" placeholder="Add your comments here for translator...."/>
</div>
diff --git a/addons/google_calendar/models/google_calendar.py b/addons/google_calendar/models/google_calendar.py
index 7a5fda8575e..007bbffeaf9 100644
--- a/addons/google_calendar/models/google_calendar.py
+++ b/addons/google_calendar/models/google_calendar.py
@@ -402,6 +402,20 @@ class GoogleCalendar(models.AbstractModel):
data_json = json.dumps(data)
return self.env['google.service']._do_request(url, data_json, headers, type='PUT')
+ def create_from_google(self, event, partner_id):
+ context_tmp = dict(self._context, NewMeeting=True)
+ res = self.with_context(context_tmp).update_from_google(False, event.GG.event, "create")
+ event.OE.event_id = res
+ meeting = self.env['calendar.event'].browse(res)
+ attendee_record = self.env['calendar.attendee'].search([('partner_id', '=', partner_id), ('event_id', '=', res)])
+ attendee_record.with_context(context_tmp).write({'oe_synchro_date': meeting.oe_update_date, 'google_internal_event_id': event.GG.event['id']})
+ if meeting.recurrency:
+ attendees = self.env['calendar.attendee'].sudo().search([('google_internal_event_id', '=ilike', '%s\_%%' % event.GG.event['id'])])
+ excluded_recurrent_event_ids = set(attendee.event_id for attendee in attendees)
+ for event in excluded_recurrent_event_ids:
+ event.write({'recurrent_id': meeting.id, 'recurrent_id_date': event.start, 'user_id': meeting.user_id.id})
+ return event
+
def update_from_google(self, event, single_event_dict, type):
""" Update an event in Odoo with information from google calendar
:param event : record od calendar.event to update
@@ -786,13 +800,8 @@ class GoogleCalendar(models.AbstractModel):
if isinstance(actToDo, NothingToDo):
continue
elif isinstance(actToDo, Create):
- context_tmp = {'newMeeting': True}
if actSrc == 'GG':
- res = recs.with_context(context_tmp).update_from_google(False, event.GG.event, "create")
- event.OE.event_id = res
- meeting = CalendarEvent.browse(res)
- attendee_records = CalendarAttendee.search([('partner_id', '=', my_partner_id), ('event_id', '=', res)])
- attendee_records.with_context(context_tmp).write({'oe_synchro_date': meeting.oe_update_date, 'google_internal_event_id': event.GG.event['id']})
+ self.create_from_google(event, my_partner_id)
elif actSrc == 'OE':
raise "Should be never here, creation for OE is done before update !"
#TODO Add to batch
@@ -817,6 +826,12 @@ class GoogleCalendar(models.AbstractModel):
main_ev = CalendarAttendee.with_context(context_novirtual).search([('google_internal_event_id', '=', event.GG.event['id'].rsplit('_', 1)[0])], limit=1)
event_to_synchronize[base_event][0][1].OE.event_id = main_ev.event_id.id
+ if event_to_synchronize[base_event][0][1].OE.event_id:
+ parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].OE.event_id, new_google_event_id)
+ res = self.update_from_google(parent_event, event.GG.event, "copy")
+ else:
+ self.create_from_google(event, my_partner_id)
+
parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].OE.event_id, new_google_event_id)
res = recs.update_from_google(parent_event, event.GG.event, "copy")
else:
diff --git a/addons/l10n_es/data/account_account_template_data.xml b/addons/l10n_es/data/account_account_template_data.xml
index 4c86cb55442..455d8132f04 100644
--- a/addons/l10n_es/data/account_account_template_data.xml
+++ b/addons/l10n_es/data/account_account_template_data.xml
@@ -1568,28 +1568,28 @@
<field name="code">4700</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, deudora por IVA</field>
- <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
+ <field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4708_child" model="account.account.template">
<field name="code">4708</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, deudora por subvenciones concedidas</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4709_child" model="account.account.template">
<field name="code">4709</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, deudora por devolución de impuestos</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_471_child" model="account.account.template">
<field name="code">471</field>
<field name="reconcile" eval="False"/>
<field name="name">Organismos de la Seguridad Social, deudores</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_472_child" model="account.account.template">
@@ -1603,77 +1603,77 @@
<field name="code">473</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, retenciones y pagos a cuenta</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4740_child" model="account.account.template">
<field name="code">4740</field>
<field name="reconcile" eval="False"/>
<field name="name">Activos por diferencias temporarias deducibles</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_non_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4742_child" model="account.account.template">
<field name="code">4742</field>
<field name="reconcile" eval="False"/>
<field name="name">Derechos por deducciones y bonificaciones pendientes de aplicar</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_non_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4745_child" model="account.account.template">
<field name="code">4745</field>
<field name="reconcile" eval="False"/>
<field name="name">Crédito por pérdidas a compensar del ejercicio</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_non_current_assets"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4750_child" model="account.account.template">
<field name="code">4750</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, acreedora por IVA</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4751_child" model="account.account.template">
<field name="code">4751</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, acreedora por retenciones practicadas</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4752_child" model="account.account.template">
<field name="code">4752</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, acreedora por impuesto sobre sociedades</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_4758_child" model="account.account.template">
<field name="code">4758</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública, acreedora por subvenciones a reintegrar</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_476_child" model="account.account.template">
<field name="code">476</field>
<field name="reconcile" eval="False"/>
<field name="name">Organismos de la Seguridad Social, acreedores</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_477_child" model="account.account.template">
<field name="code">477</field>
<field name="reconcile" eval="True"/>
<field name="name">Hacienda Pública. IVA repercutido</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_479_child" model="account.account.template">
<field name="code">479</field>
<field name="reconcile" eval="False"/>
<field name="name">Pasivos por diferencias temporarias imponibles</field>
- <field name="user_type_id" ref="account.data_account_type_expenses"/>
+ <field name="user_type_id" ref="account.data_account_type_non_current_liabilities"/>
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
</record>
<record id="pgc_480_child" model="account.account.template">
diff --git a/addons/l10n_mx/__manifest__.py b/addons/l10n_mx/__manifest__.py
index 4d804ad96a6..8ec93d7a7e3 100644
--- a/addons/l10n_mx/__manifest__.py
+++ b/addons/l10n_mx/__manifest__.py
@@ -40,5 +40,7 @@ With this module you will have:
"data/account_data.xml",
"data/account_tax_data.xml",
"data/account_chart_template_data.yml",
+ "data/fiscal_position_data.xml",
+ "views/res_config_view.xml",
],
}
diff --git a/addons/l10n_mx/data/fiscal_position_data.xml b/addons/l10n_mx/data/fiscal_position_data.xml
new file mode 100644
index 00000000000..cc22638112f
--- /dev/null
+++ b/addons/l10n_mx/data/fiscal_position_data.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" ?>
+<odoo>
+ <data noupdate="1">
+ <record id="account_fiscal_position_personasmoralesdelrgimengeneral0" model="account.fiscal.position">
+ <field name="name">Personas morales del régimen general</field>
+ <field name="note">Es para las sociedades mercantiles, asociaciones civiles de profesionales que:
+
+- Realicen actividades lucrativas,
+- Sociedades cooperativas de producción,
+- Instituciones de crédito tales como bancos y casas de bolsa,
+- Organismos descentralizados que comercialicen bienes o servicios, entre otras.
+
+
+http://www.sat.gob.mx/6_406.html
+
+última modificación :
+16/febrero/2010, 12:56, información vigente.</field>
+ </record>
+
+ <record id="account_fiscal_position_personasmoralesconfinesnolucrativos0" model="account.fiscal.position">
+ <field name="name">Personas morales con fines no lucrativos</field>
+ <field name="note">Es para las personas morales cuya finalidad no es obtener una ganancia económica o lucro, por ejemplo:
+
+- Instituciones de asistencia o de beneficencia
+- Asociaciones o sociedades civiles con fines políticos o deportivos
+- Asociaciones religiosas
+- Asociaciones patronales; sindicatos obreros; cámaras de comercio e industria
+- Asociaciones o sociedades civiles de enseñanza; de investigación científica o tecnológica
+- Sociedades cooperativas de consumo o sociedades mutualistas.
+- Colegios de profesionales
+- Partidos políticos
+- Asociaciones de padres de familia
+- Asociaciones civiles de colonos o las que administren inmuebles en condominio
+
+
+http://www.sat.gob.mx/6_404.html
+
+última modificación :
+16/febrero/2010, 12:57, información vigente.</field>
+ </record>
+
+ <record id="account_fiscal_position_asociacionesreligiosas0" model="account.fiscal.position">
+ <field name="name">Asociaciones Religiosas</field>
+ <field name="note">Son congregaciones que tienen como fin el ejercer culto a una divinidad; para efectos fiscales, se considerarán a las iglesias y demás agrupaciones que obtengan su correspondiente registro constitutivo ante la Secretaría de Gobernación, en los términos de la Ley de Asociaciones Religiosas y Culto Público, ya que es a través de este registro como se obtiene la personalidad jurídica.
+
+
+http://www.sat.gob.mx/sitio_internet/asistencia_contribuyente/principiantes/permonl/68_1813.html
+
+última modificación :
+10/abril/2012, 18:15, información vigente.</field>
+ </record>
+
+ <record id="account_fiscal_position_personasmoralesdelrgimensimplificado0" model="account.fiscal.position">
+ <field name="name">Personas morales del régimen simplificado</field>
+ <field name="note">Deben tributar en el régimen simplificado las siguientes personas morales:
+
+- Las dedicadas exclusivamente al autotransporte terrestre de carga o de pasajeros.
+
+- Las que se dediquen exclusivamente a actividades:
+ 1) Agrícolas
+ 2) Ganaderas
+ 3) Silvícolas
+ 4) Pesqueras
+
+- Las constituidas como empresas integradoras.
+
+
+http://www.sat.gob.mx/6_405.html
+última modificación :
+24/agosto/2009, 12:03, información vigente
+
+ </field>
+ </record>
+
+ <record id="account_fiscal_position_personafisicaconactividadempresarial0" model="account.fiscal.position">
+ <field name="name">Persona física con actividad empresarial</field>
+ <field name="note">Es el régimen conforme al cual pueden pagar sus impuestos todas las personas físicas que se dediquen a las siguientes actividades
+
+- Comerciales.
+
+- Industriales, que consisten en la extracción, conservación o transformación de materias primas, acabado de productos y la elaboración de satisfactores;
+
+- Agrícolas, que comprenden las actividades de siembra, cultivo, cosecha y la primera enajenación de los productos obtenidos, que no hayan sido objeto de transformación industrial;
+
+- Ganaderas, que son las consistentes en la cría y engorda de ganado, aves de corral y animales, así como la primera enajenación de sus productos, que no hayan sido objeto de transformación industrial;
+
+- De pesca, que incluyen la cría, cultivo, fomento y cuidado de la reproducción de toda clase de especies marinas y de agua dulce, incluida la acuacultura, así como la captura y extracción de las mismas y la primera enajenación de sus productos, que no hayan sido objeto de transformación industrial;
+
+- Silvícolas, que son las de cultivo de los bosques o montes, así como la cría, conservación, restauración, fomento y aprovechamiento de la vegetación de los mismos y la primera enajenación de sus productos, que no hayan sido objeto de transformación industrial.
+
+
+http://www.sat.gob.mx/sitio_internet/asistencia_contribuyente/principiantes/empresarial/11_428.html
+última modificación :
+12/septiembre/2005, 15:58, información vigente
+ </field>
+ </record>
+
+ <record id="account_fiscal_position_foreign" model="account.fiscal.position">
+ <field name="name">Foreign Customer</field>
+ </record>
+
+ <record id="account_fiscal_position0_purchase" model="account.fiscal.position.tax">
+ <field name="tax_src_id" ref="l10n_mx.1_tax14"/>
+ <field name="tax_dest_id" ref="l10n_mx.1_tax13"/>
+ <field name="position_id" ref="account_fiscal_position_foreign"/>
+ </record>
+
+ <record id="account_fiscal_position0_sale" model="account.fiscal.position.tax">
+ <field name="tax_src_id" ref="l10n_mx.1_tax12"/>
+ <field name="tax_dest_id" ref="l10n_mx.1_tax9"/>
+ <field name="position_id" ref="account_fiscal_position_foreign"/>
+ </record>
+
+ </data>
+</odoo>
diff --git a/addons/l10n_mx/models/__init__.py b/addons/l10n_mx/models/__init__.py
index 5376a315b04..f2b298f3cb9 100644
--- a/addons/l10n_mx/models/__init__.py
+++ b/addons/l10n_mx/models/__init__.py
@@ -4,3 +4,4 @@
from . import chart_template
from . import account
+from . import res_config
diff --git a/addons/l10n_mx/models/res_config.py b/addons/l10n_mx/models/res_config.py
new file mode 100644
index 00000000000..913a422cf4b
--- /dev/null
+++ b/addons/l10n_mx/models/res_config.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+from odoo import fields, models
+
+
+class AccountConfigSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ module_l10n_mx_edi = fields.Boolean('Mexican Electronic Invoicing')
diff --git a/addons/l10n_mx/views/res_config_view.xml b/addons/l10n_mx/views/res_config_view.xml
new file mode 100644
index 00000000000..d5f59f6937f
--- /dev/null
+++ b/addons/l10n_mx/views/res_config_view.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="account_config_settings_account_mx_inherit" model="ir.ui.view">
+ <field name="name">account.config.settings.form.inherit</field>
+ <field name="model">account.config.settings</field>
+ <field name="inherit_id" ref="account.account_config_settings_view_form"/>
+ <field name="arch" type="xml">
+ <xpath expr=".//div[@id='invoicing_settings']" position="inside">
+ <div class="col-xs-12 col-md-6 o_setting_box">
+ <div class="o_setting_left_pane">
+ <field name="module_l10n_mx_edi" class="oe_inline" widget="upgrade_boolean"/>
+ </div>
+ <div class="o_setting_right_pane">
+ <label for="module_l10n_mx_edi"/>
+ <div class="text-muted">
+ Create your electronic invoices automatically (CFDI format)
+ </div>
+ </div>
+ </div>
+ </xpath>
+ </field>
+ </record>
+</odoo>
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index a6e20c46bd2..bf145c9d59e 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -271,8 +271,8 @@ class MrpProduction(models.Model):
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
production._generate_raw_moves(lines)
# Check for all draft moves whether they are mto or not
- self._adjust_procure_method()
- self.move_raw_ids.action_confirm()
+ production._adjust_procure_method()
+ production.move_raw_ids.action_confirm()
return True
def _generate_finished_moves(self):
diff --git a/addons/payment_paypal/models/payment.py b/addons/payment_paypal/models/payment.py
index 6aaff94a631..60c5f57ea51 100644
--- a/addons/payment_paypal/models/payment.py
+++ b/addons/payment_paypal/models/payment.py
@@ -4,6 +4,9 @@ import json
import logging
import urlparse
+import dateutil.parser
+import pytz
+
from odoo import api, fields, models, _
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment_paypal.controllers.main import PaypalController
@@ -193,7 +196,16 @@ class TxPaypal(models.Model):
}
if status in ['Completed', 'Processed']:
_logger.info('Validated Paypal payment for tx %s: set as done' % (self.reference))
- res.update(state='done', date_validate=data.get('payment_date', fields.datetime.now()))
+ try:
+ # dateutil and pytz don't recognize abbreviations PDT/PST
+ tzinfos = {
+ 'PST': -8 * 3600,
+ 'PDT': -7 * 3600,
+ }
+ date_validate = dateutil.parser.parse(data.get('payment_date'), tzinfos=tzinfos).astimezone(pytz.utc)
+ except:
+ date_validate = fields.Datetime.now()
+ res.update(state='done', date_validate=date_validate)
return self.write(res)
elif status in ['Pending', 'Expired']:
_logger.info('Received notification for Paypal payment %s: set as pending' % (self.reference))
diff --git a/addons/payment_paypal/tests/test_paypal.py b/addons/payment_paypal/tests/test_paypal.py
index 7cbe98f1a6b..c6a44dec41f 100644
--- a/addons/payment_paypal/tests/test_paypal.py
+++ b/addons/payment_paypal/tests/test_paypal.py
@@ -187,4 +187,4 @@ class PaypalForm(PaypalCommon):
# check
self.assertEqual(tx.state, 'done', 'paypal: wrong state after receiving a valid pending notification')
self.assertEqual(tx.acquirer_reference, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification')
- self.assertEqual(tx.date_validate, '2013-11-18 03:21:19', 'paypal: wrong validation date')
+ self.assertEqual(tx.date_validate, '2013-11-18 11:21:19', 'paypal: wrong validation date')
diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js
index 5f61deb5e0c..f9cf49864d2 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -1432,6 +1432,7 @@ var ReceiptScreenWidget = ScreenWidget.extend({
print_xml: function() {
var env = {
widget: this,
+ order: this.pos.get_order(),
receipt: this.pos.get_order().export_for_printing(),
paymentlines: this.pos.get_order().get_paymentlines()
};
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index b88542f04e6..25fe10b5315 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -502,10 +502,14 @@ class SaleOrder(models.Model):
res = {}
currency = self.currency_id or self.company_id.currency_id
for line in self.order_line:
+ base_tax = 0
for tax in line.tax_id:
group = tax.tax_group_id
res.setdefault(group, 0.0)
- res[group] += tax.compute_all(line.price_reduce, quantity=line.product_uom_qty)['taxes'][0]['amount']
+ amount = tax.compute_all(line.price_reduce + base_tax, quantity=line.product_uom_qty)['taxes'][0]['amount']
+ res[group] += amount
+ if tax.include_base_amount:
+ base_tax += amount
res = sorted(res.items(), key=lambda l: l[0].sequence)
res = map(lambda l: (l[0].name, l[1]), res)
return res
diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py
index f52f6dc331d..9c95a6682ac 100644
--- a/addons/stock/models/stock_quant.py
+++ b/addons/stock/models/stock_quant.py
@@ -44,7 +44,7 @@ class Quant(models.Model):
lot_id = fields.Many2one(
'stock.production.lot', 'Lot/Serial Number',
index=True, ondelete="restrict", readonly=True)
- cost = fields.Float('Unit Cost')
+ cost = fields.Float('Unit Cost', group_operator='avg')
owner_id = fields.Many2one(
'res.partner', 'Owner',
index=True, readonly=True,
diff --git a/addons/web/static/src/js/framework/domain_utils.js b/addons/web/static/src/js/framework/domain_utils.js
new file mode 100644
index 00000000000..8cefb7cabbe
--- /dev/null
+++ b/addons/web/static/src/js/framework/domain_utils.js
@@ -0,0 +1,19 @@
+odoo.define("web.domainUtils", function (require) {
+"use strict";
+
+var pyeval = require("web.pyeval");
+
+function domainToString(domain) {
+ if (_.isString(domain)) return domain;
+ return JSON.stringify(domain || []).replace(/false/g, "False").replace(/true/g, "True");
+}
+function stringToDomain(domain) {
+ if (!_.isString(domain)) return domain;
+ return pyeval.eval("domain", domain || "[]");
+}
+
+return {
+ domainToString: domainToString,
+ stringToDomain: stringToDomain,
+};
+});
diff --git a/addons/web/static/src/js/views/form_widgets.js b/addons/web/static/src/js/views/form_widgets.js
index a3c7bcaaff3..78d8ea7c5d1 100644
--- a/addons/web/static/src/js/views/form_widgets.js
+++ b/addons/web/static/src/js/views/form_widgets.js
@@ -11,6 +11,7 @@ var Priority = require('web.Priority');
var ProgressBar = require('web.ProgressBar');
var Dialog = require('web.Dialog');
var DomainSelector = require("web.DomainSelector");
+var DomainSelectorDialog = require("web.DomainSelectorDialog");
var common = require('web.form_common');
var formats = require('web.formats');
var framework = require('web.framework');
@@ -400,11 +401,19 @@ var FieldDomain = common.AbstractField.extend(common.ReinitializeFieldMixin).ext
e.preventDefault();
this._showSelection();
},
+ "click .o_form_field_domain_dialog_button": function (e) {
+ e.preventDefault();
+ this.openDomainDialog();
+ },
},
custom_events: {
"domain_changed": function (e) {
+ if (this.options.in_dialog) return;
this.set_value(this.domainSelector.getDomain(), true);
},
+ "domain_selected": function (e) {
+ this.set_value(e.data.domain);
+ },
},
init: function () {
this._super.apply(this, arguments);
@@ -412,6 +421,7 @@ var FieldDomain = common.AbstractField.extend(common.ReinitializeFieldMixin).ext
this.valid = true;
this.debug = session.debug;
this.options = _.defaults(this.options || {}, {
+ in_dialog: false,
model: undefined, // this option is mandatory !
fs_filters: {}, // Field selector filters (to only show a subset of available fields @see FieldSelector)
});
@@ -457,7 +467,7 @@ var FieldDomain = common.AbstractField.extend(common.ReinitializeFieldMixin).ext
this.domainSelector.destroy();
}
this.domainSelector = new DomainSelector(this, this.model, domain, {
- readonly: this.get("effective_readonly"),
+ readonly: this.get("effective_readonly") || this.options.in_dialog,
fs_filters: this.options.fs_filters,
debugMode: session.debug,
});
@@ -492,6 +502,13 @@ var FieldDomain = common.AbstractField.extend(common.ReinitializeFieldMixin).ext
disable_multiple_selection: true,
}).open();
},
+ openDomainDialog: function () {
+ new DomainSelectorDialog(this, this.model, this.get("value"), {
+ readonly: this.get("effective_readonly"),
+ fs_filters: this.options.fs_filters,
+ debugMode: session.debug,
+ }).open();
+ },
});
var FieldDate = common.AbstractField.extend(common.ReinitializeFieldMixin, {
diff --git a/addons/web/static/src/js/views/list_view_editable.js b/addons/web/static/src/js/views/list_view_editable.js
index 3f5d39e60e1..ef9bf1a6062 100644
--- a/addons/web/static/src/js/views/list_view_editable.js
+++ b/addons/web/static/src/js/views/list_view_editable.js
@@ -641,7 +641,8 @@ ListView.include(/** @lends instance.web.ListView# */{
if (saveInfo.created) {
return self.start_edition();
}
- var record = self.records[next_record](saveInfo.record);
+ var options = { wraparound: !self.is_action_enabled('create') };
+ var record = self.records[next_record](saveInfo.record, options);
if (record === undefined) {
return self.start_edition();
}
diff --git a/addons/web/static/src/js/views/search_view.js b/addons/web/static/src/js/views/search_view.js
index 9f985fc3f49..65dbb4557e7 100644
--- a/addons/web/static/src/js/views/search_view.js
+++ b/addons/web/static/src/js/views/search_view.js
@@ -466,7 +466,7 @@ var SearchView = View.extend({
*/
select_completion: function (e, ui) {
e.preventDefault();
- if(ui.item.facet.values && ui.item.facet.values.length && String(ui.item.facet.values[0].value).trim() !== "") {
+ if(ui.item.facet && ui.item.facet.values && ui.item.facet.values.length && String(ui.item.facet.values[0].value).trim() !== "") {
this.query.add(ui.item.facet);
} else {
this.query.trigger('add');
diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js
index 5f4287a8d8d..15e967ff4d4 100644
--- a/addons/web/static/src/js/widgets/domain_selector.js
+++ b/addons/web/static/src/js/widgets/domain_selector.js
@@ -3,9 +3,9 @@ odoo.define("web.DomainSelector", function (require) {
var core = require("web.core");
var datepicker = require("web.datepicker");
+var domainUtils = require("web.domainUtils");
var formats = require ("web.formats");
var ModelFieldSelector = require("web.ModelFieldSelector");
-var pyeval = require("web.pyeval");
var Widget = require("web.Widget");
var _t = core._t;
@@ -55,7 +55,7 @@ var DomainNode = Widget.extend({
},
/// A DomainNode needs a model and domain to work. It can also receives a set of options
/// @param model - a string with the model name
- /// @param domain - an array of the prefix representation of the domain
+ /// @param domain - an array of the prefix representation of the domain (or a string which represents it)
/// @param options - an object with possible values:
/// - readonly, a boolean to indicate if the widget is readonly or not (default to true)
/// - fs_filters, an object with a series of filters to use for the field selector (see @FieldSelector)
@@ -109,7 +109,7 @@ var DomainTree = DomainNode.extend({
/// @see DomainTree._addFlattenedChildren
init: function (parent, model, domain, options) {
this._super.apply(this, arguments);
- this._initialize(domain);
+ this._initialize(domainUtils.stringToDomain(domain));
},
/// @see DomainTree.init
_initialize: function (domain) {
@@ -265,8 +265,9 @@ var DomainSelector = DomainTree.extend({
/// the widget is re-rendered and notifies the parents. If not, a warning is shown to the
/// user and the input is ignored.
"change .o_domain_debug_input": function (e) {
+ var domain;
try {
- var domain = pyeval.eval("domain", $(e.currentTarget).val() || "[]");
+ domain = domainUtils.stringToDomain($(e.currentTarget).val());
} catch (err) {
this.do_warn(_t("Syntax error"), _t("The domain you entered is not properly formed"));
return;
@@ -292,12 +293,7 @@ var DomainSelector = DomainTree.extend({
// Display technical domain if in debug mode
this.$debugInput = this.$(".o_domain_debug_input");
if (this.$debugInput.length) {
- var strValue = this.getDomain() || "[]";
- if (!_.isString(strValue)) { // TODO there is no "pyuneval" function
- strValue = JSON.stringify(strValue);
- strValue = strValue.replace(/false/g, "False").replace(/true/g, "True");
- }
- this.$debugInput.val(strValue);
+ this.$debugInput.val(domainUtils.domainToString(this.getDomain()));
}
},
});
@@ -328,6 +324,7 @@ var DomainLeaf = DomainNode.extend({
init: function (parent, model, domain, options) {
this._super.apply(this, arguments);
+ domain = domainUtils.stringToDomain(domain);
this.chain = domain[0][0];
this.operator = domain[0][1];
this.value = domain[0][2];
diff --git a/addons/web/static/src/js/widgets/domain_selector_dialog.js b/addons/web/static/src/js/widgets/domain_selector_dialog.js
new file mode 100644
index 00000000000..47bfa4e1359
--- /dev/null
+++ b/addons/web/static/src/js/widgets/domain_selector_dialog.js
@@ -0,0 +1,48 @@
+odoo.define("web.DomainSelectorDialog", function (require) {
+"use strict";
+
+var core = require("web.core");
+var Dialog = require("web.Dialog");
+var DomainSelector = require("web.DomainSelector");
+
+var _t = core._t;
+
+return Dialog.extend({
+ init: function (parent, model, domain, options) {
+ this.model = model;
+ this.options = _.extend({
+ readonly: true,
+ fs_filters: {},
+ debugMode: false,
+ }, options || {});
+
+ var buttons;
+ if (this.options.readonly) {
+ buttons = [
+ {text: _t("Close"), close: true},
+ ];
+ } else {
+ buttons = [
+ {text: _t("Save"), classes: "btn-primary", close: true, click: function () {
+ this.trigger_up("domain_selected", {domain: this.domainSelector.getDomain()});
+ }},
+ {text: _t("Discard"), close: true},
+ ];
+ }
+
+ this._super(parent, _.extend({}, {
+ title: _t("Domain"),
+ buttons: buttons,
+ }, options || {}));
+
+ this.domainSelector = new DomainSelector(this, model, domain, options);
+ },
+ start: function () {
+ this.$el.css("overflow", "visible").closest(".modal-dialog").css("height", "auto"); // This restores default modal height (bootstrap) and allows field selector to overflow
+ return $.when(
+ this._super.apply(this, arguments),
+ this.domainSelector.appendTo(this.$el)
+ );
+ },
+});
+});
diff --git a/addons/web/static/src/less/domain_selector.less b/addons/web/static/src/less/domain_selector.less
index 7dced900b21..f3917526ec5 100644
--- a/addons/web/static/src/less/domain_selector.less
+++ b/addons/web/static/src/less/domain_selector.less
@@ -24,7 +24,10 @@
&.o_domain_selector {
&.o_edit_mode {
position: relative;
- padding-right: @o-domain-selector-panel-space;
+
+ > .o_domain_node_children_container {
+ padding-right: @o-domain-selector-panel-space;
+ }
}
> .o_domain_node_children_container {
diff --git a/addons/web/static/src/less/form_view_layout.less b/addons/web/static/src/less/form_view_layout.less
index 281cf0d217e..fc5522035e5 100644
--- a/addons/web/static/src/less/form_view_layout.less
+++ b/addons/web/static/src/less/form_view_layout.less
@@ -91,7 +91,7 @@
// Title
.oe_title {
> h1, > h2, > h3 {
- width: 100%; // Needed because inline-block when is a hx.o_row
+ width: 100%; // Needed because inline-block when is a hx.o_row
margin-top: 0;
margin-bottom: 0;
line-height: inherit;
@@ -276,6 +276,20 @@
padding: 0 1em;
}
}
+
+ .o_form_field_domain {
+ > .o_form_field_domain_panel {
+ margin-top: 8px;
+ }
+ &.o_inline_mode.o_edit_mode {
+ position: relative;
+
+ > .o_form_field_domain_panel {
+ .o-position-absolute(0, 0);
+ margin-top: 0;
+ }
+ }
+ }
}
// Overriden style when form view in modal
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index f6ac60c4d7e..2ee261a3bdd 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -670,13 +670,16 @@
t-att-maxlength="widget.field.size"/>
</t>
-<div t-name="FieldDomain" class="o_form_field_domain">
+<div t-name="FieldDomain" t-attf-class="o_form_field_domain#{widget.get('effective_readonly') ? '' : ' o_edit_mode'}#{widget.options.in_dialog ? '' : ' o_inline_mode'}">
<!-- domain selector will be instantiated here -->
- <div class="mt8">
+ <div class="o_form_field_domain_panel">
<i class="fa fa-arrow-right"/>
- <span><span class="o_domain_records_count"/> Records Selected</span>
- <button class="btn btn-default btn-xs o_domain_show_selection_button" type="button">See selection</button>
+ <button class="btn btn-xs btn-default o_domain_show_selection_button" type="button">
+ <span class="o_domain_records_count"/> record(s)
+ </button>
<span class="text-warning o_domain_error_message hidden"><i class="fa fa-exclamation-triangle"/> Invalid domain</span>
+ <button t-if="widget.options.in_dialog &amp;&amp; !widget.get('effective_readonly')"
+ class="btn btn-sm btn-primary o_form_field_domain_dialog_button">Edit domain</button>
</div>
</div>
@@ -684,7 +687,7 @@
<div t-if="!widget.readonly &amp;&amp; !widget.noControlPanel" class="btn-group btn-group-sm pull-right o_domain_node_control_panel">
<button class="btn btn-default o_domain_delete_node_button"><i class="fa fa-minus"/></button>
<button class="btn btn-default o_domain_add_node_button"><i class="fa fa-plus"/></button>
- <button class="btn btn-default o_domain_add_node_button" t-att-data-branch="1"><i class="fa fa-ellipsis-h"/></button>
+ <button class="btn btn-default o_domain_add_node_button" data-branch="1"><i class="fa fa-ellipsis-h"/></button>
</div>
</t>
<t t-name="DomainTree.OperatorSelector">
@@ -712,9 +715,9 @@
</t>
<t t-else="">
<div>
- <t t-if="widget.children.length === 1">Match the records with the following rule:</t>
+ <t t-if="widget.children.length === 1">Match records with the following rule:</t>
<t t-else="">
- <span>Match the records with</span>
+ <span>Match records with</span>
<t t-call="DomainTree.OperatorSelector"/>
<span>of the following rules:</span>
</t>
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 533e8e8b23a..c0a9b2c372f 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -134,6 +134,7 @@
<script type="text/javascript" src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/data_model.js"></script>
+ <script type="text/javascript" src="/web/static/src/js/framework/domain_utils.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/formats.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/view.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/pyeval.js"></script>
@@ -155,6 +156,7 @@
<script type="text/javascript" src="/web/static/src/js/widgets/debug_manager.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/data_export.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/date_picker.js"></script>
+ <script type="text/javascript" src="/web/static/src/js/widgets/domain_selector_dialog.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/domain_selector.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/loading.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/model_field_selector.js"></script>
diff --git a/addons/web_editor/static/src/js/backend.js b/addons/web_editor/static/src/js/backend.js
index 9c6f1df5e8c..ce8643f04de 100644
--- a/addons/web_editor/static/src/js/backend.js
+++ b/addons/web_editor/static/src/js/backend.js
@@ -161,6 +161,11 @@ var FieldTextHtmlSimple = widget.extend({
return !this.get('value') || this.get('value') === "<p><br/></p>" || !this.get('value').match(/\S/);
},
commit_value: function () {
+ /* Switch to WYSIWYG mode if currently in code view */
+ if (session.debug) {
+ var layoutInfo = this.$textarea.data('layoutInfo');
+ $.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo, false);
+ }
if (this.options['style-inline']) {
transcoder.class_to_style(this.$content);
transcoder.font_to_img(this.$content);
@@ -377,6 +382,11 @@ var FieldTextHtml = widget.extend({
this._dirty_flag = false;
return this.editor.save();
} else if (this._dirty_flag && this.editor && this.editor.buildingBlock) {
+ /* Switch to WYSIWYG mode if currently in code view */
+ if (session.debug) {
+ var layoutInfo = this.editor.rte.editable().data('layoutInfo');
+ $.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo, false);
+ }
this.editor.buildingBlock.clean_for_save();
this.internal_set_value( this.$content.html() );
}
diff --git a/addons/web_editor/static/src/js/rte.summernote.js b/addons/web_editor/static/src/js/rte.summernote.js
index 1789ed69e7e..9f908a245bc 100644
--- a/addons/web_editor/static/src/js/rte.summernote.js
+++ b/addons/web_editor/static/src/js/rte.summernote.js
@@ -511,12 +511,32 @@ function prettify_html(html) {
}
return result;
}
-$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo) {
+
+/*
+ * This override when clicking on the 'Code View' button has two aims:
+ *
+ * - have our own code view implementation for FieldTextHtml
+ * - add an 'enable' paramater to call the function directly and allow us to
+ * disable (false) or enable (true) the code view mode.
+ */
+$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo, enable) {
+ if (layoutInfo === undefined) {
+ return;
+ }
if (layoutInfo.toolbar) {
+ // if editor inline (FieldTextHtmlSimple)
+ var is_activated = $.summernote.eventHandler.modules.codeview.isActivated(layoutInfo);
+ if (is_activated === enable) {
+ return;
+ }
return eventHandler.modules.codeview.toggle(layoutInfo);
} else {
+ // if editor iframe (FieldTextHtml)
var $editor = layoutInfo.editor();
var $textarea = $editor.prev('textarea');
+ if ($textarea.is('textarea') === enable) {
+ return;
+ }
if (!$textarea.length) {
// init and create texarea
diff --git a/addons/web_kanban/static/src/js/kanban_view.js b/addons/web_kanban/static/src/js/kanban_view.js
index 4917c24b241..7cce7617da9 100644
--- a/addons/web_kanban/static/src/js/kanban_view.js
+++ b/addons/web_kanban/static/src/js/kanban_view.js
@@ -710,24 +710,19 @@ var KanbanView = View.extend({
var context = {};
context['default_' + this.group_by_field] = column.id;
var name = event.data.value;
- this.dataset.name_create(name, context).then(function on_success (data) {
+ this.dataset.name_create(name).done(function(data) {
add_record(data[0]);
- }, function on_fail (event) {
+ }).fail(function(error, event) {
event.preventDefault();
- var popup = new form_common.SelectCreatePopup(this);
- popup.select_element(
- self.model,
- {
- title: _t("Create: "),
- initial_view: "form",
- disable_multiple_selection: true
- },
- [],
- {"default_name": name}
- );
- popup.on("elements_selected", self, function(element_ids) {
- add_record(element_ids[0]);
- });
+ var dialog = new form_common.FormViewDialog(self, {
+ res_model: self.model,
+ context: _.extend({"default_name": name}, context),
+ title: _t("Create"),
+ disable_multiple_selection: true,
+ on_selected: function(element_ids) {
+ add_record(element_ids[0]);
+ }
+ }).open();
});
function add_record(id) {
@@ -817,8 +812,20 @@ function transform_qweb_template (node, fvg, many2manys) {
} else if (fields_registry.contains(ftype)) {
// do nothing, the kanban record will handle it
} else {
- node.tag = qweb.prefix;
- node.attrs[qweb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
+ if (node.attrs.bold) {
+ node.tag = 'strong';
+ var children_node = {
+ attrs: {},
+ children: [],
+ tag: qweb.prefix,
+ };
+ children_node.attrs[qweb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
+ node.children.push(children_node);
+ } else {
+ node.tag = qweb.prefix;
+ node.attrs[qweb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
+ }
+
}
break;
case 'button':
diff --git a/addons/web_kanban/static/src/less/kanban_view.less b/addons/web_kanban/static/src/less/kanban_view.less
index 877559ddf1f..0640fe9f3e3 100644
--- a/addons/web_kanban/static/src/less/kanban_view.less
+++ b/addons/web_kanban/static/src/less/kanban_view.less
@@ -65,7 +65,9 @@
}
.o_dropdown_kanban {
- float: right;
+ position: absolute;
+ top: 5px;
+ right: 10px;
@media (max-width: @screen-xs-max) {
visibility: visible;
}
diff --git a/addons/website_crm/views/website_crm_config_settings_views.xml b/addons/website_crm/views/website_crm_config_settings_views.xml
index 8f8c4e9dbe6..a141b4e4509 100644
--- a/addons/website_crm/views/website_crm_config_settings_views.xml
+++ b/addons/website_crm/views/website_crm_config_settings_views.xml
@@ -6,7 +6,7 @@
<field name="inherit_id" ref="website.website_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="msg_contact_form_install_setting" position="after">
- <div class="content-group mt16">
+ <div class="content-group mt16" attrs="{'invisible': [('module_website_crm', '=', False)]}">
<div class="row">
<label class="col-md-3 o_light_label" string="Sales Channel" for="crm_default_team_id"/>
<field name="crm_default_team_id" class="oe_inline"/>
diff --git a/addons/website_livechat/views/res_config.xml b/addons/website_livechat/views/res_config.xml
index b50e2f6c1cf..03189ce1d70 100644
--- a/addons/website_livechat/views/res_config.xml
+++ b/addons/website_livechat/views/res_config.xml
@@ -7,7 +7,7 @@
<field name="inherit_id" ref="website.website_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="msg_module_website_livechat" position="replace">
- <div class="content-group mt16">
+ <div class="content-group mt16" attrs="{'invisible': [('module_website_livechat', '=', False)]}">
<div class="row">
<label class="col-md-3 o_light_label" string="Channel" for="channel_id"/>
<field name="channel_id" class="oe_inline"/>
diff --git a/addons/website_mass_mailing/static/src/js/website_mass_mailing.js b/addons/website_mass_mailing/static/src/js/website_mass_mailing.js
index a9e8ea86273..ae499fe2438 100644
--- a/addons/website_mass_mailing/static/src/js/website_mass_mailing.js
+++ b/addons/website_mass_mailing/static/src/js/website_mass_mailing.js
@@ -124,8 +124,11 @@ animation.registry.newsletter_popup = animation.Class.extend({
odoo.define('mass_mailing.unsubscribe', function (require) {
var ajax = require('web.ajax');
+ var core = require('web.core');
require('web_editor.base'); // wait for implicit dependencies to load
+ var _t = core._t;
+
if (!$('.o_unsubscribe_form').length) {
return $.Deferred().reject("DOM doesn't contain '.o_unsubscribe_form'");
}
@@ -148,10 +151,10 @@ odoo.define('mass_mailing.unsubscribe', function (require) {
ajax.jsonRpc('/mail/mailing/unsubscribe', 'call', {'opt_in_ids': checked_ids, 'opt_out_ids': unchecked_ids, 'email': email, 'mailing_id': mailing_id})
.then(function(result) {
- $('.alert-info').html('Your changes has been saved.').removeClass('alert-info').addClass('alert-success');
+ $('.alert-info').html(_t('Your changes have been saved.')).removeClass('alert-info').addClass('alert-success');
})
.fail(function() {
- $('.alert-info').html('You changes has not been saved, try again later.').removeClass('alert-info').addClass('alert-warning');
+ $('.alert-info').html(_t('Your changes have not been saved, try again later.')).removeClass('alert-info').addClass('alert-warning');
});
});
});
diff --git a/addons/website_portal_sale/controllers/main.py b/addons/website_portal_sale/controllers/main.py
index 40d840029a6..e421a9ce8b0 100644
--- a/addons/website_portal_sale/controllers/main.py
+++ b/addons/website_portal_sale/controllers/main.py
@@ -217,7 +217,7 @@ class website_account(website_account):
partner = request.env['res.users'].browse(request.uid).partner_id
invoices = request.env['account.invoice'].sudo().search_count([('partner_id', '=', partner.id), ('state', 'not in', ['draft', 'cancel'])])
if invoices:
- if data.get('vat', partner.vat) != partner.vat:
+ if (data.get('vat', partner.vat) or False) != partner.vat:
error['vat'] = 'error'
error_message.append(_('Changing VAT number is not allowed once invoices have been issued for your account. Please contact us directly for this operation.'))
if data.get('name', partner.name) != partner.name:
diff --git a/addons/website_sale_delivery/views/website_config_settings_views.xml b/addons/website_sale_delivery/views/website_config_settings_views.xml
index 61cde1a3e9e..f36e98a110a 100644
--- a/addons/website_sale_delivery/views/website_config_settings_views.xml
+++ b/addons/website_sale_delivery/views/website_config_settings_views.xml
@@ -6,7 +6,7 @@
<field name="inherit_id" ref="website_sale.website_config_settings_view_form_inherit_website_sale"/>
<field name="arch" type="xml">
<div id="msg_delivery_method_setting" position="replace">
- <div class="content-group">
+ <div class="content-group" attrs="{'invisible': [('module_website_sale_delivery', '=', False)]}">
<div class="mt16">
<button type="action" name="%(delivery.action_delivery_carrier_form)d" string="Delivery Methods" class="btn-link" icon="fa-arrow-right"/>
</div>
diff --git a/addons/website_slides/view/res_config.xml b/addons/website_slides/view/res_config.xml
index d035371572b..955b92e5eae 100644
--- a/addons/website_slides/view/res_config.xml
+++ b/addons/website_slides/view/res_config.xml
@@ -6,7 +6,7 @@
<field name="inherit_id" ref="website.website_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="msg_slides_install_setting" position="replace">
- <div class="content-group" groups="base.group_no_one">
+ <div class="content-group" groups="base.group_no_one" attrs="{'invisible': [('module_website_slides', '=', False)]}">
<div class="row mt16">
<label class="col-md-3 o_light_label" for="website_slide_google_app_key"/>
<field name="website_slide_google_app_key" class="oe_inline"/>
diff --git a/addons/website_twitter/views/website_twitter_settings_views.xml b/addons/website_twitter/views/website_twitter_settings_views.xml
index 230be8a19b2..224e9f34c29 100644
--- a/addons/website_twitter/views/website_twitter_settings_views.xml
+++ b/addons/website_twitter/views/website_twitter_settings_views.xml
@@ -6,7 +6,7 @@
<field name="inherit_id" ref="website.website_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="msg_twitter_roller_install_setting" position="replace">
- <div class="content-group">
+ <div class="content-group" attrs="{'invisible': [('module_website_twitter', '=', False)]}">
<div class="mt16">
<div class="row">
<label class="col-md-3 o_light_label" string="API Key" for="twitter_api_key"/>