diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-03-26 10:33:26 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-03-26 10:33:26 +0100 |
| commit | 5dbf7bf357f8f76a9e36f4707bd9e9bfc77e3436 (patch) | |
| tree | fecaa70fd89a26938b03ad124cb326b6523f47bc /addons | |
| parent | 02f5b654c385772649534fe205d3328fb21354ba (diff) | |
| parent | f00c490be8688d80f211f6755b5ada541eefd602 (diff) | |
[MERGE] forward port branch saas-12.1 up to f00c490be86
Diffstat (limited to 'addons')
41 files changed, 324 insertions, 76 deletions
diff --git a/addons/account/models/account.py b/addons/account/models/account.py index 405e4978bcd..06c05c8180a 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -581,8 +581,7 @@ class AccountJournal(models.Model): if self.company_id != self.env.ref('base.main_company'): alias_name += '-' + str(self.company_id.name) return { - 'alias_defaults': {'type': 'in_invoice'}, - 'alias_user_id': self.env.user.id, + 'alias_defaults': {'type': 'in_invoice', 'company_id': self.company_id.id}, 'alias_parent_thread_id': self.id, 'alias_name': re.sub(r'[^\w]+', '-', alias_name) } diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index fbbde7737b1..43a1eaf7512 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -1928,12 +1928,12 @@ class AccountInvoiceLine(models.Model): } return data - @api.model - def create(self, vals): - if vals.get('display_type', self.default_get(['display_type'])['display_type']): - vals.update(price_unit=0, account_id=False, quantity=0) - - return super(AccountInvoiceLine, self).create(vals) + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if vals.get('display_type', self.default_get(['display_type'])['display_type']): + vals.update(price_unit=0, account_id=False, quantity=0) + return super(AccountInvoiceLine, self).create(vals_list) @api.multi def write(self, values): diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py index aa37b7bec3c..7861644525a 100644 --- a/addons/account/report/account_invoice_report.py +++ b/addons/account/report/account_invoice_report.py @@ -114,7 +114,8 @@ class AccountInvoiceReport(models.Model): ai.partner_bank_id, SUM ((invoice_type.sign_qty * ail.quantity) / u.factor * u2.factor) AS product_qty, SUM(ail.price_subtotal_signed * invoice_type.sign) AS price_total, - SUM(ai.amount_total * invoice_type.sign) AS amount_total, + (ai.amount_total * invoice_type.sign) / (SELECT count(*) FROM account_invoice_line l where invoice_id = ai.id) * + count(*) * invoice_type.sign AS amount_total, SUM(ABS(ail.price_subtotal_signed)) / CASE WHEN SUM(ail.quantity / u.factor * u2.factor) <> 0::numeric THEN SUM(ail.quantity / u.factor * u2.factor) diff --git a/addons/auth_signup/data/auth_signup_data.xml b/addons/auth_signup/data/auth_signup_data.xml index 658ea04d251..6db81fd0dc3 100644 --- a/addons/auth_signup/data/auth_signup_data.xml +++ b/addons/auth_signup/data/auth_signup_data.xml @@ -142,7 +142,7 @@ % set website_url = object.env['ir.config_parameter'].sudo().get_param('web.base.url') Your Odoo domain is: <b><a href='${website_url}'>${website_url}</a></b><br /> Your sign in email is: <b><a href="/web/login?login=${object.email}" target="_blank">${object.email}</a></b><br /><br /> - Never heard of Odoo? It’s a all-in-one business software loved by 3+ million users. It will considerably improve your experience at work and increase your productivity. + Never heard of Odoo? It’s an all-in-one business software loved by 3+ million users. It will considerably improve your experience at work and increase your productivity. <br /><br /> Have a look at the <a href="https://www.odoo.com/page/tour?utm_source=db&utm_medium=auth" style="color: #875A7B;">Odoo Tour</a> to discover the tool. <br /><br /> diff --git a/addons/base_iban/models/res_partner_bank.py b/addons/base_iban/models/res_partner_bank.py index 62b414eae00..f457a912011 100644 --- a/addons/base_iban/models/res_partner_bank.py +++ b/addons/base_iban/models/res_partner_bank.py @@ -70,13 +70,21 @@ class ResPartnerBank(models.Model): @api.model def create(self, vals): if vals.get('acc_number'): - vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number'])) + try: + validate_iban(vals['acc_number']) + vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number'])) + except ValidationError: + pass return super(ResPartnerBank, self).create(vals) @api.multi def write(self, vals): if vals.get('acc_number'): - vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number'])) + try: + validate_iban(vals['acc_number']) + vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number'])) + except ValidationError: + pass return super(ResPartnerBank, self).write(vals) @api.one diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index d2370c986e2..ca59e30798b 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -277,6 +277,13 @@ class Lead(models.Model): if self.state_id: self.country_id = self.state_id.country_id.id + @api.onchange('country_id') + def _onchange_country_id(self): + res = {'domain': {'state_id': []}} + if self.country_id: + res['domain']['state_id'] = [('country_id', '=', self.country_id.id)] + return res + # ---------------------------------------- # ORM override (CRUD, fields_view_get, ...) # ---------------------------------------- diff --git a/addons/crm/models/crm_team.py b/addons/crm/models/crm_team.py index a101fb26848..d7e66bfa3ee 100644 --- a/addons/crm/models/crm_team.py +++ b/addons/crm/models/crm_team.py @@ -48,13 +48,18 @@ class Team(models.Model): team.unassigned_leads_count = counts.get(team.id, 0) def _compute_opportunities(self): - opportunity_data = self.env['crm.lead'].read_group([ + opportunity_data = self.env['crm.lead'].search([ ('team_id', 'in', self.ids), ('probability', '<', 100), ('type', '=', 'opportunity'), - ], ['planned_revenue', 'team_id'], ['team_id']) - counts = {datum['team_id'][0]: datum['team_id_count'] for datum in opportunity_data} - amounts = {datum['team_id'][0]: (datum['planned_revenue']) for datum in opportunity_data} + ]).read(['planned_revenue', 'team_id']) + counts = {} + amounts = {} + for datum in opportunity_data: + counts.setdefault(datum['team_id'][0], 0) + amounts.setdefault(datum['team_id'][0], 0) + counts[datum['team_id'][0]] += 1 + amounts[datum['team_id'][0]] += (datum.get('planned_revenue', 0)) for team in self: team.opportunities_count = counts.get(team.id, 0) team.opportunities_amount = amounts.get(team.id, 0) diff --git a/addons/fleet/models/fleet_vehicle_cost.py b/addons/fleet/models/fleet_vehicle_cost.py index 0c5a04f6d9c..238101c42fb 100644 --- a/addons/fleet/models/fleet_vehicle_cost.py +++ b/addons/fleet/models/fleet_vehicle_cost.py @@ -279,7 +279,7 @@ class FleetVehicleLogContract(models.Model): 'fleet.mail_act_fleet_contract_to_renew', contract.expiration_date, user_id=contract.user_id.id) - expired_contracts = self.search([('state', '!=', 'expired'), ('expiration_date', '<',fields.Date.today() )]) + expired_contracts = self.search([('state', 'not in', ['expired', 'closed']), ('expiration_date', '<',fields.Date.today() )]) expired_contracts.write({'state': 'expired'}) futur_contracts = self.search([('state', 'not in', ['futur', 'closed']), ('start_date', '>', fields.Date.today())]) diff --git a/addons/hr_holidays/static/scss/hr_leave_mobile.scss b/addons/hr_holidays/static/scss/hr_leave_mobile.scss new file mode 100644 index 00000000000..7dabf58db05 --- /dev/null +++ b/addons/hr_holidays/static/scss/hr_leave_mobile.scss @@ -0,0 +1,6 @@ +@include media-breakpoint-down(sm) { + .o_hr_holidays_dates { + display: flex; + flex-flow: column; + } +} diff --git a/addons/hr_holidays/views/hr_leave_template.xml b/addons/hr_holidays/views/hr_leave_template.xml index ecffad0e31d..17000934502 100644 --- a/addons/hr_holidays/views/hr_leave_template.xml +++ b/addons/hr_holidays/views/hr_leave_template.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> - <template id="assets_backend" inherit_id="web.assets_backend"> - <xpath expr="script[last()]" position="after"> - <script type="text/javascript" src="/hr_holidays/static/src/js/time_off_calendar.js"></script> - </xpath> - </template> + <template id="assets_backend" inherit_id="web.assets_backend"> + <xpath expr="script[last()]" position="after"> + <script type="text/javascript" src="/hr_holidays/static/src/js/time_off_calendar.js"></script> + </xpath> + <xpath expr="link[last()]" position="after"> + <link rel="stylesheet" type="text/scss" href="/hr_holidays/static/scss/hr_leave_mobile.scss"/> + </xpath> + </template> </odoo> diff --git a/addons/hr_holidays/views/hr_leave_views.xml b/addons/hr_holidays/views/hr_leave_views.xml index 215a2c36f6d..1cd2367c653 100644 --- a/addons/hr_holidays/views/hr_leave_views.xml +++ b/addons/hr_holidays/views/hr_leave_views.xml @@ -168,7 +168,7 @@ <div> <field name="date_from" invisible="1"/> <field name="date_to" invisible="1"/> - <div class="o_row o_row_readonly"> + <div class="o_row o_row_readonly o_hr_holidays_dates"> <field name="request_date_from" class="oe_inline" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}"/> <span class="oe_inline" diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py index 943c68cf0d0..0542428f25c 100644 --- a/addons/hr_timesheet/models/hr_timesheet.py +++ b/addons/hr_timesheet/models/hr_timesheet.py @@ -148,7 +148,7 @@ class AccountAnalyticLine(models.Model): :return: a dictionary mapping each record id to its corresponding dictionnary values to write (may be empty). """ - result = dict.fromkeys(self.ids, dict()) + result = {id_: {} for id_ in self.ids} sudo_self = self.sudo() # this creates only one env for all operation that required sudo() # (re)compute the amount (depending on unit_amount, employee_id for the cost, and account_id for currency) if any([field_name in values for field_name in ['unit_amount', 'employee_id', 'account_id']]): diff --git a/addons/hr_timesheet/tests/test_timesheet.py b/addons/hr_timesheet/tests/test_timesheet.py index b984beaed0b..a67fb5f79dc 100644 --- a/addons/hr_timesheet/tests/test_timesheet.py +++ b/addons/hr_timesheet/tests/test_timesheet.py @@ -232,3 +232,35 @@ class TestTimesheet(TestCommonTimesheet): self.task1.write({ 'project_id': False }) + + def test_recompute_amount_for_multiple_timesheets(self): + """ Check that amount is recomputed correctly when setting unit_amount for multiple timesheets at once. """ + Timesheet = self.env['account.analytic.line'] + self.empl_employee.timesheet_cost = 5.0 + self.empl_employee2.timesheet_cost = 6.0 + # create a timesheet for each employee + timesheet_1 = Timesheet.sudo(self.user_employee).create({ + 'project_id': self.project_customer.id, + 'task_id': self.task1.id, + 'name': '/', + 'unit_amount': 1, + }) + timesheet_2 = Timesheet.sudo(self.user_employee2).create({ + 'project_id': self.project_customer.id, + 'task_id': self.task1.id, + 'name': '/', + 'unit_amount': 1, + }) + timesheets = timesheet_1 + timesheet_2 + + # increase unit_amount to trigger amount recomputation + timesheets.sudo().write({ + 'unit_amount': 2, + }) + + # since timesheet costs are different for both employees, we should get different amounts + self.assertRecordValues(timesheets, [{ + 'amount': -10.0, + }, { + 'amount': -12.0, + }]) diff --git a/addons/l10n_tr/__manifest__.py b/addons/l10n_tr/__manifest__.py index f33a46de98b..4b5d2ac9033 100644 --- a/addons/l10n_tr/__manifest__.py +++ b/addons/l10n_tr/__manifest__.py @@ -13,8 +13,8 @@ Bu modül kurulduktan sonra, Muhasebe yapılandırma sihirbazı çalışır * Sihirbaz sizden hesap planı şablonu, planın kurulacağı şirket, banka hesap bilgileriniz, ilgili para birimi gibi bilgiler isteyecek. """, - 'author': 'Ahmet Altınışık', - 'maintainer':'https://launchpad.net/~openerp-turkey', + 'author': 'Ahmet Altınışık, Can Tecim', + 'maintainer':'https://launchpad.net/~openerp-turkey, http://www.cantecim.com', 'depends': [ 'account', ], @@ -25,5 +25,6 @@ Bu modül kurulduktan sonra, Muhasebe yapılandırma sihirbazı çalışır 'data/account_data.xml', 'data/account_tax_template_data.xml', 'data/account_chart_template_data.xml', + 'data/res.country.state.csv' ], } diff --git a/addons/l10n_tr/data/res.country.state.csv b/addons/l10n_tr/data/res.country.state.csv new file mode 100644 index 00000000000..7a749f056b1 --- /dev/null +++ b/addons/l10n_tr/data/res.country.state.csv @@ -0,0 +1,82 @@ +"id","country_id:id","name","code" +state_tr_01,base.tr,"Adana","01" +state_tr_02,base.tr,"Adıyaman","02" +state_tr_03,base.tr,"Afyon","03" +state_tr_04,base.tr,"Ağrı","04" +state_tr_05,base.tr,"Amasya","05" +state_tr_06,base.tr,"Ankara","06" +state_tr_07,base.tr,"Antalya","07" +state_tr_08,base.tr,"Artvin","08" +state_tr_09,base.tr,"Aydın","09" +state_tr_10,base.tr,"Balıkesir","10" +state_tr_11,base.tr,"Bilecik","11" +state_tr_12,base.tr,"Bingöl","12" +state_tr_13,base.tr,"Bitlis","13" +state_tr_14,base.tr,"Bolu","14" +state_tr_15,base.tr,"Burdur","15" +state_tr_16,base.tr,"Bursa","16" +state_tr_17,base.tr,"Çanakkale","17" +state_tr_18,base.tr,"Çankırı","18" +state_tr_19,base.tr,"Çorum","19" +state_tr_20,base.tr,"Denizli","20" +state_tr_21,base.tr,"Diyarbakır","21" +state_tr_22,base.tr,"Edirne","22" +state_tr_23,base.tr,"Elazığ","23" +state_tr_24,base.tr,"Erzincan","24" +state_tr_25,base.tr,"Erzurum","25" +state_tr_26,base.tr,"Eskişehir","26" +state_tr_27,base.tr,"Gaziantep","27" +state_tr_28,base.tr,"Giresun","28" +state_tr_29,base.tr,"Gümüşhane","29" +state_tr_30,base.tr,"Hakkari","30" +state_tr_31,base.tr,"Hatay","31" +state_tr_32,base.tr,"Isparta","32" +state_tr_33,base.tr,"İçel","33" +state_tr_34,base.tr,"İstanbul","34" +state_tr_35,base.tr,"İzmir","35" +state_tr_36,base.tr,"Kars","36" +state_tr_37,base.tr,"Kastamonu","37" +state_tr_38,base.tr,"Kayseri","38" +state_tr_39,base.tr,"Kırklareli","39" +state_tr_40,base.tr,"Kırşehir","40" +state_tr_41,base.tr,"Kocaeli","41" +state_tr_42,base.tr,"Konya","42" +state_tr_43,base.tr,"Kütahya","43" +state_tr_44,base.tr,"Malatya","44" +state_tr_45,base.tr,"Manisa","45" +state_tr_46,base.tr,"K.maraş","46" +state_tr_47,base.tr,"Mardin","47" +state_tr_48,base.tr,"Muğla","48" +state_tr_49,base.tr,"Muş","49" +state_tr_50,base.tr,"Nevşehir","50" +state_tr_51,base.tr,"Niğde","51" +state_tr_52,base.tr,"Ordu","52" +state_tr_53,base.tr,"Rize","53" +state_tr_54,base.tr,"Sakarya","54" +state_tr_55,base.tr,"Samsun","55" +state_tr_56,base.tr,"Siirt","56" +state_tr_57,base.tr,"Sinop","57" +state_tr_58,base.tr,"Sivas","58" +state_tr_59,base.tr,"Tekirdağ","59" +state_tr_60,base.tr,"Tokat","60" +state_tr_61,base.tr,"Trabzon","61" +state_tr_62,base.tr,"Tunceli","62" +state_tr_63,base.tr,"Şanlıurfa","63" +state_tr_64,base.tr,"Uşak","64" +state_tr_65,base.tr,"Van","65" +state_tr_66,base.tr,"Yozgat","66" +state_tr_67,base.tr,"Zonguldak","67" +state_tr_68,base.tr,"Aksaray","68" +state_tr_69,base.tr,"Bayburt","69" +state_tr_70,base.tr,"Karaman","70" +state_tr_71,base.tr,"Kırıkkale","71" +state_tr_72,base.tr,"Batman","72" +state_tr_73,base.tr,"Şırnak","73" +state_tr_74,base.tr,"Bartın","74" +state_tr_75,base.tr,"Ardahan","75" +state_tr_76,base.tr,"Iğdır","76" +state_tr_77,base.tr,"Yalova","77" +state_tr_78,base.tr,"Karabük","78" +state_tr_79,base.tr,"Kilis","79" +state_tr_80,base.tr,"Osmaniye","80" +state_tr_81,base.tr,"Düzce","81"
\ No newline at end of file diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index f3d351f678f..f5bfd7c11cf 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -501,19 +501,21 @@ class MailActivity(models.Model): activity_domain.append(('res_id', 'in', res.ids)) grouped_activities = self.env['mail.activity'].read_group( activity_domain, - ['res_id', 'activity_type_id', 'res_name:max(res_name)', 'ids:array_agg(id)', 'date_deadline:min(date_deadline)'], + ['res_id', 'activity_type_id', 'ids:array_agg(id)', 'date_deadline:min(date_deadline)'], ['res_id', 'activity_type_id'], lazy=False) + # filter out unreadable records + if not domain: + res_ids = tuple(a['res_id'] for a in grouped_activities) + res = self.env[res_model].search([('id', 'in', res_ids)]) + grouped_activities = [a for a in grouped_activities if a['res_id'] in res.ids] activity_type_ids = self.env['mail.activity.type'] - res_id_to_name = {} res_id_to_deadline = {} activity_data = defaultdict(dict) for group in grouped_activities: res_id = group['res_id'] - res_name = group['res_name'] activity_type_id = group['activity_type_id'][0] activity_type_ids |= self.env['mail.activity.type'].browse(activity_type_id) # we will get the name when reading mail_template_ids - res_id_to_name[res_id] = res_name res_id_to_deadline[res_id] = group['date_deadline'] if (res_id not in res_id_to_deadline or group['date_deadline'] < res_id_to_deadline[res_id]) else res_id_to_deadline[res_id] state = self._compute_state_from_date(group['date_deadline'], self.user_id.sudo().tz) activity_data[res_id][activity_type_id] = { @@ -523,6 +525,7 @@ class MailActivity(models.Model): 'o_closest_deadline': group['date_deadline'], } res_ids_sorted = sorted(res_id_to_deadline, key=lambda item: res_id_to_deadline[item]) + res_id_to_name = dict(self.env[res_model].browse(res_ids_sorted).name_get()) activity_type_infos = [] for elem in sorted(activity_type_ids, key=lambda item: item.sequence): mail_template_info = [] diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index a18bd385f50..818de84dc20 100644 --- a/addons/payment_adyen/models/payment.py +++ b/addons/payment_adyen/models/payment.py @@ -18,6 +18,31 @@ from odoo.tools.pycompat import to_text _logger = logging.getLogger(__name__) +# https://docs.adyen.com/developers/development-resources/currency-codes +CURRENCY_CODE_MAPS = { + "BHD": 3, + "CVE": 0, + "DJF": 0, + "GNF": 0, + "IDR": 0, + "JOD": 3, + "JPY": 0, + "KMF": 0, + "KRW": 0, + "KWD": 3, + "LYD": 3, + "OMR": 3, + "PYG": 0, + "RWF": 0, + "TND": 3, + "UGX": 0, + "VND": 0, + "VUV": 0, + "XAF": 0, + "XOF": 0, + "XPF": 0, +} + class AcquirerAdyen(models.Model): _inherit = 'payment.acquirer' @@ -28,6 +53,16 @@ class AcquirerAdyen(models.Model): adyen_skin_hmac_key = fields.Char('Skin HMAC Key', required_if_provider='adyen', groups='base.group_user') @api.model + def _adyen_convert_amount(self, amount, currency): + """ + Adyen requires the amount to be multiplied by 10^k, + where k depends on the currency code. + """ + k = CURRENCY_CODE_MAPS.get(currency.name, 2) + paymentAmount = int(tools.float_round(amount, k) * (10**k)) + return paymentAmount + + @api.model def _get_adyen_urls(self, environment): """ Adyen URLs: yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple """ return { @@ -120,12 +155,13 @@ class AcquirerAdyen(models.Model): import datetime from dateutil import relativedelta + paymentAmount = self._adyen_convert_amount(values['amount'], values['currency']) if self.provider == 'adyen' and len(self.adyen_skin_hmac_key) == 64: tmp_date = datetime.datetime.today() + relativedelta.relativedelta(days=1) values.update({ 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(tools.float_round(values['amount'], 2) * 100), + 'paymentAmount': '%d' % paymentAmount, 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date.strftime('%Y-%m-%d'), 'skinCode': self.adyen_skin_code, @@ -143,7 +179,7 @@ class AcquirerAdyen(models.Model): values.update({ 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(tools.float_round(values['amount'], 2) * 100), + 'paymentAmount': '%d' % paymentAmount, 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date, 'skinCode': self.adyen_skin_code, diff --git a/addons/payment_ogone/models/payment.py b/addons/payment_ogone/models/payment.py index c78149af1d2..8bf9ee730c2 100644 --- a/addons/payment_ogone/models/payment.py +++ b/addons/payment_ogone/models/payment.py @@ -15,6 +15,7 @@ from odoo import api, fields, models, _ from odoo.addons.payment.models.payment_acquirer import ValidationError from odoo.addons.payment_ogone.controllers.main import OgoneController from odoo.addons.payment_ogone.data import ogone +from odoo.http import request from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, ustr from odoo.tools.float_utils import float_compare, float_repr, float_round @@ -356,9 +357,14 @@ class PaymentTxOgone(models.Model): 'ECI': 9, # Recurring (from eCommerce) 'ALIAS': self.payment_token_id.acquirer_ref, 'RTIMEOUT': 30, - 'PARAMPLUS' : url_encode(param_plus) + 'PARAMPLUS': url_encode(param_plus), + 'EMAIL': self.partner_id.email or '', + 'CN': self.partner_id.name or '', } + if request: + data['REMOTE_ADDR'] = request.httprequest.remote_addr + if kwargs.get('3d_secure'): data.update({ 'FLAG3D': 'Y', diff --git a/addons/payment_stripe/static/src/js/stripe.js b/addons/payment_stripe/static/src/js/stripe.js index 262068fd12d..7d8d20a0590 100644 --- a/addons/payment_stripe/static/src/js/stripe.js +++ b/addons/payment_stripe/static/src/js/stripe.js @@ -21,9 +21,13 @@ odoo.define('payment_stripe.stripe', function(require) { $.blockUI.defaults.css["background-color"] = ''; $.blockUI.defaults.overlayCSS["opacity"] = '0.9'; } + var stripeHandler; function getStripeHandler() { - var handler = StripeCheckout.configure({ + if (stripeHandler) { + return stripeHandler; + } + var handler = stripeHandler = StripeCheckout.configure({ key: $("input[name='stripe_key']").val(), image: $("input[name='stripe_image']").val(), locale: 'auto', diff --git a/addons/payment_stripe/views/payment_stripe_templates.xml b/addons/payment_stripe/views/payment_stripe_templates.xml index 2e3101e5de0..46da1615802 100644 --- a/addons/payment_stripe/views/payment_stripe_templates.xml +++ b/addons/payment_stripe/views/payment_stripe_templates.xml @@ -21,7 +21,12 @@ <input type="hidden" name='email' t-att-value='email'/> <input id="acquirer_stripe" type="hidden" name="acquirer" t-att-value="acquirer.id"/> <input type="hidden" name="stripe_key" t-att-value="acquirer.stripe_publishable_key"/> - <script type="text/javascript" src="/payment_stripe/static/src/js/stripe.js"></script> + <script type="text/javascript"> + odoo.define(function (require) { + var ajax = require('web.ajax'); + ajax.loadJS("/payment_stripe/static/src/js/stripe.js"); + }); + </script> </template> <template id="stripe_s2s_form"> diff --git a/addons/point_of_sale/views/pos_config_view.xml b/addons/point_of_sale/views/pos_config_view.xml index 2994faa3078..133f4e5e8ea 100644 --- a/addons/point_of_sale/views/pos_config_view.xml +++ b/addons/point_of_sale/views/pos_config_view.xml @@ -141,16 +141,16 @@ </div> </div> </div> - <h2>IotBox / Hardware Proxy</h2> + <h2>IoT Box</h2> <div class="row mt16 o_settings_container" id="posbox_reference"> <div class="col-12 col-lg-6 o_setting_box"> <div class="o_setting_left_pane"> <field name="is_posbox"/> </div> <div class="o_setting_right_pane"> - <label for="is_posbox"/> + <label for="is_posbox" string="IoT Box"/> <div class="text-muted"> - Use an integrated hardware setup like <a href="https://www.odoo.com/documentation/user/online/iot/pos.html" target="_blank">IoT Box</a> + Connect devices to your PoS (ticket printer, barcode scanner, scale, etc.) </div> <div class="content-group" attrs="{'invisible' : [('is_posbox', '=', False)]}"> <div class="row mt16"> diff --git a/addons/product/views/product_template_views.xml b/addons/product/views/product_template_views.xml index 2fa45b79f2e..9c800274522 100644 --- a/addons/product/views/product_template_views.xml +++ b/addons/product/views/product_template_views.xml @@ -69,7 +69,6 @@ <field name="image_small"/> <field name="lst_price"/> <field name="product_variant_count"/> - <field name="product_variant_ids"/> <field name="currency_id"/> <field name="activity_state"/> <progressbar field="activity_state" colors='{"planned": "success", "today": "warning", "overdue": "danger"}'/> diff --git a/addons/purchase_requisition/models/purchase.py b/addons/purchase_requisition/models/purchase.py index 5379a3bf29c..70643757781 100644 --- a/addons/purchase_requisition/models/purchase.py +++ b/addons/purchase_requisition/models/purchase.py @@ -38,7 +38,7 @@ class PurchaseOrder(models.Model): else: self.origin = requisition.name self.notes = requisition.description - self.date_order = requisition.date_end or fields.Datetime.now() + self.date_order = fields.Datetime.now() if requisition.type_id.line_copy != 'copy': return diff --git a/addons/sale/models/account_invoice.py b/addons/sale/models/account_invoice.py index 29fa6b64f1b..76c4e541be0 100644 --- a/addons/sale/models/account_invoice.py +++ b/addons/sale/models/account_invoice.py @@ -40,7 +40,8 @@ class AccountInvoice(models.Model): def _onchange_delivery_address(self): addr = self.partner_id.address_get(['delivery']) self.partner_shipping_id = addr and addr.get('delivery') - if self.env.context.get('type', 'out_invoice') == 'out_invoice': + inv_type = self.type or self.env.context.get('type', 'out_invoice') + if inv_type == 'out_invoice': company = self.company_id or self.env.user.company_id self.comment = company.with_context(lang=self.partner_id.lang).invoice_terms diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 22b8d24e131..875b48646c2 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -506,6 +506,8 @@ class SaleOrder(models.Model): # We only want to create sections that have at least one invoiceable line pending_section = None + # Create lines in batch to avoid performance problems + line_vals_list = [] for line in order.order_line: if line.display_type == 'line_section': pending_section = line @@ -527,14 +529,21 @@ class SaleOrder(models.Model): if line.qty_to_invoice > 0 or (line.qty_to_invoice < 0 and final): if pending_section: - pending_section.invoice_line_create(invoices[group_key].id, pending_section.qty_to_invoice) + line_vals_list.extend(pending_section.invoice_line_create_vals( + invoices[group_key].id, + pending_section.qty_to_invoice + )) pending_section = None - line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice) + line_vals_list.extend(line.invoice_line_create_vals( + invoices[group_key].id, line.qty_to_invoice + )) if references.get(invoices.get(group_key)): if order not in references[invoices[group_key]]: references[invoices[group_key]] |= order + self.env['account.invoice.line'].create(line_vals_list) + for group_key in invoices: invoices[group_key].write({'name': ', '.join(invoices_name[group_key]), 'origin': ', '.join(invoices_origin[group_key])}) @@ -1345,18 +1354,34 @@ class SaleOrderLine(models.Model): @api.multi def invoice_line_create(self, invoice_id, qty): """ Create an invoice line. The quantity to invoice can be positive (invoice) or negative (refund). + + .. deprecated:: 12.0 + Replaced by :func:`invoice_line_create_vals` which can be used for creating + `account.invoice.line` records in batch + :param invoice_id: integer :param qty: float quantity to invoice :returns recordset of account.invoice.line created """ - invoice_lines = self.env['account.invoice.line'] + return self.env['account.invoice.line'].create( + self.invoice_line_create_vals(invoice_id, qty)) + + def invoice_line_create_vals(self, invoice_id, qty): + """ Create an invoice line. The quantity to invoice can be positive (invoice) or negative + (refund). + + :param invoice_id: integer + :param qty: float quantity to invoice + :returns list of dict containing creation values for account.invoice.line records + """ + vals_list = [] precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for line in self: if not float_is_zero(qty, precision_digits=precision) or not line.product_id: vals = line._prepare_invoice_line(qty=qty) vals.update({'invoice_id': invoice_id, 'sale_line_ids': [(6, 0, [line.id])]}) - invoice_lines |= self.env['account.invoice.line'].create(vals) - return invoice_lines + vals_list.append(vals) + return vals_list @api.multi def _prepare_procurement_values(self, group_id=False): diff --git a/addons/sale/report/sale_report_templates.xml b/addons/sale/report/sale_report_templates.xml index b438cbd3db2..edce182dcfc 100644 --- a/addons/sale/report/sale_report_templates.xml +++ b/addons/sale/report/sale_report_templates.xml @@ -116,14 +116,14 @@ </td> </t> <t t-if="line.display_type == 'line_section'"> - <td t-att-colspan="colspan"> + <td t-att-colspan="99"> <span t-field="line.name"/> </td> <t t-set="current_section" t-value="line"/> <t t-set="current_subtotal" t-value="0"/> </t> <t t-if="line.display_type == 'line_note'"> - <td t-att-colspan="colspan"> + <td t-att-colspan="99"> <span t-field="line.name"/> </td> </t> @@ -131,7 +131,7 @@ <t t-if="current_section and (line_last or doc.order_line[line_index+1].display_type == 'line_section')"> <tr class="is-subtotal text-right"> - <td t-att-colspan="colspan"> + <td t-att-colspan="99"> <strong class="mr16">Subtotal</strong> <span t-esc="current_subtotal" diff --git a/addons/sale/views/sale_portal_templates.xml b/addons/sale/views/sale_portal_templates.xml index 52960206c53..a8d59282942 100644 --- a/addons/sale/views/sale_portal_templates.xml +++ b/addons/sale/views/sale_portal_templates.xml @@ -161,7 +161,7 @@ <t t-if="sale_order.remaining_validity_days > 1">days</t><t t-else="">day</t> </div> </li> - <li t-if="sale_order.amount_undiscounted > sale_order.amount_untaxed" class="list-group-item flex-grow-1"> + <li t-if="sale_order.amount_undiscounted - sale_order.amount_untaxed > 0.01" class="list-group-item flex-grow-1"> <small><b class="text-muted">Your advantage</b></small> <small> <b t-field="sale_order.amount_undiscounted" diff --git a/addons/stock/static/src/js/stock_traceability_report_widgets.js b/addons/stock/static/src/js/stock_traceability_report_widgets.js index 7a52ea100c1..97468a48135 100644 --- a/addons/stock/static/src/js/stock_traceability_report_widgets.js +++ b/addons/stock/static/src/js/stock_traceability_report_widgets.js @@ -39,7 +39,7 @@ var ReportWidget = Widget.extend({ this.do_action({ type: 'ir.actions.client', tag: 'stock_report_generic', - name: $el.data('lot_name'), + name: $el.data('lot_name') !== undefined && $el.data('lot_name').toString(), context: { active_id : $el.data('lot_id'), active_model : 'stock.production.lot', diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 269964ccef1..171d4c1a842 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -361,7 +361,7 @@ <filter name="done" string="Done" domain="[('state','=','done')]" help="Pickings already processed"/> <filter name="cancel" string="Cancelled" domain="[('state','=', 'cancel')]" help="Cancelled Moves"/> <separator/> - <filter name="late" string="Late" domain="[('scheduled_date','<', time.strftime('%%Y-%%m-%%d %%H:%%M:%%S'))]" help="Pickings that are late on scheduled time"/> + <filter name="late" string="Late" domain="[('scheduled_date','<', time.strftime('%%Y-%%m-%%d %%H:%%M:%%S')), ('state', 'in', ('assigned', 'waiting', 'confirmed'))]" help="Pickings that are late on scheduled time"/> <separator/> <filter name="backorder" string="Backorders" domain="[('backorder_id','!=', False)]" help="Remaining parts of picking partially processed"/> <separator/> diff --git a/addons/stock_dropshipping/models/sale.py b/addons/stock_dropshipping/models/sale.py index 5e23612a098..e80b7433e29 100644 --- a/addons/stock_dropshipping/models/sale.py +++ b/addons/stock_dropshipping/models/sale.py @@ -13,7 +13,7 @@ class SaleOrderLine(models.Model): def _get_qty_procurement(self, previous_product_uom_qty): # People without purchase rights should be able to do this operation purchase_lines_sudo = self.sudo().purchase_line_ids - if not self.move_ids.filtered(lambda r: r.state != 'cancel') and purchase_lines_sudo.filtered(lambda r: r.state != 'cancel'): + if purchase_lines_sudo.filtered(lambda r: r.state != 'cancel'): qty = 0.0 for po_line in purchase_lines_sudo.filtered(lambda r: r.state != 'cancel'): qty += po_line.product_uom._compute_quantity(po_line.product_qty, self.product_uom, rounding_method='HALF-UP') diff --git a/addons/stock_picking_batch/report/report_picking_batch.xml b/addons/stock_picking_batch/report/report_picking_batch.xml index 079ccdf1ed4..4eb4cf2ec62 100644 --- a/addons/stock_picking_batch/report/report_picking_batch.xml +++ b/addons/stock_picking_batch/report/report_picking_batch.xml @@ -20,6 +20,7 @@ <thead> <tr> <th>Picking Reference</th> + <th>Barcode</th> <th>Status</th> <th>Commitment Date</th> <th>Scheduled Date</th> @@ -31,6 +32,9 @@ <span t-field="pick.name"/> </td> <td> + <img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' % ('Code128', pick.name, 300, 50)" alt="Barcode"/> + </td> + <td> <span t-field="pick.state"/> </td> <td> diff --git a/addons/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index 1a796b07501..dea415d6765 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -502,7 +502,7 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.assertEqual(msg.model, False, 'message_post: private discussion: parameter model not correctly ignored when having no res_id') # Test: message-id - self.assertIn('openerp-private', msg.message_id, 'message_post: private discussion: message-id should contain the private keyword') + self.assertIn('openerp-private', msg.message_id.split('@')[0], 'message_post: private discussion: message-id should contain the private keyword') # Do: Bert replies through mailgateway (is a customer) self.format_and_process( @@ -530,9 +530,9 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models', 'odoo.addons.mail.models.mail_mail') def test_forward_parent_id(self): msg = self.test_record.sudo(self.user_employee).message_post(no_auto_thread=True, subtype='mail.mt_comment') - self.assertNotIn(msg.model, msg.message_id) - self.assertNotIn('-%d-' % msg.res_id, msg.message_id) - self.assertIn('reply_to', msg.message_id) + self.assertNotIn(msg.model, msg.message_id.split('@')[0]) + self.assertNotIn('-%d-' % msg.res_id, msg.message_id.split('@')[0]) + self.assertIn('reply_to', msg.message_id.split('@')[0]) # forward it to a new thread AND an existing thread fw_msg_id = '<THIS.IS.A.FW.MESSAGE.1@bert.fr>' diff --git a/addons/test_mail/tests/test_mail_message.py b/addons/test_mail/tests/test_mail_message.py index 3b7cf25da46..c5962339f68 100644 --- a/addons/test_mail/tests/test_mail_message.py +++ b/addons/test_mail/tests/test_mail_message.py @@ -31,7 +31,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): 'reply_to': 'test.reply@example.com', 'email_from': 'test.from@example.com', }) - self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') self.assertEqual(msg.reply_to, 'test.reply@example.com') self.assertEqual(msg.email_from, 'test.from@example.com') @@ -39,7 +39,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() msg = self.Message.create({}) - self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) @@ -50,7 +50,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink() msg = self.Message.create({}) - self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) @@ -61,7 +61,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall) msg = self.Message.create({}) - self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') reply_to_name = self.env.user.company_id.name reply_to_email = '%s@%s' % (alias_catchall, alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) @@ -74,7 +74,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): 'model': 'mail.test', 'res_id': self.alias_record.id }) - self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id) + self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) @@ -88,7 +88,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): 'model': 'mail.test', 'res_id': self.alias_record.id }) - self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id) + self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, self.alias_record.name) reply_to_email = '%s@%s' % (self.alias_record.alias_name, alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) @@ -104,7 +104,7 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): 'model': 'mail.test', 'res_id': self.alias_record.id }) - self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id) + self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, self.alias_record.name) reply_to_email = '%s@%s' % (self.alias_record.alias_name, alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) @@ -116,9 +116,9 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): 'res_id': self.alias_record.id, 'no_auto_thread': True, }) - self.assertIn('reply_to', msg.message_id) - self.assertNotIn('mail.test', msg.message_id) - self.assertNotIn('-%d-' % self.alias_record.id, msg.message_id) + self.assertIn('reply_to', msg.message_id.split('@')[0]) + self.assertNotIn('mail.test', msg.message_id.split('@')[0]) + self.assertNotIn('-%d-' % self.alias_record.id, msg.message_id.split('@')[0]) def test_mail_message_base64_image(self): msg = self.env['mail.message'].sudo(self.user_employee).create({ diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js index 0934ae462b3..af31c252898 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -19,6 +19,10 @@ var QuickCreate = require('web.CalendarQuickCreate'); var _t = core._t; var QWeb = core.qweb; +function dateToServer (date) { + return date.clone().utc().locale('en').format('YYYY-MM-DD HH:mm:ss'); +} + var CalendarController = AbstractController.extend({ custom_events: _.extend({}, AbstractController.prototype.custom_events, { changeDate: '_onChangeDate', @@ -236,7 +240,7 @@ var CalendarController = AbstractController.extend({ for (var k in context) { if (context[k] && context[k]._isAMomentObject) { - context[k] = context[k].clone().utc().format('YYYY-MM-DD HH:mm:ss'); + context[k] = dateToServer(context[k]); } } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 7a6bca6aa7a..f28190d2700 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1505,7 +1505,7 @@ <t t-set="att_prev" t-value="{'accesskey': 'p'}" /> <t t-set="att_next" t-value="{'accesskey': 'n'}" /> </t> - <button type="button" class="fa fa-chevron-left btn btn-secondary o_pager_previous" t-att="att_prev" aria-label="Previous" title="Next" tabindex="-1"/> + <button type="button" class="fa fa-chevron-left btn btn-secondary o_pager_previous" t-att="att_prev" aria-label="Previous" title="Previous" tabindex="-1"/> <button type="button" class="fa fa-chevron-right btn btn-secondary o_pager_next" t-att="att_next" aria-label="Next" title="Next" tabindex="-1"/> </span> </div> diff --git a/addons/web_editor/static/src/js/backend/convert_inline.js b/addons/web_editor/static/src/js/backend/convert_inline.js index b6b36a388ef..0c985ba761f 100644 --- a/addons/web_editor/static/src/js/backend/convert_inline.js +++ b/addons/web_editor/static/src/js/backend/convert_inline.js @@ -175,7 +175,7 @@ function getMatchedCSSRules(a) { break; } $el = $el.parent(); - } while (!$el.is('html')); + } while ($el.length && !$el.is('html')); } return style; diff --git a/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js b/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js index b4e783a5f6d..b8c6057bb0e 100644 --- a/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js +++ b/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js @@ -392,6 +392,7 @@ var SnippetEditor = Widget.extend({ */ _onDragAndDropStart: function () { var self = this; + this.dropped = false; self.size = { width: self.$target.width(), height: self.$target.height() @@ -439,10 +440,21 @@ var SnippetEditor = Widget.extend({ * 'move' button. * * @private + * @param {Event} ev + * @param {Object} ui */ - _onDragAndDropStop: function () { + _onDragAndDropStop: function (ev, ui) { this.$editable.find('.oe_drop_zone').droppable('destroy').remove(); + // TODO lot of this is duplicated code of the d&d feature of snippets + if (!this.dropped) { + var $el = $.nearest({x: ui.position.left, y: ui.position.top}, '.oe_drop_zone').first(); + if ($el.length) { + $el.after(this.$target); + this.dropped = true; + } + } + var prev = this.$target.first()[0].previousSibling; var next = this.$target.last()[0].nextSibling; var $parent = this.$target.parent(); diff --git a/addons/web_editor/static/src/scss/web_editor.common.scss b/addons/web_editor/static/src/scss/web_editor.common.scss index 6f83dc28524..76f167e0a7d 100644 --- a/addons/web_editor/static/src/scss/web_editor.common.scss +++ b/addons/web_editor/static/src/scss/web_editor.common.scss @@ -203,7 +203,7 @@ ul.oe_menu_editor { @mixin o-spacing-all($factor: 1) { // Generate vertical margin/padding classes used by the editor @for $i from 0 through (256 / 8) { - @include o-vspacing($i * 8); + @include o-vspacing($i * 8, $factor); } @include o-vspacing(4, $factor); diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py index 0280dbd71c7..1174f91d40e 100644 --- a/addons/website_event/controllers/main.py +++ b/addons/website_event/controllers/main.py @@ -181,10 +181,7 @@ class WebsiteEventController(http.Controller): def event_register(self, event, **post): if not event.can_access_from_current_website(): raise werkzeug.exceptions.NotFound() - if not request.context.get('pricelist'): - pricelist = request.website.get_current_pricelist() - if pricelist: - event = event.with_context(pricelist=pricelist.id) + values = { 'event': event, 'main_object': event, diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py index 689fe5cdc81..acf5f58be2d 100644 --- a/addons/website_event_sale/controllers/main.py +++ b/addons/website_event_sale/controllers/main.py @@ -11,6 +11,10 @@ class WebsiteEventSaleController(WebsiteEventController): @http.route() def event_register(self, event, **post): event = event.with_context(pricelist=request.website.id) + if not request.context.get('pricelist'): + pricelist = request.website.get_current_pricelist() + if pricelist: + event = event.with_context(pricelist=pricelist.id) return super(WebsiteEventSaleController, self).event_register(event, **post) def _process_tickets_details(self, data): diff --git a/addons/website_forum/static/src/scss/website_forum.scss b/addons/website_forum/static/src/scss/website_forum.scss index 391adf9d792..aadd4802fd4 100644 --- a/addons/website_forum/static/src/scss/website_forum.scss +++ b/addons/website_forum/static/src/scss/website_forum.scss @@ -223,3 +223,7 @@ img.o_forum_avatar_big { height: $owprofile-tabs-height; background-color: #66445e; } + +.website_forum { + margin-bottom: $spacer; +} |
