[MERGE] forward port branch saas-11.2 up to c834c0f587
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
<!--Email template -->
|
||||
<record id="email_template_edi_invoice" model="mail.template">
|
||||
<field name="name">Invoicing: Invoice email</field>
|
||||
<field name="email_from">${(object.user_id.email and '%s <%s>' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
|
||||
<field name="email_from">${(object.user_id.email and '"%s" <%s>' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
|
||||
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a'})</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
|
||||
@@ -1374,8 +1374,6 @@ class AccountInvoice(models.Model):
|
||||
else:
|
||||
payment_method = self.env.ref('account.account_payment_method_manual_out')
|
||||
journal_payment_methods = pay_journal.outbound_payment_method_ids
|
||||
if payment_method not in journal_payment_methods:
|
||||
raise UserError(_('No appropriate payment method enabled on journal %s') % pay_journal.name)
|
||||
|
||||
communication = self.type in ('in_invoice', 'in_refund') and self.reference or self.number
|
||||
if self.origin:
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
import calendar
|
||||
import time
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import fields, models, api, _
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo.tools.float_utils import float_round, float_is_zero
|
||||
|
||||
|
||||
@@ -63,6 +65,61 @@ Best Regards,'''))
|
||||
account_setup_coa_done = fields.Boolean(string='Chart of Account Checked', help="Technical field holding the status of the chart of account setup step.")
|
||||
account_setup_bar_closed = fields.Boolean(string='Setup Bar Closed', help="Technical field set to True when setup bar has been closed by the user.")
|
||||
|
||||
@api.multi
|
||||
def _check_lock_dates(self, vals):
|
||||
'''Check the lock dates for the current companies. This can't be done in a api.constrains because we need
|
||||
to perform some comparison between new/old values. This method forces the lock dates to be irreversible.
|
||||
|
||||
* You cannot define stricter conditions on advisors than on users. Then, the lock date on advisor must be set
|
||||
after the lock date for users.
|
||||
* You cannot lock a period that is not finished yet. Then, the lock date for advisors must be set after the
|
||||
last day of the previous month.
|
||||
* The new lock date for advisors must be set after the previous lock date.
|
||||
|
||||
:param vals: The values passed to the write method.
|
||||
'''
|
||||
period_lock_date = vals.get('period_lock_date') and\
|
||||
time.strptime(vals['period_lock_date'], DEFAULT_SERVER_DATE_FORMAT)
|
||||
fiscalyear_lock_date = vals.get('fiscalyear_lock_date') and\
|
||||
time.strptime(vals['fiscalyear_lock_date'], DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
previous_month = datetime.strptime(fields.Date.today(), DEFAULT_SERVER_DATE_FORMAT) + relativedelta(months=-1)
|
||||
days_previous_month = calendar.monthrange(previous_month.year, previous_month.month)
|
||||
previous_month = previous_month.replace(day=days_previous_month[1]).timetuple()
|
||||
for company in self:
|
||||
old_fiscalyear_lock_date = company.fiscalyear_lock_date and\
|
||||
time.strptime(company.fiscalyear_lock_date, DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
# The user attempts to remove the lock date for advisors
|
||||
if old_fiscalyear_lock_date and not fiscalyear_lock_date and 'fiscalyear_lock_date' in vals:
|
||||
raise ValidationError(_('The lock date for advisors is irreversible and can\'t be removed.'))
|
||||
|
||||
# The user attempts to set a lock date for advisors prior to the previous one
|
||||
if old_fiscalyear_lock_date and fiscalyear_lock_date and fiscalyear_lock_date < old_fiscalyear_lock_date:
|
||||
raise ValidationError(_('The new lock date for advisors must be set after the previous lock date.'))
|
||||
|
||||
# In case of no new fiscal year in vals, fallback to the oldest
|
||||
if not fiscalyear_lock_date:
|
||||
if old_fiscalyear_lock_date:
|
||||
fiscalyear_lock_date = old_fiscalyear_lock_date
|
||||
else:
|
||||
continue
|
||||
|
||||
# The user attempts to set a lock date for advisors prior to the last day of previous month
|
||||
if fiscalyear_lock_date > previous_month:
|
||||
raise ValidationError(_('You cannot lock a period that is not finished yet. Please make sure that the lock date for advisors is not set after the last day of the previous month.'))
|
||||
|
||||
# In case of no new period lock date in vals, fallback to the one defined in the company
|
||||
if not period_lock_date:
|
||||
if company.period_lock_date:
|
||||
period_lock_date = time.strptime(company.period_lock_date, DEFAULT_SERVER_DATE_FORMAT)
|
||||
else:
|
||||
continue
|
||||
|
||||
# The user attempts to set a lock date for advisors prior to the lock date for users
|
||||
if period_lock_date < fiscalyear_lock_date:
|
||||
raise ValidationError(_('You cannot define stricter conditions on advisors than on users. Please make sure that the lock date on advisor is set before the lock date for users.'))
|
||||
|
||||
@api.model
|
||||
def _verify_fiscalyear_last_day(self, company_id, last_day, last_month):
|
||||
company = self.browse(company_id)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
|
||||
from odoo.osv.orm import except_orm
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from calendar import monthrange
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo.tests import tagged
|
||||
|
||||
@@ -14,14 +16,16 @@ class TestPeriodState(AccountingTestCase):
|
||||
def setUp(self):
|
||||
super(TestPeriodState, self).setUp()
|
||||
self.user_id = self.env.user
|
||||
self.day_before_yesterday = datetime.now() - timedelta(2)
|
||||
self.yesterday = datetime.now() - timedelta(1)
|
||||
self.yesterday_str = self.yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
last_day_month = datetime.now() - relativedelta(months=1)
|
||||
last_day_month = last_day_month.replace(day=monthrange(last_day_month.year, last_day_month.month)[1])
|
||||
self.last_day_month_str = last_day_month.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
#make sure there is no unposted entry
|
||||
draft_entries = self.env['account.move'].search([('date', '<=', self.yesterday_str), ('state', '=', 'draft')])
|
||||
draft_entries = self.env['account.move'].search([('date', '<=', self.last_day_month_str), ('state', '=', 'draft')])
|
||||
if draft_entries:
|
||||
draft_entries.post()
|
||||
self.user_id.company_id.write({'fiscalyear_lock_date': self.yesterday_str})
|
||||
self.user_id.company_id.fiscalyear_lock_date = self.last_day_month_str
|
||||
self.sale_journal_id = self.env['account.journal'].search([('type', '=', 'sale')])[0]
|
||||
self.account_id = self.env['account.account'].search([('internal_type', '=', 'receivable')])[0]
|
||||
|
||||
@@ -30,7 +34,7 @@ class TestPeriodState(AccountingTestCase):
|
||||
move = self.env['account.move'].create({
|
||||
'name': '/',
|
||||
'journal_id': self.sale_journal_id.id,
|
||||
'date': self.day_before_yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'date': self.last_day_month_str,
|
||||
'line_ids': [(0, 0, {
|
||||
'name': 'foo',
|
||||
'debit': 10,
|
||||
|
||||
@@ -42,6 +42,12 @@ class TestReconciliation(AccountingTestCase):
|
||||
self.diff_income_account = self.env['res.users'].browse(self.env.uid).company_id.income_currency_exchange_account_id
|
||||
self.diff_expense_account = self.env['res.users'].browse(self.env.uid).company_id.expense_currency_exchange_account_id
|
||||
|
||||
self.inbound_payment_method = self.env['account.payment.method'].create({
|
||||
'name': 'inbound',
|
||||
'code': 'IN',
|
||||
'payment_type': 'inbound',
|
||||
})
|
||||
|
||||
def create_invoice(self, type='out_invoice', invoice_amount=50, currency_id=None):
|
||||
#we create an invoice in given currency
|
||||
invoice = self.account_invoice_model.create({'partner_id': self.partner_agrolait_id,
|
||||
@@ -709,6 +715,49 @@ class TestReconciliation(AccountingTestCase):
|
||||
credit_aml.with_context(invoice_id=inv.id).remove_move_reconcile()
|
||||
self.assertAlmostEquals(inv.residual, 111)
|
||||
|
||||
def test_revert_payment_and_reconcile(self):
|
||||
payment = self.env['account.payment'].create({
|
||||
'payment_method_id': self.inbound_payment_method.id,
|
||||
'payment_type': 'inbound',
|
||||
'partner_type': 'customer',
|
||||
'partner_id': self.partner_agrolait_id,
|
||||
'journal_id': self.bank_journal_usd.id,
|
||||
'payment_date': '2018-06-04',
|
||||
'amount': 666,
|
||||
})
|
||||
payment.post()
|
||||
|
||||
self.assertEqual(len(payment.move_line_ids), 2)
|
||||
|
||||
bank_line = payment.move_line_ids.filtered(lambda l: l.account_id.id == self.bank_journal_usd.default_debit_account_id.id)
|
||||
customer_line = payment.move_line_ids - bank_line
|
||||
|
||||
self.assertEqual(len(bank_line), 1)
|
||||
self.assertEqual(len(customer_line), 1)
|
||||
self.assertNotEqual(bank_line.id, customer_line.id)
|
||||
|
||||
self.assertEqual(bank_line.move_id.id, customer_line.move_id.id)
|
||||
move = bank_line.move_id
|
||||
|
||||
# Reversing the payment's move
|
||||
reversed_move_list = move.reverse_moves('2018-06-04')
|
||||
self.assertEqual(len(reversed_move_list), 1)
|
||||
reversed_move = self.env['account.move'].browse(reversed_move_list[0])
|
||||
|
||||
self.assertEqual(len(reversed_move.line_ids), 2)
|
||||
|
||||
# Testing the reconciliation matching between the move lines and their reversed counterparts
|
||||
reversed_bank_line = reversed_move.line_ids.filtered(lambda l: l.account_id.id == self.bank_journal_usd.default_debit_account_id.id)
|
||||
reversed_customer_line = reversed_move.line_ids - reversed_bank_line
|
||||
|
||||
self.assertEqual(len(reversed_bank_line), 1)
|
||||
self.assertEqual(len(reversed_customer_line), 1)
|
||||
self.assertNotEqual(reversed_bank_line.id, reversed_customer_line.id)
|
||||
self.assertEqual(reversed_bank_line.move_id.id, reversed_customer_line.move_id.id)
|
||||
|
||||
self.assertEqual(reversed_bank_line.full_reconcile_id.id, bank_line.full_reconcile_id.id)
|
||||
self.assertEqual(reversed_customer_line.full_reconcile_id.id, customer_line.full_reconcile_id.id)
|
||||
|
||||
def test_partial_reconcile_currencies_02(self):
|
||||
####
|
||||
# Day 1: Invoice Cust/001 to customer (expressed in USD)
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="partner_id"
|
||||
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"/>
|
||||
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
|
||||
attrs="{'readonly': [('parent_state', '=', 'posted')]}"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Information">
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
{
|
||||
'name' : 'Irreversible Lock Date',
|
||||
'version' : '1.0',
|
||||
'category': 'Accounting',
|
||||
'description': """
|
||||
Make the lock date irreversible:
|
||||
|
||||
* You cannot define stricter conditions on advisors than on users. Then, the lock date on advisor must be set before the lock date for users.
|
||||
* You cannot lock a period that is not finished yet. Then, the lock date for advisors must be set before the last day of the previous month.
|
||||
* The new lock date for advisors must be set after the previous lock date.
|
||||
""",
|
||||
'depends' : ['account'],
|
||||
'data': [],
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import res_company
|
||||
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, api
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
# fiscalyear_lock_date can't be set to a prior date
|
||||
if 'fiscalyear_lock_date' in vals or 'period_lock_date' in vals:
|
||||
self._check_lock_dates(vals)
|
||||
return super(ResCompany, self).write(vals)
|
||||
@@ -97,6 +97,7 @@ class AccountAnalyticAccount(models.Model):
|
||||
domain=domain + [('amount', '>=', 0.0)],
|
||||
fields=['account_id', 'currency_id', 'amount'],
|
||||
groupby=['account_id', 'currency_id'],
|
||||
lazy=False,
|
||||
)
|
||||
data_credit = defaultdict(float)
|
||||
for l in credit_groups:
|
||||
@@ -106,6 +107,7 @@ class AccountAnalyticAccount(models.Model):
|
||||
domain=domain + [('amount', '<', 0.0)],
|
||||
fields=['account_id', 'currency_id', 'amount'],
|
||||
groupby=['account_id', 'currency_id'],
|
||||
lazy=False,
|
||||
)
|
||||
data_debit = defaultdict(float)
|
||||
for l in debit_groups:
|
||||
|
||||
@@ -64,12 +64,14 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
'position': 'fixed',
|
||||
'top': '50%',
|
||||
'transform': 'translateY(-50%)',
|
||||
'opacity': 0,
|
||||
'z-index': '-1',
|
||||
},
|
||||
});
|
||||
// Avoid to show autocomplete for a non appearing input
|
||||
this.$barcodeInput.attr('autocomplete', 'off');
|
||||
}
|
||||
|
||||
this.__removeBarcodeField = _.debounce(this._removeBarcodeField, this.inputTimeOut);
|
||||
this.__blurBarcodeInput = _.debounce(this._blurBarcodeInput, this.inputTimeOut);
|
||||
},
|
||||
|
||||
handle_buffered_keys: function() {
|
||||
@@ -232,7 +234,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
this.max_time_between_keys_in_ms);
|
||||
}
|
||||
// if the barcode input doesn't receive keydown for a while, remove it.
|
||||
this.__removeBarcodeField();
|
||||
this.__blurBarcodeInput();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -247,21 +249,22 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
var barcodeValue = this.$barcodeInput.val();
|
||||
if (barcodeValue.match(this.regexp)) {
|
||||
core.bus.trigger('barcode_scanned', barcodeValue, $(e.target).parent()[0]);
|
||||
this.$barcodeInput.val('');
|
||||
this._blurBarcodeInput();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the temporary input created to store the barcode value.
|
||||
* If nothing happens, this input will be removed, so the focus will be lost
|
||||
* and the virtual keyboard on mobile devices will be closed.
|
||||
* Removes the value and focus from the barcode input.
|
||||
* If nothing happens, the focus will be lost and
|
||||
* the virtual keyboard on mobile devices will be closed.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_removeBarcodeField: function () {
|
||||
_blurBarcodeInput: function () {
|
||||
if (this.$barcodeInput) {
|
||||
// Reset the value and remove from the DOM.
|
||||
this.$barcodeInput.val('').remove();
|
||||
// Close the virtual keyboard on mobile browsers
|
||||
// FIXME: actually we can't prevent keyboard from opening
|
||||
this.$barcodeInput.val('').blur();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ msgstr "Bağlantı Modeli"
|
||||
#. module: base_automation
|
||||
#: model:ir.model.fields,field_description:base_automation.field_base_automation__binding_type
|
||||
msgid "Binding Type"
|
||||
msgstr ""
|
||||
msgstr "Bağlantı Türü"
|
||||
|
||||
#. module: base_automation
|
||||
#: selection:base.automation.lead.test,state:0
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
# * base_geolocalize
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux <mat@odoo.com>, 2017
|
||||
# Martin Trigaux, 2017
|
||||
# Ahmet Altinisik <aaltinisik@altinkaya.com.tr>, 2017
|
||||
# Ayhan KIZILTAN <akiziltan76@hotmail.com>, 2017
|
||||
# gezgin biri <gezginbiri@hotmail.com>, 2017
|
||||
# Murat Kaplan <muratk@projetgrup.com>, 2017
|
||||
# Matanat Ahmadova <ahmadova.matanat01@gmail.com>, 2017
|
||||
# Umur Akın <umura@projetgrup.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~18\n"
|
||||
"Project-Id-Version: Odoo Server saas~11.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-09-20 09:53+0000\n"
|
||||
"PO-Revision-Date: 2017-09-20 09:53+0000\n"
|
||||
"Last-Translator: Matanat Ahmadova <ahmadova.matanat01@gmail.com>, 2017\n"
|
||||
"POT-Creation-Date: 2018-03-22 14:10+0000\n"
|
||||
"PO-Revision-Date: 2018-03-22 14:10+0000\n"
|
||||
"Last-Translator: Umur Akın <umura@projetgrup.com>, 2018\n"
|
||||
"Language-Team: Turkish (https://www.transifex.com/odoo/teams/41243/tr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -45,6 +45,8 @@ msgid ""
|
||||
"Cannot contact geolocation servers. Please make sure that your Internet "
|
||||
"connection is up and running (%s)."
|
||||
msgstr ""
|
||||
"Coğrafi konumlandıma sunucusuna bağlanılamıyor. Lütfen internet bağlantınızı"
|
||||
" açık ve çalışmakta olduğundan emin olun (%s)."
|
||||
|
||||
#. module: base_geolocalize
|
||||
#: model:ir.model,name:base_geolocalize.model_res_partner
|
||||
@@ -52,21 +54,21 @@ msgid "Contact"
|
||||
msgstr "Kontak"
|
||||
|
||||
#. module: base_geolocalize
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_partner_partner_latitude
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_users_partner_latitude
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_partner__partner_latitude
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_users__partner_latitude
|
||||
msgid "Geo Latitude"
|
||||
msgstr "Coğrafi Enlem"
|
||||
|
||||
#. module: base_geolocalize
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_partner_partner_longitude
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_users_partner_longitude
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_partner__partner_longitude
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_users__partner_longitude
|
||||
msgid "Geo Longitude"
|
||||
msgstr "Coğ Boylam"
|
||||
|
||||
#. module: base_geolocalize
|
||||
#: model:ir.ui.view,arch_db:base_geolocalize.view_crm_partner_geo_form
|
||||
msgid "Geolocate"
|
||||
msgstr ""
|
||||
msgstr "Yer Etiketi"
|
||||
|
||||
#. module: base_geolocalize
|
||||
#: model:ir.ui.view,arch_db:base_geolocalize.view_crm_partner_geo_form
|
||||
@@ -74,8 +76,8 @@ msgid "Geolocation"
|
||||
msgstr "Coğrafi Konum"
|
||||
|
||||
#. module: base_geolocalize
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_partner_date_localization
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_users_date_localization
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_partner__date_localization
|
||||
#: model:ir.model.fields,field_description:base_geolocalize.field_res_users__date_localization
|
||||
msgid "Geolocation Date"
|
||||
msgstr "Coğrafi Konum"
|
||||
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
# 苏州远鼎 <tiexinliu@126.com>, 2016
|
||||
# liAnGjiA <liangjia@qq.com>, 2016
|
||||
# 山西清水欧度(QQ:54773801) <54773801@qq.com>, 2018
|
||||
# John Lin <linyinhuan@139.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-03-22 14:10+0000\n"
|
||||
"PO-Revision-Date: 2018-03-22 14:10+0000\n"
|
||||
"Last-Translator: 山西清水欧度(QQ:54773801) <54773801@qq.com>, 2018\n"
|
||||
"Last-Translator: John Lin <linyinhuan@139.com>, 2018\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -143,7 +144,7 @@ msgstr "十进制分隔符:"
|
||||
#: code:addons/base_import/static/src/xml/base_import.xml:76
|
||||
#, python-format
|
||||
msgid "Defer parent/child computation"
|
||||
msgstr ""
|
||||
msgstr "推迟父/子计算"
|
||||
|
||||
#. module: base_import
|
||||
#: model:ir.model.fields,field_description:base_import.field_base_import_import__display_name
|
||||
@@ -317,7 +318,7 @@ msgid ""
|
||||
"If the model uses parent/child relations, computing the"
|
||||
" parent / child relation occurs on every line, and lead"
|
||||
" to a slower import. Defering it can speed up import."
|
||||
msgstr ""
|
||||
msgstr "如果该模型使用父/子关系,每行都会发生父/子关系计算,并使导入更慢。推迟她能提升导入速度。"
|
||||
|
||||
#. module: base_import
|
||||
#. openerp-web
|
||||
|
||||
@@ -6,8 +6,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-03-22 14:11+0000\n"
|
||||
"PO-Revision-Date: 2018-03-22 14:11+0000\n"
|
||||
"POT-Creation-Date: 2018-06-06 08:01+0000\n"
|
||||
"PO-Revision-Date: 2018-06-06 08:01+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -865,6 +865,13 @@ msgstr ""
|
||||
msgid "Meeting"
|
||||
msgstr ""
|
||||
|
||||
#. module: calendar
|
||||
#: code:addons/calendar/models/calendar.py:933
|
||||
#: code:addons/calendar/models/calendar.py:937
|
||||
#, python-format
|
||||
msgid "Meeting '%s' starts '%s' and ends '%s'"
|
||||
msgstr ""
|
||||
|
||||
#. module: calendar
|
||||
#: model:ir.ui.view,arch_db:calendar.view_calendar_event_form
|
||||
msgid "Meeting Details"
|
||||
|
||||
@@ -13,13 +13,14 @@
|
||||
# 老窦 北京 <2662059195@qq.com>, 2018
|
||||
# e2f <projects@e2f.com>, 2018
|
||||
# e2f_cn c5 <jarvisn@ecinnovations.com>, 2018
|
||||
# John Lin <linyinhuan@139.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-03-22 14:11+0000\n"
|
||||
"PO-Revision-Date: 2018-03-22 14:11+0000\n"
|
||||
"Last-Translator: e2f_cn c5 <jarvisn@ecinnovations.com>, 2018\n"
|
||||
"Last-Translator: John Lin <linyinhuan@139.com>, 2018\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -1062,7 +1063,7 @@ msgstr "邀请向导"
|
||||
#. module: calendar
|
||||
#: model:ir.model.fields,field_description:calendar.field_calendar_event__is_highlighted
|
||||
msgid "Is the Event Highlighted"
|
||||
msgstr ""
|
||||
msgstr "是事件高亮"
|
||||
|
||||
#. module: calendar
|
||||
#: selection:calendar.event,byday:0
|
||||
|
||||
@@ -930,9 +930,13 @@ class Meeting(models.Model):
|
||||
def _check_closing_date(self):
|
||||
for meeting in self:
|
||||
if meeting.start_datetime and meeting.stop_datetime and meeting.stop_datetime < meeting.start_datetime:
|
||||
raise ValidationError(_('Ending datetime cannot be set before starting datetime.'))
|
||||
raise ValidationError(_('Ending datetime cannot be set before starting datetime.') + "\n" +
|
||||
_("Meeting '%s' starts '%s' and ends '%s'") % (meeting.name, meeting.start_datetime, meeting.stop_datetime)
|
||||
)
|
||||
if meeting.start_date and meeting.stop_date and meeting.stop_date < meeting.start_date:
|
||||
raise ValidationError(_('Ending date cannot be set before starting date.'))
|
||||
raise ValidationError(_('Ending date cannot be set before starting date.') + "\n" +
|
||||
_("Meeting '%s' starts '%s' and ends '%s'") % (meeting.name, meeting.start_date, meeting.stop_date)
|
||||
)
|
||||
|
||||
@api.onchange('start_datetime', 'duration')
|
||||
def _onchange_duration(self):
|
||||
|
||||
@@ -1021,7 +1021,7 @@ msgstr "Atamaya Zorla"
|
||||
#. module: crm
|
||||
#: model:ir.ui.view,arch_db:crm.res_config_settings_view_form
|
||||
msgid "Format phone numbers based on national conventions"
|
||||
msgstr ""
|
||||
msgstr "Telefon numaralarını ulusal sözleşmelere göre biçimlendirme"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/models/crm_lead.py:588
|
||||
@@ -1869,7 +1869,7 @@ msgstr "Telefon"
|
||||
#. module: crm
|
||||
#: model:ir.model.fields,field_description:crm.field_res_config_settings__module_crm_phone_validation
|
||||
msgid "Phone Formatting"
|
||||
msgstr ""
|
||||
msgstr "Telefon Biçimlendirmesi"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/models/crm_team.py:165
|
||||
|
||||
@@ -91,4 +91,4 @@ msgstr "Proje"
|
||||
#. module: crm_project
|
||||
#: model:ir.model,name:crm_project.model_crm_lead_convert2task
|
||||
msgid "crm.lead.convert2task"
|
||||
msgstr ""
|
||||
msgstr "crm.lead.convert2task"
|
||||
|
||||
@@ -162,7 +162,8 @@ class StockPicking(models.Model):
|
||||
if self.carrier_id.free_over and self.sale_id and self.sale_id._compute_amount_total_without_delivery() >= self.carrier_id.amount:
|
||||
res['exact_price'] = 0.0
|
||||
self.carrier_price = res['exact_price']
|
||||
self.carrier_tracking_ref = res['tracking_number']
|
||||
if res['tracking_number']:
|
||||
self.carrier_tracking_ref = res['tracking_number']
|
||||
order_currency = self.sale_id.currency_id or self.company_id.currency_id
|
||||
msg = _("Shipment sent to carrier %s for shipping with tracking number %s<br/>Cost: %.2f %s") % (self.carrier_id.name, self.carrier_tracking_ref, self.carrier_price, order_currency.name)
|
||||
self.message_post(body=msg)
|
||||
|
||||
@@ -206,6 +206,168 @@ msgid ""
|
||||
"</div>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<div style=\"background:#F3F5F6;color:#515166;padding:25px 0px;font-family:Arial,Helvetica,sans-serif;font-size:14px;\">\n"
|
||||
"% set date_begin = format_tz(object.event_id.date_begin, tz='UTC', format='%Y%m%dT%H%M%SZ')\n"
|
||||
"% set date_end = format_tz(object.event_id.date_end, tz='UTC', format='%Y%m%dT%H%M%SZ')\n"
|
||||
" <table style=\"width:600px;margin:5px auto;\">\n"
|
||||
" <tbody>\n"
|
||||
" <tr>\n"
|
||||
" <td>\n"
|
||||
" <a href=\"/\">\n"
|
||||
" <img src=\"/logo\" alt=\"${object.company_id.name}\" style=\"vertical-align:baseline;max-width:100px;\" />\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" <td style=\"text-align:right;vertical-align:middle;\">\n"
|
||||
" % if 'website_url' in object.event_id and object.event_id.website_url:\n"
|
||||
" <a href=\"${object.event_id.website_url}\" style=\"background-color: #1abc9c; padding: 12px; font-weight: 12px; text-decoration: none; color: #fff; border-radius: 5px; font-size:16px;\">Ver evento</a>\n"
|
||||
" % endif\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody>\n"
|
||||
" </table>\n"
|
||||
" <table style=\"width:600px;margin:0px auto;background:white;border:1px solid #e1e1e1;\">\n"
|
||||
" <tbody>\n"
|
||||
" <tr>\n"
|
||||
" <td style=\"padding:15px 20px 0px 20px; font-size:16px; font-weight:300;\">\n"
|
||||
" <p style=\"font-size:16px;\">\n"
|
||||
" Hi,\n"
|
||||
" </p><p style=\"font-size:16px;\">\n"
|
||||
" Nos alegra confirmarle su registro en el evento:\n"
|
||||
" </p>\n"
|
||||
" <ul>\n"
|
||||
" <li>Evento: \n"
|
||||
" % if 'website_url' in object.event_id and object.event_id.website_url:\n"
|
||||
" <a href=\"${object.event_id.website_url}\" style=\"color:#875A7B;text-decoration:none;\">${object.event_id.name}</a>\n"
|
||||
" % else:\n"
|
||||
" <strong>${object.event_id.name}</strong>\n"
|
||||
" % endif\n"
|
||||
" </li>\n"
|
||||
" <li>Asistente: ${object.name}</li>\n"
|
||||
" </ul>\n"
|
||||
" <p style=\"font-size:16px;\">\n"
|
||||
" Nos vemos pronto,\n"
|
||||
" </p>\n"
|
||||
" <p style=\"font-size:16px; margin-bottom: 30px\">\n"
|
||||
" <i>\n"
|
||||
" -- <br/>\n"
|
||||
" % if object.event_id.organizer_id:\n"
|
||||
" ${object.event_id.organizer_id.name}\n"
|
||||
" % else:\n"
|
||||
" Los organizadores.\n"
|
||||
" % endif\n"
|
||||
" </i>\n"
|
||||
" </p>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr>\n"
|
||||
" <td style=\"padding:15px 20px 0px 20px;\">\n"
|
||||
" <table style=\"width:100%;border-top:1px solid #e1e1e1;\">\n"
|
||||
" <tr>\n"
|
||||
" <td style=\"padding:25px 0px;vertical-align:top;\">\n"
|
||||
" <img src=\"/web_editor/font_to_img/61555/rgb(81,81,102)/34\" style=\"padding:4px;max-width:inherit;\" height=\"34\">\n"
|
||||
" </td>\n"
|
||||
" <td style=\"padding:25px 10px 25px 10px;width:50%;line-height:20px;vertical-align:top;\">\n"
|
||||
" <div><strong>Desde</strong> ${object.event_id.date_begin_located}</div>\n"
|
||||
" <div><strong>Hasta</strong> ${object.event_id.date_end_located}</div>\n"
|
||||
" <div style=\"font-size:12px;color:#9e9e9e\"><i><strong>TZ</strong> ${object.event_id.date_tz}</i></div>\n"
|
||||
" </td>\n"
|
||||
" % if object.event_id.address_id.country_id.name:\n"
|
||||
" <td style=\"padding:25px 0px;vertical-align:top;\">\n"
|
||||
" <img src=\"/web_editor/font_to_img/61505/rgb(81,81,102)/34\" style=\"padding:4px;max-width:inherit;\" height=\"34\">\n"
|
||||
" </td>\n"
|
||||
" <td style=\"padding:30px 10px 25px 10px;width:50%;vertical-align:top;\">\n"
|
||||
" % set location = ''\n"
|
||||
" % if object.event_id.address_id.name:\n"
|
||||
" <p style=\"margin:0px 0px 0px 0px;\">${object.event_id.address_id.name}</p>\n"
|
||||
" % endif\n"
|
||||
" % if object.event_id.address_id.street:\n"
|
||||
" <p style=\"margin:0px 0px 0px 0px;\">${object.event_id.address_id.street}</p>\n"
|
||||
" % set location = object.event_id.address_id.street\n"
|
||||
" % endif\n"
|
||||
" % if object.event_id.address_id.street2:\n"
|
||||
" <p style=\"margin:0px 0px 0px 0px;\">${object.event_id.address_id.street2}</p>\n"
|
||||
" % set location = '%s, %s' % (location, object.event_id.address_id.street2)\n"
|
||||
" % endif\n"
|
||||
" <p style=\"margin:0px 0px 0px 0px;\">\n"
|
||||
" % if object.event_id.address_id.city:\n"
|
||||
" ${object.event_id.address_id.city},\n"
|
||||
" % set location = '%s, %s' % (location, object.event_id.address_id.city)\n"
|
||||
" % endif\n"
|
||||
" % if object.event_id.address_id.state_id.name:\n"
|
||||
" ${object.event_id.address_id.state_id.name},\n"
|
||||
" % set location = '%s, %s' % (location, object.event_id.address_id.state_id.name)\n"
|
||||
" % endif\n"
|
||||
" % if object.event_id.address_id.zip:\n"
|
||||
" ${object.event_id.address_id.zip}\n"
|
||||
" % set location = '%s, %s' % (location, object.event_id.address_id.zip)\n"
|
||||
" % endif\n"
|
||||
" </p>\n"
|
||||
" % if object.event_id.address_id.country_id.name:\n"
|
||||
" <p style=\"margin:0px 0px 0px 0px;\">${object.event_id.address_id.country_id.name}</p>\n"
|
||||
" % set location = '%s, %s' % (location, object.event_id.address_id.country_id.name)\n"
|
||||
" % endif\n"
|
||||
" </td>\n"
|
||||
" % endif\n"
|
||||
" </tr>\n"
|
||||
" </table>\n"
|
||||
" % if object.event_id.organizer_id:\n"
|
||||
" <table style=\"width:100%;border-top:1px solid #e1e1e1;\">\n"
|
||||
" <tr>\n"
|
||||
" <td style=\"padding:10px 0px 25px 0px;\">\n"
|
||||
" <h2 style=\"font-weight:300;margin:10px 0px\">¿Preguntas sobre este evento?</h2>\n"
|
||||
" <p>Por favor contacte con el organizador:</p>\n"
|
||||
" <ul>\n"
|
||||
" <li>${object.event_id.organizer_id.name}</li>\n"
|
||||
" % if object.event_id.organizer_id.email\n"
|
||||
" <li>Correo: <a href=\"mailto:${object.event_id.organizer_id.email}\" style=\"text-decoration:none;color:#875A7B;\">${object.event_id.organizer_id.email}</a></li>\n"
|
||||
" % endif\n"
|
||||
" % if object.event_id.organizer_id.phone\n"
|
||||
" <li>Teléfono: ${object.event_id.organizer_id.phone}</li>\n"
|
||||
" % endif\n"
|
||||
" </ul>\n"
|
||||
"\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </table>\n"
|
||||
" % endif\n"
|
||||
" <table style=\"width:100%;border-top:1px solid #e1e1e1;\">\n"
|
||||
" <tr>\n"
|
||||
" <td style=\"padding:25px 0px;\">\n"
|
||||
" <strong>Añada este evento a su calendario</strong>\n"
|
||||
" <a href=\"https://www.google.com/calendar/render?action=TEMPLATE&text=${object.event_id.name}&dates=${date_begin}/${date_end}&location=${location}\" style=\"padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;\" target=\"new\"><img src=\"/web_editor/font_to_img/61525/rgb(135,90,123)/16\" style=\"vertical-align:middle;\" height=\"16\"> Google</a>\n"
|
||||
" <a href=\"https://bay02.calendar.live.com/calendar/calendar.aspx?rru=addevent&summary=${object.event_id.name}&dtstart=${date_begin}&dtend=${date_end}&location=${location}\" style=\"padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;\" target=\"new\"><img src=\"/web_editor/font_to_img/61525/rgb(135,90,123)/16\" style=\"vertical-align:middle;\" height=\"16\"> Outlook</a>\n"
|
||||
" <a href=\"https://calendar.yahoo.com/?v=60&view=d&type=20&title=${object.event_id.name}&in_loc=${location}&st=${format_tz(object.event_id.date_begin, tz='UTC', format='%Y%m%dT%H%M%S')}&et=${format_tz(object.event_id.date_end, tz='UTC', format='%Y%m%dT%H%M%S')}\" style=\"padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;\" target=\"new\"><img src=\"/web_editor/font_to_img/61525/rgb(135,90,123)/16\" style=\"vertical-align:middle;\" height=\"16\"> Yahoo</a>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </table>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody>\n"
|
||||
" </table>\n"
|
||||
" % if object.event_id.address_id:\n"
|
||||
" <div style=\"width:598px;margin:0px auto;border-left:1px solid #dddddd;border-right:1px solid #dddddd;border-bottom:1px solid #dddddd;\">\n"
|
||||
" <a href=\"https://maps.google.com/maps?q=${location}\" target=\"new\">\n"
|
||||
" <img src=\"http://maps.googleapis.com/maps/api/staticmap?autoscale=1&size=598x200&maptype=roadmap&format=png&visual_refresh=true&markers=size:mid%7Ccolor:0xa5117d%7Clabel:%7C${location}\" style=\"vertical-align:bottom;\" />\n"
|
||||
" </a>\n"
|
||||
" </div>\n"
|
||||
" % endif\n"
|
||||
" <table style=\"width:600px;margin:0px auto;text-align:center;\">\n"
|
||||
" <tbody>\n"
|
||||
" <tr>\n"
|
||||
" <td style=\"padding-top:10px;font-size: 12px;\">\n"
|
||||
" <div>Enviado por ${object.company_id.name}</div>\n"
|
||||
" % if 'website_url' in object.event_id and object.event_id.website_url:\n"
|
||||
" <div>\n"
|
||||
" Descubra <a href=\"/event\" style=\"text-decoration:none;color:#717188;\">todos nuestros eventos</a>.\n"
|
||||
" </div>\n"
|
||||
" % endif\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody>\n"
|
||||
" </table>\n"
|
||||
"</div>\n"
|
||||
" "
|
||||
|
||||
#. module: event
|
||||
#: model:mail.template,body_html:event.event_reminder
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<field name="name">view.res.partner.form.event.inherited</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="groups_id" eval="[(4, ref('event.group_event_user'))]"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button class="oe_stat_button"
|
||||
|
||||
@@ -677,7 +677,7 @@ class GoogleCalendar(models.AbstractModel):
|
||||
try:
|
||||
all_event_from_google = self.get_event_synchro_dict(lastSync=lastSync)
|
||||
except requests.HTTPError as e:
|
||||
if e.response.code == 410: # GONE, Google is lost.
|
||||
if e.response.status_code == 410: # GONE, Google is lost.
|
||||
# we need to force the rollback from this cursor, because it locks my res_users but I need to write in this tuple before to raise.
|
||||
self.env.cr.rollback()
|
||||
self.env.user.write({'google_calendar_last_sync_date': False})
|
||||
@@ -842,7 +842,7 @@ class GoogleCalendar(models.AbstractModel):
|
||||
try:
|
||||
# if already deleted from gmail or never created
|
||||
recs.delete_an_event(current_event[0])
|
||||
except Exception as e:
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if e.response.status_code in (401, 410,):
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -5,9 +5,10 @@ from odoo import fields, models, tools
|
||||
|
||||
|
||||
class LeaveReport(models.Model):
|
||||
|
||||
_name = "hr.leave.report"
|
||||
_description = 'Leave Summary / Report'
|
||||
_auto = False
|
||||
_order = "date_from DESC, employee_id"
|
||||
|
||||
employee_id = fields.Many2one('hr.employee', string="Employee", readonly=True)
|
||||
name = fields.Char('Description', readonly=True)
|
||||
|
||||
@@ -46,12 +46,13 @@
|
||||
<field name="model">hr.leave.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree create="0" edit="0" delete="0">
|
||||
<field name="type"/>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="number_of_days" string="Number of Days" sum="Remaining Days"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
<field name="state"/>
|
||||
<field name="type"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
<field name="model">hr.leave</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Leave">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="holiday_status_id"/>
|
||||
<field name="name"/>
|
||||
<filter domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/>
|
||||
<filter string="Approved Leaves" domain="[('state', '=', 'validate')]" name="validated"/>
|
||||
@@ -40,10 +43,6 @@
|
||||
<separator/>
|
||||
<filter string="My Leaves" name="my_leaves" domain="[('employee_id.user_id', '=', uid)]"/>
|
||||
<separator/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="holiday_status_id"/>
|
||||
<separator/>
|
||||
<filter string="Late Activities" name="activities_overdue"
|
||||
domain="[('activity_ids.date_deadline', '<', context_today().strftime('%Y-%m-%d'))]"
|
||||
help="Show all records which has next action date is before today"/>
|
||||
|
||||
@@ -111,7 +111,7 @@ class Task(models.Model):
|
||||
@api.depends('timesheet_ids.unit_amount')
|
||||
def _compute_effective_hours(self):
|
||||
for task in self:
|
||||
task.effective_hours = sum(task.timesheet_ids.mapped('unit_amount'))
|
||||
task.effective_hours = round(sum(task.timesheet_ids.mapped('unit_amount')), 2)
|
||||
|
||||
@api.depends('effective_hours', 'subtask_effective_hours', 'planned_hours')
|
||||
def _compute_progress_hours(self):
|
||||
|
||||
@@ -522,6 +522,10 @@ class Escpos:
|
||||
# Print Code
|
||||
if code:
|
||||
self._raw(code)
|
||||
# We are using type A commands
|
||||
# So we need to add the 'NULL' character
|
||||
# https://github.com/python-escpos/python-escpos/pull/98/files#diff-a0b1df12c7c67e38915adbe469051e2dR444
|
||||
self._raw('\x00')
|
||||
else:
|
||||
raise exception.BarcodeCodeError()
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ class ResCompany(models.Model):
|
||||
if company._is_accounting_unalterable():
|
||||
sequence_fields = ['l10n_fr_secure_sequence_id']
|
||||
company._create_secure_sequence(sequence_fields)
|
||||
# fiscalyear_lock_date can't be set to a prior date
|
||||
if 'fiscalyear_lock_date' in vals or 'period_lock_date' in vals:
|
||||
self._check_lock_dates(vals)
|
||||
return res
|
||||
|
||||
def _create_secure_sequence(self, sequence_fields):
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
def uninstall_hook(cr, registry):
|
||||
cr.execute(
|
||||
"DELETE FROM ir_model_data WHERE module = 'l10n_generic_coa'"
|
||||
)
|
||||
|
||||
@@ -24,4 +24,5 @@ Install some generic chart of accounts.
|
||||
'data/account_invoice_demo.xml',
|
||||
],
|
||||
'website': 'https://www.odoo.com/page/accounting',
|
||||
'uninstall_hook': 'uninstall_hook',
|
||||
}
|
||||
|
||||
@@ -3048,7 +3048,7 @@ msgstr "Modeller"
|
||||
#. module: mail
|
||||
#: model:ir.model,name:mail.model_base_module_uninstall
|
||||
msgid "Module Uninstallation"
|
||||
msgstr ""
|
||||
msgstr "Yüklemeyi Kaldırma Modülü"
|
||||
|
||||
#. module: mail
|
||||
#: model:ir.ui.view,arch_db:mail.view_mail_search
|
||||
|
||||
@@ -667,7 +667,7 @@ msgstr "E-Posta"
|
||||
#: model:ir.ui.menu,name:mass_mailing.mass_mailing_menu_root
|
||||
#: model:ir.ui.view,arch_db:mass_mailing.res_config_settings_view_form
|
||||
msgid "Email Marketing"
|
||||
msgstr ""
|
||||
msgstr "E-posta Pazarlama"
|
||||
|
||||
#. module: mass_mailing
|
||||
#: model:ir.model,name:mass_mailing.model_mail_mail_statistics
|
||||
|
||||
@@ -84,7 +84,7 @@ class MailMail(models.Model):
|
||||
def _send_prepare_values(self, partner=None):
|
||||
# TDE: temporary addition (mail was parameter) due to semi-new-API
|
||||
res = super(MailMail, self)._send_prepare_values(partner)
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url').rstrip('/')
|
||||
if self.mailing_id and res.get('body') and res.get('email_to'):
|
||||
emails = tools.email_split(res.get('email_to')[0])
|
||||
email_to = emails and emails[0] or False
|
||||
|
||||
@@ -3604,7 +3604,7 @@ msgid ""
|
||||
"link to your file."
|
||||
msgstr ""
|
||||
"U kan een bestand van uw computer uploaden of een internet link "
|
||||
"kopiëren/plakken die linkt naar uw bestand"
|
||||
"kopiëren/plakken die linkt naar uw bestand."
|
||||
|
||||
#. module: mrp
|
||||
#: code:addons/mrp/models/mrp_production.py:523
|
||||
|
||||
@@ -3575,7 +3575,7 @@ msgid ""
|
||||
"category is specified, all available products will be shown."
|
||||
msgstr ""
|
||||
"De kassa toont de productcategorieën standaard. Als er geen categorie is "
|
||||
"gespecificeerd worden alle producten getoond"
|
||||
"gespecificeerd worden alle producten getoond."
|
||||
|
||||
#. module: point_of_sale
|
||||
#: model:ir.model.fields,help:point_of_sale.field_pos_config__pricelist_id
|
||||
|
||||
@@ -364,11 +364,12 @@ class PosConfig(models.Model):
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if (self.is_posbox or vals.get('is_posbox')) and (self.iface_customer_facing_display or vals.get('iface_customer_facing_display')):
|
||||
facing_display = (self.customer_facing_display_html or vals.get('customer_facing_display_html') or '').strip()
|
||||
if not facing_display:
|
||||
vals['customer_facing_display_html'] = self._compute_default_customer_html()
|
||||
result = super(PosConfig, self).write(vals)
|
||||
|
||||
config_display = self.filtered(lambda c: c.is_posbox and c.iface_customer_facing_display and not (c.customer_facing_display_html or '').strip())
|
||||
if config_display:
|
||||
super(PosConfig, config_display).write({'customer_facing_display_html': self._compute_default_customer_html()})
|
||||
|
||||
self.sudo()._set_fiscal_position()
|
||||
self.sudo()._check_modules_to_install()
|
||||
self.sudo()._check_groups_implied()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<!--Email template -->
|
||||
<record id="email_template_edi_purchase" model="mail.template">
|
||||
<field name="name">RFQ - Send by Email</field>
|
||||
<field name="email_from">${(object.create_uid.email and '%s <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe}</field>
|
||||
<field name="email_from">${(object.create_uid.email and '"%s" <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe}</field>
|
||||
<field name="subject">${object.company_id.name} Order (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
@@ -46,7 +46,7 @@ from ${object.company_id.name}.
|
||||
<!--Email template -->
|
||||
<record id="email_template_edi_purchase_done" model="mail.template">
|
||||
<field name="name">Purchase Order - Send by Email</field>
|
||||
<field name="email_from">${(object.create_uid.email and '%s <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe}</field>
|
||||
<field name="email_from">${(object.create_uid.email and '"%s" <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe}</field>
|
||||
<field name="subject">${object.company_id.name} Order (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
|
||||
@@ -943,12 +943,12 @@ class ProcurementRule(models.Model):
|
||||
if domain in cache:
|
||||
po = cache[domain]
|
||||
else:
|
||||
po = self.env['purchase.order'].search([dom for dom in domain])
|
||||
po = self.env['purchase.order'].sudo().search([dom for dom in domain])
|
||||
po = po[0] if po else False
|
||||
cache[domain] = po
|
||||
if not po:
|
||||
vals = self._prepare_purchase_order(product_id, product_qty, product_uom, origin, values, partner)
|
||||
po = self.env['purchase.order'].create(vals)
|
||||
po = self.env['purchase.order'].sudo().create(vals)
|
||||
cache[domain] = po
|
||||
elif not po.origin or origin not in po.origin.split(', '):
|
||||
if po.origin:
|
||||
@@ -969,7 +969,7 @@ class ProcurementRule(models.Model):
|
||||
break
|
||||
if not po_line:
|
||||
vals = self._prepare_purchase_order_line(product_id, product_qty, product_uom, values, po, partner)
|
||||
self.env['purchase.order.line'].create(vals)
|
||||
self.env['purchase.order.line'].sudo().create(vals)
|
||||
|
||||
def _get_purchase_schedule_date(self, values):
|
||||
"""Return the datetime value to use as Schedule Date (``date_planned``) for the
|
||||
|
||||
@@ -184,7 +184,7 @@ class TestStockValuation(TransactionCase):
|
||||
'company_id': po1.company_id.id,
|
||||
})
|
||||
eur_currency._compute_current_rate()
|
||||
price_unit_usd_new_rate = po1.currency_id.compute(po1.order_line.price_unit, po1.company_id.currency_id, round=True)
|
||||
price_unit_usd_new_rate = po1.currency_id.compute(po1.order_line.price_unit, po1.company_id.currency_id, round=False)
|
||||
|
||||
# the new price_unit is lower than th initial because of the rate's change
|
||||
self.assertLess(price_unit_usd_new_rate, price_unit_usd)
|
||||
@@ -198,7 +198,7 @@ class TestStockValuation(TransactionCase):
|
||||
wizard.process()
|
||||
|
||||
# the unit price of the stock move has been updated to the latest value
|
||||
self.assertAlmostEqual(move1.price_unit, price_unit_usd_new_rate, places=2)
|
||||
self.assertAlmostEqual(move1.price_unit, price_unit_usd_new_rate)
|
||||
|
||||
self.assertAlmostEqual(self.product1.stock_value, price_unit_usd_new_rate * 10, delta=0.1)
|
||||
|
||||
@@ -412,4 +412,3 @@ class TestStockValuationWithCOA(AccountingTestCase):
|
||||
# check the anglo saxon entries
|
||||
price_diff_entry = self.env['account.move.line'].search([('account_id', '=', price_diff_account.id)])
|
||||
self.assertEqual(price_diff_entry.credit, 100)
|
||||
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
# Fernando San Martín Woerner <fsnmartin@gmail.com>, 2018
|
||||
# José Matias Zuazo <jose.zuazo@tpsistemas.com.ar>, 2018
|
||||
# Nicolás Broggi <rnbroggi@gmail.com>, 2018
|
||||
# Carlos Vásquez <carlos.vasquez@clearcorp.co.cr>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-03-22 14:11+0000\n"
|
||||
"PO-Revision-Date: 2018-03-22 14:11+0000\n"
|
||||
"Last-Translator: Nicolás Broggi <rnbroggi@gmail.com>, 2018\n"
|
||||
"Last-Translator: Carlos Vásquez <carlos.vasquez@clearcorp.co.cr>, 2018\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -97,6 +98,20 @@ msgid ""
|
||||
" <p>Thank you,</p>\n"
|
||||
" </data>"
|
||||
msgstr ""
|
||||
"<?xml version=\"1.0\"?>\n"
|
||||
"<data>Estimado(a) ${object.partner_id.name}</p>\n"
|
||||
" <p>\n"
|
||||
" Ésta es su orden de reparación ${doc_name} <strong>${object.name}</strong>\n"
|
||||
" % if object.origin:\n"
|
||||
" (con referencia: ${object.origin} )\n"
|
||||
" % endif\n"
|
||||
" % if object.invoice_method != 'none':\n"
|
||||
" por un total de <strong>${format_amount(object.amount_total, object.pricelist_id.currency_id)}.</strong>\n"
|
||||
" % endif\n"
|
||||
" </p>\n"
|
||||
" <p>Puede responder a este correo electrónico si tiene alguna duda.</p>\n"
|
||||
" <p>Gracias,</p>\n"
|
||||
" </data>"
|
||||
|
||||
#. module: repair
|
||||
#: model:ir.ui.view,arch_db:repair.report_repairorder
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<!--Email template -->
|
||||
<record id="email_template_edi_sale" model="mail.template">
|
||||
<field name="name">Sales Order - Send by Email</field>
|
||||
<field name="email_from">${(object.user_id.email and '%s <%s>' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
|
||||
<field name="email_from">${(object.user_id.email and '"%s" <%s>' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
|
||||
<field name="subject">${object.company_id.name} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
|
||||
@@ -24,7 +24,7 @@ class ProductTemplate(models.Model):
|
||||
@api.depends('product_variant_ids.sales_count')
|
||||
def _sales_count(self):
|
||||
for product in self:
|
||||
product.sales_count = sum([p.sales_count for p in product.product_variant_ids])
|
||||
product.sales_count = sum([p.sales_count for p in product.with_context(active_test=False).product_variant_ids])
|
||||
|
||||
@api.multi
|
||||
def action_view_sales(self):
|
||||
|
||||
@@ -4454,7 +4454,8 @@ msgstr "Aantallen"
|
||||
#, python-format
|
||||
msgid "Quants cannot be created for consumables or services."
|
||||
msgstr ""
|
||||
"Quants kunnen niet worden aangemaakt voor verbruiksartikelen of diensten."
|
||||
"Hoeveelheden kunnen niet worden aangemaakt voor verbruiksartikelen of "
|
||||
"diensten."
|
||||
|
||||
#. module: stock
|
||||
#: model:ir.model.fields,field_description:stock.field_stock_picking_type__rate_picking_backorders
|
||||
@@ -5429,8 +5430,8 @@ msgid ""
|
||||
"Technical field used to compute whether the mark as todo button should be "
|
||||
"shown."
|
||||
msgstr ""
|
||||
"Technisch veld waarmee berekend wordt of de markeer als ToDo zichtbaar mag "
|
||||
"zijn."
|
||||
"Technisch veld waarmee berekend wordt of de markeer als \"Te doen\" "
|
||||
"zichtbaar mag zijn."
|
||||
|
||||
#. module: stock
|
||||
#: model:ir.model.fields,help:stock.field_stock_picking__show_validate
|
||||
|
||||
@@ -930,11 +930,15 @@ class StockMove(models.Model):
|
||||
if not move.move_orig_ids:
|
||||
if move.procure_method == 'make_to_order':
|
||||
continue
|
||||
# If we don't need any quantity, consider the move assigned.
|
||||
need = move.product_qty - move.reserved_availability
|
||||
if float_is_zero(need, precision_rounding=move.product_id.uom_id.rounding):
|
||||
assigned_moves |= move
|
||||
continue
|
||||
# Reserve new quants and create move lines accordingly.
|
||||
available_quantity = self.env['stock.quant']._get_available_quantity(move.product_id, move.location_id)
|
||||
if available_quantity <= 0:
|
||||
continue
|
||||
need = move.product_qty - move.reserved_availability
|
||||
taken_quantity = move._update_reserved_quantity(need, available_quantity, move.location_id, strict=False)
|
||||
if float_is_zero(taken_quantity, precision_rounding=move.product_id.uom_id.rounding):
|
||||
continue
|
||||
|
||||
@@ -66,7 +66,7 @@ class ReportStockForecat(models.Model):
|
||||
LEFT JOIN
|
||||
stock_location source_location ON sm.location_id = source_location.id
|
||||
WHERE
|
||||
sm.state IN ('confirmed','assigned','waiting') and
|
||||
sm.state IN ('confirmed','partially_available','assigned','waiting') and
|
||||
source_location.usage != 'internal' and dest_location.usage = 'internal'
|
||||
GROUP BY sm.date_expected,sm.product_id, sm.company_id
|
||||
UNION ALL
|
||||
@@ -88,7 +88,7 @@ class ReportStockForecat(models.Model):
|
||||
LEFT JOIN
|
||||
stock_location dest_location ON sm.location_dest_id = dest_location.id
|
||||
WHERE
|
||||
sm.state IN ('confirmed','assigned','waiting') and
|
||||
sm.state IN ('confirmed','partially_available','assigned','waiting') and
|
||||
source_location.usage = 'internal' and dest_location.usage != 'internal'
|
||||
GROUP BY sm.date_expected,sm.product_id, sm.company_id)
|
||||
as MAIN
|
||||
|
||||
@@ -1074,6 +1074,31 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.customer_location), 12.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.customer_location)), 12)
|
||||
|
||||
def test_availability_8(self):
|
||||
""" Test the assignment mechanism when the product quantity is decreased on a partially
|
||||
reserved stock move.
|
||||
"""
|
||||
# make some stock
|
||||
self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 3.0)
|
||||
self.assertAlmostEqual(self.product1.qty_available, 3.0)
|
||||
|
||||
move_partial = self.env['stock.move'].create({
|
||||
'name': 'test_partial',
|
||||
'location_id': self.stock_location.id,
|
||||
'location_dest_id': self.customer_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 5.0,
|
||||
})
|
||||
|
||||
move_partial._action_confirm()
|
||||
move_partial._action_assign()
|
||||
self.assertAlmostEqual(self.product1.virtual_available, -2.0)
|
||||
self.assertEqual(move_partial.state, 'partially_available')
|
||||
move_partial.product_uom_qty = 3.0
|
||||
move_partial._action_assign()
|
||||
self.assertEqual(move_partial.state, 'assigned')
|
||||
|
||||
def test_unreserve_1(self):
|
||||
""" Check that unreserving a stock move sets the products reserved as available and
|
||||
set the state back to confirmed.
|
||||
@@ -3917,4 +3942,3 @@ class StockMove(TransactionCase):
|
||||
picking.button_validate()
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 0)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.customer_location), 2)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<field name="model">stock.return.picking</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='product_return_moves']/tree" position="inside">
|
||||
<field name="to_refund" widget="boolean_toggle"/>
|
||||
<field name="to_refund"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -87,8 +87,6 @@ class SurveyMailComposeMessage(models.TransientModel):
|
||||
#set url
|
||||
url = wizard.survey_id.public_url
|
||||
|
||||
url = urls.url_parse(url).path[1:] # dirty hack to avoid incorrect urls
|
||||
|
||||
if token:
|
||||
url = url + '/' + token
|
||||
|
||||
|
||||
@@ -1990,9 +1990,7 @@ var BasicModel = AbstractModel.extend({
|
||||
var records = [];
|
||||
var ids = [];
|
||||
list = this._applyX2ManyOperations(list);
|
||||
if (_.isEmpty(list.data)) {
|
||||
return $.when();
|
||||
}
|
||||
|
||||
_.each(list.data, function (localId) {
|
||||
var record = self.localData[localId];
|
||||
var data = record._changes || record.data;
|
||||
@@ -2003,6 +2001,9 @@ var BasicModel = AbstractModel.extend({
|
||||
ids.push(many2oneRecord.res_id);
|
||||
model = many2oneRecord.model;
|
||||
});
|
||||
if (!ids.length) {
|
||||
return $.when();
|
||||
}
|
||||
return this._rpc({
|
||||
model: model,
|
||||
method: 'name_get',
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
padding: 0px;
|
||||
background-style: none;
|
||||
border-style: none;
|
||||
height: 0px;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
|
||||
@@ -2551,6 +2551,58 @@ QUnit.module('relational_fields', {
|
||||
|
||||
QUnit.module('FieldOne2Many');
|
||||
|
||||
QUnit.test('New record with a o2m also with 2 new records, ordered, and resequenced', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Needed to have two new records in a single stroke
|
||||
this.data.partner.onchanges = {
|
||||
foo: function(obj) {
|
||||
obj.p = [
|
||||
[5],
|
||||
[0, 0, {trululu: false}],
|
||||
[0, 0, {trululu: false}],
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch:'<form string="Partners">' +
|
||||
'<field name="foo" />' +
|
||||
'<field name="p">' +
|
||||
'<tree editable="bottom" default_order="int_field">' +
|
||||
'<field name="int_field" widget="handle"/>' +
|
||||
'<field name="trululu"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'</form>',
|
||||
viewOptions: {
|
||||
mode: 'create',
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(args.method + ' ' + args.model)
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
|
||||
// change the int_field through drag and drop
|
||||
// that way, we'll trigger the sorting and the name_get
|
||||
// of the lines of "p"
|
||||
testUtils.dragAndDrop(
|
||||
form.$('.ui-sortable-handle').eq(1),
|
||||
form.$('tbody tr').first(),
|
||||
{position: 'top'}
|
||||
);
|
||||
|
||||
// Only those two should have been called
|
||||
// name_get on trululu would trigger an traceback
|
||||
assert.verifySteps(['default_get partner', 'onchange partner']);
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('O2M List with pager, decoration and default_order: add and cancel adding', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
|
||||
@@ -2255,7 +2255,7 @@ $.summernote.pluginEvents.backColor = function (event, editor, layoutInfo, backC
|
||||
};
|
||||
|
||||
options.onCreateLink = function (sLinkUrl) {
|
||||
if (sLinkUrl.indexOf('mailto:') === 0) {
|
||||
if (sLinkUrl.indexOf('mailto:') === 0 || sLinkUrl.indexOf('tel:') === 0) {
|
||||
// pass
|
||||
} else if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {
|
||||
sLinkUrl = 'mailto:' + sLinkUrl;
|
||||
|
||||
@@ -18,8 +18,9 @@ from odoo import http, models, fields, _
|
||||
from odoo.http import request
|
||||
from odoo.tools import pycompat, OrderedSet
|
||||
from odoo.addons.http_routing.models.ir_http import slug, _guess_mimetype
|
||||
from odoo.addons.web.controllers.main import WebClient, Binary, Home
|
||||
from odoo.addons.web.controllers.main import WebClient, Binary
|
||||
from odoo.addons.portal.controllers.portal import pager as portal_pager
|
||||
from odoo.addons.portal.controllers.web import Home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -34,11 +34,11 @@ class ResPartnerActivation(models.Model):
|
||||
class ResPartner(models.Model):
|
||||
_inherit = "res.partner"
|
||||
|
||||
partner_weight = fields.Integer('Level Weight', default=lambda *args: 0,
|
||||
partner_weight = fields.Integer('Level Weight', default=0, track_visibility='onchange',
|
||||
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)")
|
||||
grade_id = fields.Many2one('res.partner.grade', 'Level')
|
||||
grade_id = fields.Many2one('res.partner.grade', 'Level', track_visibility='onchange')
|
||||
grade_sequence = fields.Integer(related='grade_id.sequence', readonly=True, store=True)
|
||||
activation = fields.Many2one('res.partner.activation', 'Activation', index=True)
|
||||
activation = fields.Many2one('res.partner.activation', 'Activation', index=True, track_visibility='onchange')
|
||||
date_partnership = fields.Date('Partnership Date')
|
||||
date_review = fields.Date('Latest Partner Review')
|
||||
date_review_next = fields.Date('Next Partner Review')
|
||||
|
||||
@@ -20,8 +20,11 @@ return instance.appendTo($form).then(function () {
|
||||
odoo.define('website_event.website_event', function (require) {
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
// Catch registration form event, because of JS for attendee details
|
||||
var EventRegistrationForm = Widget.extend({
|
||||
start: function () {
|
||||
@@ -31,7 +34,6 @@ var EventRegistrationForm = Widget.extend({
|
||||
.off('click')
|
||||
.removeClass('a-submit')
|
||||
.click(function (ev) {
|
||||
$(this).attr('disabled', true);
|
||||
self.on_click(ev);
|
||||
});
|
||||
});
|
||||
@@ -43,15 +45,18 @@ var EventRegistrationForm = Widget.extend({
|
||||
var $form = $(ev.currentTarget).closest('form');
|
||||
var $button = $(ev.currentTarget).closest('[type="submit"]');
|
||||
var post = {};
|
||||
$('#registration_form table').siblings('.alert').remove();
|
||||
$('#registration_form select').each(function () {
|
||||
post[$(this).attr('name')] = $(this).val();
|
||||
});
|
||||
var tickets_ordered = _.some(_.map(post, function (value, key) { return parseInt(value); }));
|
||||
if (!tickets_ordered) {
|
||||
return $('#registration_form table').after(
|
||||
'<div class="alert alert-info">Please select at least one ticket.</div>'
|
||||
);
|
||||
$('<div class="alert alert-info"/>')
|
||||
.text(_t('Please select at least one ticket.'))
|
||||
.insertAfter('#registration_form table');
|
||||
return $.Deferred();
|
||||
} else {
|
||||
$button.attr('disabled', true);
|
||||
return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) {
|
||||
var $modal = $(modal);
|
||||
$modal.find('.modal-body > div').removeClass('container'); // retrocompatibility - REMOVE ME in master / saas-19
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
<div id="o-carousel-product" class="carousel slide" data-ride="carousel" data-interval="0">
|
||||
<div class="carousel-outer">
|
||||
<div class="carousel-inner">
|
||||
<div t-if="variant_img" class="item active" itemprop="image" t-field="product.product_variant_id.image" t-options="{'widget': 'image', 'class': 'product_detail_img js_variant_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update'] + (product.product_variant_id['__last_update'] or '')}"/>
|
||||
<div t-if="variant_img" class="item active" itemprop="image" t-field="product[:1].product_variant_id.image" t-options="{'widget': 'image', 'class': 'product_detail_img js_variant_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update'] + (product.product_variant_id['__last_update'] or '')}"/>
|
||||
<div t-attf-class="item#{'' if variant_img else ' active'}" itemprop="image" t-field="product.image" t-options="{'widget': 'image', 'class': 'product_detail_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update']}"/>
|
||||
<t t-if="len(image_ids)" t-foreach="image_ids" t-as="pimg">
|
||||
<div class="item" t-field="pimg.image" t-options='{"widget": "image", "class": "product_detail_img", "alt-field": "name", "zoom": "image" }'/>
|
||||
|
||||
@@ -534,10 +534,14 @@ Supported Browsers
|
||||
Odoo is supported by multiple browsers for each of its versions. No
|
||||
distinction is made according to the browser version in order to be
|
||||
up-to-date. Odoo is supported on the current browser version. The list
|
||||
of the supported browsers by Odoo version is the following:
|
||||
of the supported browsers is the following:
|
||||
|
||||
- IE11,
|
||||
- Mozilla Firefox,
|
||||
- Google Chrome,
|
||||
- Safari,
|
||||
- Microsoft Edge
|
||||
|
||||
- **Odoo 9:** IE11, Mozilla Firefox, Google Chrome, Safari, Microsoft Edge
|
||||
- **Odoo 10+:** Mozilla Firefox, Google Chrome, Safari, Microsoft Edge
|
||||
|
||||
.. [#different-machines]
|
||||
to have multiple Odoo installations use the same PostgreSQL database,
|
||||
|
||||
+325
-202
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<header>
|
||||
<button string="Save" type="object" name="execute" class="oe_highlight" />
|
||||
<button string="Discard" type="object" name="cancel" />
|
||||
<button string="Discard" type="object" name="cancel" special="cancel" />
|
||||
</header>
|
||||
</div>
|
||||
<div class="o_setting_container">
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
<field name="country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'
|
||||
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"/>
|
||||
</div>
|
||||
<field name="vat" placeholder="e.g. BE0477472701"/>
|
||||
<field name="vat" placeholder="e.g. BE0477472701" attrs="{'readonly': [('parent_id','!=',False)]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="function" placeholder="e.g. Sales Director"
|
||||
@@ -244,7 +244,7 @@
|
||||
<field name="country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'
|
||||
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"/>
|
||||
</div>
|
||||
<field name="vat" placeholder="e.g. BE0477472701"/>
|
||||
<field name="vat" placeholder="e.g. BE0477472701" attrs="{'readonly': [('parent_id','!=',False)]}"/>
|
||||
<field name="category_id" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}" placeholder="Tags..."/>
|
||||
</group>
|
||||
<group>
|
||||
|
||||
+45
-7
@@ -25,7 +25,8 @@ _logger = logging.getLogger(__name__)
|
||||
_test_logger = logging.getLogger('odoo.tests')
|
||||
|
||||
|
||||
def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=None, report=None):
|
||||
def load_module_graph(cr, graph, status=None, perform_checks=True,
|
||||
skip_modules=None, report=None, models_to_check=None):
|
||||
"""Migrates+Updates or Installs all module nodes from ``graph``
|
||||
:param graph: graph of module nodes to load
|
||||
:param status: deprecated parameter, unused, left to avoid changing signature in 8.0
|
||||
@@ -93,6 +94,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||
if kind in ('demo', 'test'):
|
||||
threading.currentThread().testing = False
|
||||
|
||||
if models_to_check is None:
|
||||
models_to_check = set()
|
||||
|
||||
processed_modules = []
|
||||
loaded_modules = []
|
||||
registry = odoo.registry(cr.dbname)
|
||||
@@ -106,6 +110,8 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||
t0 = time.time()
|
||||
t0_sql = odoo.sql_db.sql_counter
|
||||
|
||||
models_updated = set()
|
||||
|
||||
for index, package in enumerate(graph, 1):
|
||||
module_name = package.name
|
||||
module_id = package.id
|
||||
@@ -127,10 +133,20 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||
model_names = registry.load(cr, package)
|
||||
|
||||
loaded_modules.append(package.name)
|
||||
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
|
||||
if (hasattr(package, 'init') or hasattr(package, 'update')
|
||||
or package.state in ('to install', 'to upgrade')):
|
||||
models_updated |= set(model_names)
|
||||
models_to_check -= set(model_names)
|
||||
registry.setup_models(cr)
|
||||
registry.init_models(cr, model_names, {'module': package.name})
|
||||
cr.commit()
|
||||
elif package.state != 'to remove':
|
||||
# The current module has simply been loaded. The models extended by this module
|
||||
# and for which we updated the schema, must have their schema checked again.
|
||||
# This is because the extension may have changed the model,
|
||||
# e.g. adding required=True to an existing field, but the schema has not been
|
||||
# updated by this module because it's not marked as 'to upgrade/to install'.
|
||||
models_to_check |= set(model_names) & models_updated
|
||||
|
||||
idref = {}
|
||||
|
||||
@@ -225,9 +241,14 @@ def _check_module_names(cr, module_names):
|
||||
incorrect_names = mod_names.difference([x['name'] for x in cr.dictfetchall()])
|
||||
_logger.warning('invalid module names, ignored: %s', ", ".join(incorrect_names))
|
||||
|
||||
def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_modules, perform_checks):
|
||||
def load_marked_modules(cr, graph, states, force, progressdict, report,
|
||||
loaded_modules, perform_checks, models_to_check=None):
|
||||
"""Loads modules marked with ``states``, adding them to ``graph`` and
|
||||
``loaded_modules`` and returns a list of installed/upgraded modules."""
|
||||
|
||||
if models_to_check is None:
|
||||
models_to_check = set()
|
||||
|
||||
processed_modules = []
|
||||
while True:
|
||||
cr.execute("SELECT name from ir_module_module WHERE state IN %s" ,(tuple(states),))
|
||||
@@ -236,7 +257,10 @@ def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_m
|
||||
break
|
||||
graph.add_modules(cr, module_list, force)
|
||||
_logger.debug('Updating graph with %d more modules', len(module_list))
|
||||
loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules, perform_checks=perform_checks)
|
||||
loaded, processed = load_module_graph(
|
||||
cr, graph, progressdict, report=report, skip_modules=loaded_modules,
|
||||
perform_checks=perform_checks, models_to_check=models_to_check
|
||||
)
|
||||
processed_modules.extend(processed)
|
||||
loaded_modules.extend(loaded)
|
||||
if not processed:
|
||||
@@ -250,6 +274,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
if force_demo:
|
||||
force.append('demo')
|
||||
|
||||
models_to_check = set()
|
||||
|
||||
cr = db.cursor()
|
||||
try:
|
||||
if not odoo.modules.db.is_initialized(cr):
|
||||
@@ -278,7 +304,9 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
# processed_modules: for cleanup step after install
|
||||
# loaded_modules: to avoid double loading
|
||||
report = registry._assertion_report
|
||||
loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=update_module, report=report)
|
||||
loaded_modules, processed_modules = load_module_graph(
|
||||
cr, graph, status, perform_checks=update_module,
|
||||
report=report, models_to_check=models_to_check)
|
||||
|
||||
load_lang = tools.config.pop('load_language')
|
||||
if load_lang or update_module:
|
||||
@@ -333,11 +361,11 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
previously_processed = len(processed_modules)
|
||||
processed_modules += load_marked_modules(cr, graph,
|
||||
['installed', 'to upgrade', 'to remove'],
|
||||
force, status, report, loaded_modules, update_module)
|
||||
force, status, report, loaded_modules, update_module, models_to_check)
|
||||
if update_module:
|
||||
processed_modules += load_marked_modules(cr, graph,
|
||||
['to install'], force, status, report,
|
||||
loaded_modules, update_module)
|
||||
loaded_modules, update_module, models_to_check)
|
||||
|
||||
registry.loaded = True
|
||||
registry.setup_models(cr)
|
||||
@@ -407,6 +435,16 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
cr.commit()
|
||||
return registry
|
||||
|
||||
# STEP 5.5: Verify extended fields on every model
|
||||
# This will fix the schema of all models in a situation such as:
|
||||
# - module A is loaded and defines model M;
|
||||
# - module B is installed/upgraded and extends model M;
|
||||
# - module C is loaded and extends model M;
|
||||
# - module B and C depend on A but not on each other;
|
||||
# The changes introduced by module C are not taken into account by the upgrade of B.
|
||||
if models_to_check:
|
||||
registry.init_models(cr, list(models_to_check), {'models_to_check': True})
|
||||
|
||||
# STEP 6: verify custom views on every model
|
||||
if update_module:
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
|
||||
@@ -287,6 +287,8 @@ class Registry(Mapping):
|
||||
"""
|
||||
if 'module' in context:
|
||||
_logger.info('module %s: creating or updating database tables', context['module'])
|
||||
elif context.get('models_to_check', False):
|
||||
_logger.info("verifying fields for every extended model")
|
||||
|
||||
env = odoo.api.Environment(cr, SUPERUSER_ID, context)
|
||||
models = [env[model_name] for model_name in model_names]
|
||||
|
||||
Reference in New Issue
Block a user