diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-06-09 16:43:27 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-06-09 16:43:27 +0200 |
| commit | cc38b93ab2a6daf9c5badbc387cff20d1a01ddee (patch) | |
| tree | d5d9942c4101f836a247e609266d3d39f1eeb4ee /addons | |
| parent | fb504f3cbd41dc52a81d76aa54d83117730671d0 (diff) | |
| parent | 49f819a7a797f0c046337118847f143197714e03 (diff) | |
[MERGE] forward port branch saas-15 up to 49f819a7a79
Diffstat (limited to 'addons')
31 files changed, 210 insertions, 73 deletions
diff --git a/addons/account/models/account.py b/addons/account/models/account.py index fcab29082bd..9354e4731bd 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -468,7 +468,10 @@ class AccountJournal(models.Model): @api.model def name_search(self, name='', args=None, operator='ilike', limit=100): args = args or [] - recs = self.search(['|', ('code', operator, name), ('name', operator, name)] + args, limit=limit) + connector = '|' + if operator in expression.NEGATIVE_TERM_OPERATORS: + connector = '&' + recs = self.search([connector, ('code', operator, name), ('name', operator, name)] + args, limit=limit) return recs.name_get() @api.multi diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 6aff8481161..0fc05b549bc 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -248,7 +248,7 @@ class AccountBankStatement(models.Model): for aml in st_line.journal_entry_ids: moves |= aml.move_id if moves: - moves.post() + moves.filtered(lambda m: m.state != 'posted').post() statement.message_post(body=_('Statement %s confirmed, journal items were created.') % (statement.name,)) statements.link_bank_to_partner() statements.write({'state': 'confirm', 'date_done': time.strftime("%Y-%m-%d %H:%M:%S")}) diff --git a/addons/account/tests/account_test_classes.py b/addons/account/tests/account_test_classes.py index cf37e2493ef..8477f4109d9 100644 --- a/addons/account/tests/account_test_classes.py +++ b/addons/account/tests/account_test_classes.py @@ -28,3 +28,30 @@ class AccountingTestCase(HttpCase): if theorical_lines: raise ValidationError('Remaining theorical line (not found). %s)' % ([(aml[0], aml[1], aml[2]) for aml in theorical_lines])) return True + + def ensure_account_property(self, property_name): + '''Ensure the ir.property targetting an account.account passed as parameter exists. + In case it's not: create it with a random account. This is useful when testing with + partially defined localization (missing stock properties for example) + + :param property_name: The name of the property. + ''' + company_id = self.env.user.company_id + field_id = self.env['ir.model.fields'].search( + [('model', '=', 'product.template'), ('name', '=', property_name)], limit=1) + property_id = self.env['ir.property'].search([ + ('company_id', '=', company_id.id), + ('name', '=', property_name), + ('res_id', '=', None), + ('fields_id', '=', field_id.id)], limit=1) + account_id = self.env['account.account'].search([('company_id', '=', company_id.id)], limit=1) + value_reference = 'account.account,%d' % account_id.id + if property_id and not property_id.value_reference: + property_id.value_reference = value_reference + else: + self.env['ir.property'].create({ + 'name': property_name, + 'company_id': company_id.id, + 'fields_id': field_id.id, + 'value_reference': value_reference, + }) diff --git a/addons/base_geolocalize/models/res_partner.py b/addons/base_geolocalize/models/res_partner.py index 778a844ad83..44fa8d9692f 100644 --- a/addons/base_geolocalize/models/res_partner.py +++ b/addons/base_geolocalize/models/res_partner.py @@ -8,6 +8,8 @@ from odoo.exceptions import UserError def geo_find(addr): + if not addr: + return None url = 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=' url += urllib2.quote(addr.encode('utf8')) diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 43eb8f08d6e..889ddf7bb7b 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -100,18 +100,23 @@ class IrModule(models.Model): raise UserError(_("File '%s' exceed maximum allowed file size") % zf.filename) with tempdir() as module_dir: - z.extractall(module_dir) - dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))] - for mod_name in dirs: - module_names.append(mod_name) - try: - # assert mod_name.startswith('theme_') - path = opj(module_dir, mod_name) - self._import_module(mod_name, path, force=force) - success.append(mod_name) - except Exception as e: - _logger.exception('Error while importing module') - errors[mod_name] = exception_to_unicode(e) + import odoo.modules as addons + try: + addons.module.ad_paths.append(module_dir) + z.extractall(module_dir) + dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))] + for mod_name in dirs: + module_names.append(mod_name) + try: + # assert mod_name.startswith('theme_') + path = opj(module_dir, mod_name) + self._import_module(mod_name, path, force=force) + success.append(mod_name) + except Exception as e: + _logger.exception('Error while importing module') + errors[mod_name] = exception_to_unicode(e) + finally: + addons.module.ad_paths.remove(module_dir) r = ["Successfully imported module '%s'" % mod for mod in success] for mod, error in errors.items(): r.append("Error while importing module '%s': %r" % (mod, error)) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index 98f5e5c95d9..0782ae3384a 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -567,15 +567,18 @@ class Meeting(models.Model): if not event_date: event_date = datetime.now() - # Convert the event date to saved timezone (or context tz) as it'll - # define the correct hour/day asked by the user to repeat for recurrence. - event_date = event_date.astimezone(timezone) # transform "+hh:mm" timezone - rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date, forceset=True) + if self.allday and self.rrule and 'UNTIL' in self.rrule and 'Z' not in self.rrule: + rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date.replace(tzinfo=None), forceset=True, ignoretz=True) + else: + # Convert the event date to saved timezone (or context tz) as it'll + # define the correct hour/day asked by the user to repeat for recurrence. + event_date = event_date.astimezone(timezone) # transform "+hh:mm" timezone + rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date, forceset=True, tzinfos={}) recurring_meetings = self.search([('recurrent_id', '=', self.id), '|', ('active', '=', False), ('active', '=', True)]) for meeting in recurring_meetings: rset1._exdate.append(todate(meeting.recurrent_id_date)) - return [d.astimezone(pytz.UTC) for d in rset1] + return [d.astimezone(pytz.UTC) if d.tzinfo else d for d in rset1] @api.multi def _get_recurrency_end_date(self): diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index fb4472f43e8..5ea52c874e2 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -247,6 +247,7 @@ class Lead(models.Model): team_id = self.env['crm.team']._get_default_team_id(user_id=user_id) return {'team_id': team_id} + @api.constrains('user_id') @api.onchange('user_id') def _onchange_user_id(self): """ When changing the user, also set a team_id or restrict team id to the ones user_id is member of. """ diff --git a/addons/delivery/models/delivery_carrier.py b/addons/delivery/models/delivery_carrier.py index 543c0feb0b7..dc91bf4e5e6 100644 --- a/addons/delivery/models/delivery_carrier.py +++ b/addons/delivery/models/delivery_carrier.py @@ -226,26 +226,26 @@ class DeliveryCarrier(models.Model): if record.delivery_type == 'fixed': PriceRule.search([('carrier_id', '=', record.id)]).unlink() - line_data = { - 'carrier_id': record.id, - 'variable': 'price', - 'operator': '>=', - } - # Create the delivery price rules - if record.free_if_more_than: - line_data.update({ - 'max_value': record.amount, - 'standard_price': 0.0, - 'list_base_price': 0.0, - }) - PriceRule.create(line_data) - if record.fixed_price is not False: - line_data.update({ - 'max_value': 0.0, - 'standard_price': record.fixed_price, - 'list_base_price': record.fixed_price, - }) - PriceRule.create(line_data) + line_data = { + 'carrier_id': record.id, + 'variable': 'price', + 'operator': '>=', + } + # Create the delivery price rules + if record.free_if_more_than: + line_data.update({ + 'max_value': record.amount, + 'standard_price': 0.0, + 'list_base_price': 0.0, + }) + PriceRule.create(line_data) + if record.fixed_price is not False: + line_data.update({ + 'max_value': 0.0, + 'standard_price': record.fixed_price, + 'list_base_price': record.fixed_price, + }) + PriceRule.create(line_data) return True @api.model diff --git a/addons/hr_holidays/models/hr_holidays.py b/addons/hr_holidays/models/hr_holidays.py index eff33ce5af3..2ad8de7130e 100644 --- a/addons/hr_holidays/models/hr_holidays.py +++ b/addons/hr_holidays/models/hr_holidays.py @@ -329,9 +329,12 @@ class Holidays(models.Model): res = [] for leave in self: if leave.type == 'remove': - res.append((leave.id, _("%s on %s : %.2f day(s)") % (leave.employee_id.name or leave.category_id.name, leave.holiday_status_id.name, leave.number_of_days_temp))) + if self.env.context.get('short_name'): + res.append((leave.id, _("%s : %.2f day(s)") % (leave.name or leave.holiday_status_id.name, leave.number_of_days_temp))) + else: + res.append((leave.id, _("%s on %s : %.2f day(s)") % (leave.employee_id.name or leave.category_id.name, leave.holiday_status_id.name, leave.number_of_days_temp))) else: - res.append((leave.id, _("Allocation of %s : %.2f day(s) To %s") % (leave.holiday_status_id.name, leave.number_of_days_temp,leave.employee_id.name))) + res.append((leave.id, _("Allocation of %s : %.2f day(s) To %s") % (leave.holiday_status_id.name, leave.number_of_days_temp, leave.employee_id.name))) return res def _check_state_access_right(self, vals): diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index a797892a4c2..4f728d48698 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -208,8 +208,11 @@ class MrpProduction(models.Model): @api.depends('move_raw_ids.quantity_done', 'move_finished_ids.quantity_done') def _compute_post_visible(self): for order in self: - order.post_visible = any(order.move_raw_ids.filtered(lambda x: (x.quantity_done) > 0 and (x.state not in ['done', 'cancel']))) or \ - any(order.move_finished_ids.filtered(lambda x: (x.quantity_done) > 0 and (x.state not in ['done', 'cancel']))) + if order.product_tmpl_id._is_cost_method_standard(): + order.post_visible = any((x.quantity_done > 0 and x.state not in ['done', 'cancel']) for x in order.move_raw_ids) or \ + any((x.quantity_done > 0 and x.state not in ['done' 'cancel']) for x in order.move_finished_ids) + else: + order.post_visible = any((x.quantity_done > 0 and x.state not in ['done' 'cancel']) for x in order.move_finished_ids) @api.multi @api.depends('workorder_ids.state', 'move_finished_ids') diff --git a/addons/sale/tests/test_sale_order.py b/addons/sale/tests/test_sale_order.py index 4022c85c179..248cb435ff2 100644 --- a/addons/sale/tests/test_sale_order.py +++ b/addons/sale/tests/test_sale_order.py @@ -104,6 +104,9 @@ class TestSaleOrder(TestSale): def test_cost_invoicing(self): """ Test confirming a vendor invoice to reinvoice cost on the so """ + # force the pricelist to have the same currency as the company + self.env.ref('product.list0').currency_id = self.env.ref('base.main_company').currency_id + serv_cost = self.env.ref('product.service_cost_01') prod_gap = self.env.ref('product.product_product_1') so = self.env['sale.order'].create({ diff --git a/addons/sale_expense/tests/test_sale_expense.py b/addons/sale_expense/tests/test_sale_expense.py index 2dd9dba7726..9b3fa6cd79a 100644 --- a/addons/sale_expense/tests/test_sale_expense.py +++ b/addons/sale_expense/tests/test_sale_expense.py @@ -7,6 +7,9 @@ from odoo.addons.sale.tests.test_sale_common import TestSale class TestSaleExpense(TestSale): def test_sale_expense(self): """ Test the behaviour of sales orders when managing expenses """ + # force the pricelist to have the same currency as the company + self.env.ref('product.list0').currency_id = self.env.ref('base.main_company').currency_id + # create a so with a product invoiced on delivery prod = self.env.ref('product.product_product_1') so = self.env['sale.order'].create({ diff --git a/addons/stock/i18n/stock.pot b/addons/stock/i18n/stock.pot index 1296f083384..8e86883b4aa 100644 --- a/addons/stock/i18n/stock.pot +++ b/addons/stock/i18n/stock.pot @@ -6384,6 +6384,12 @@ msgid "You cannot set a negative product quantity in an inventory line:\n" msgstr "" #. module: stock +#: code:addons/stock/models/stock_production_lot.py:37 +#, python-format +msgid "You are not allowed to create a lot for this picking type" +msgstr "" + +#. module: stock #: code:addons/stock/models/stock_move.py:927 #, python-format msgid "You cannot split a draft move. It needs to be confirmed first." diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index 54b4a877fd7..6e26cf6dc77 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -419,6 +419,9 @@ class ProductTemplate(models.Model): relation="stock.location.route", string="Category Routes", related='categ_id.total_route_ids') + def _is_cost_method_standard(self): + return True + def _compute_quantities(self): res = self._compute_quantities_dict() for template in self: diff --git a/addons/stock/models/stock_production_lot.py b/addons/stock/models/stock_production_lot.py index 60f370fff51..a568cd80fe3 100644 --- a/addons/stock/models/stock_production_lot.py +++ b/addons/stock/models/stock_production_lot.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models, _ +from odoo.exceptions import UserError class ProductionLot(models.Model): @@ -27,6 +28,15 @@ class ProductionLot(models.Model): ('name_ref_uniq', 'unique (name, product_id)', 'The combination of serial number and product must be unique !'), ] + @api.model + def create(self, vals): + pack_id = self.env.context.get('active_pack_operation', False) + if pack_id: + pack = self.env['stock.pack.operation'].browse(pack_id) + if pack.picking_id and not pack.picking_id.picking_type_id.use_create_lots: + raise UserError(_("You are not allowed to create a lot for this picking type")) + return super(ProductionLot, self).create(vals) + @api.one @api.depends('quant_ids.qty') def _product_qty(self): diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py index 20de2d25775..8453a49b4e3 100644 --- a/addons/stock/models/stock_scrap.py +++ b/addons/stock/models/stock_scrap.py @@ -66,6 +66,12 @@ class StockScrap(models.Model): scrap.do_scrap() return scrap + @api.multi + def unlink(self): + if 'done' in self.mapped('state'): + raise UserError(_('You cannot delete a scrap which is done.')) + return super(StockScrap, self).unlink() + def _get_origin_moves(self): return self.picking_id and self.picking_id.move_lines.filtered(lambda x: x.product_id == self.product_id) diff --git a/addons/stock/security/ir.model.access.csv b/addons/stock/security/ir.model.access.csv index dc8f1756134..6b13597199d 100644 --- a/addons/stock/security/ir.model.access.csv +++ b/addons/stock/security/ir.model.access.csv @@ -78,4 +78,8 @@ access_barcode_rule_stock_manager,barcode.rule.stock.manager,barcodes.model_barc access_stock_forecast_user,report.stock.forecast.user,model_report_stock_forecast,stock.group_stock_user,1,0,0,0 access_stock_forecast_manager,report.stock.forecast.manager,model_report_stock_forecast,stock.group_stock_manager,1,1,1,1 access_stock_scrap_user,stock.scrap.user,model_stock_scrap,stock.group_stock_user,1,1,1,0 -access_procurement_order,procurement.order,stock.model_procurement_order,base.group_portal,1,0,0,0
\ No newline at end of file +access_procurement_order,procurement.order,stock.model_procurement_order,base.group_portal,1,0,0,0 +access_product_attribute_manager,product.attribute manager,product.model_product_attribute,stock.group_stock_manager,1,1,1,1 +access_product_attribute_value_manager,product.attribute manager value,product.model_product_attribute_value,stock.group_stock_manager,1,1,1,1 +access_product_attribute_price_manager,product.attribute manager price,product.model_product_attribute_price,stock.group_stock_manager,1,1,1,1 +access_product_attribute_line_manager,product.attribute manager line,product.model_product_attribute_line,stock.group_stock_manager,1,1,1,1
\ No newline at end of file diff --git a/addons/stock/views/stock_pack_operation_views.xml b/addons/stock/views/stock_pack_operation_views.xml index 5b6919dab83..cd8469d4672 100644 --- a/addons/stock/views/stock_pack_operation_views.xml +++ b/addons/stock/views/stock_pack_operation_views.xml @@ -85,7 +85,7 @@ <field name="lot_name" invisible="not context.get('only_create', False)"/> <field name="lot_id" invisible="context.get('only_create', False)" domain="[('product_id','=', parent.product_id)]" - context="{'default_product_id': parent.product_id}"/> + context="{'default_product_id': parent.product_id, 'active_pack_operation': parent.id}"/> <field name="qty_todo" invisible="not context.get('show_reserved') or context.get('serial') or context.get('state_done')" readonly="1"/> <field name="qty" invisible="context.get('serial')"/> <button name="do_minus" type="object" icon="fa-minus-square" attrs="{'invisible': [('qty', '<=', 0.99)]}" invisible="not context.get('show_reserved') or context.get('state_done')"/> diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py index 1e4ac7ffbe1..1b15d2aa066 100644 --- a/addons/stock_account/models/product.py +++ b/addons/stock_account/models/product.py @@ -51,6 +51,9 @@ class ProductTemplate(models.Model): def _compute_cost_method(self): self.cost_method = self.property_cost_method or self.categ_id.property_cost_method + def _is_cost_method_standard(self): + return self.property_cost_method == 'standard' + @api.one def _set_cost_method(self): return self.write({'property_cost_method': self.cost_method}) diff --git a/addons/stock_landed_costs/tests/common.py b/addons/stock_landed_costs/tests/common.py index cdd99228dab..205d2171853 100644 --- a/addons/stock_landed_costs/tests/common.py +++ b/addons/stock_landed_costs/tests/common.py @@ -59,6 +59,9 @@ class TestStockLandedCostsCommon(AccountingTestCase): self.brokerage_quantity = self._create_services('Brokerage Cost') self.transportation_weight = self._create_services('Transportation Cost') self.packaging_volume = self._create_services('Packaging Cost') + # Ensure the account properties exists. + self.ensure_account_property('property_stock_account_input') + self.ensure_account_property('property_stock_account_output') def _create_services(self, name): return self.Product.create({ diff --git a/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js b/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js index 807bdff70dd..8f0724bbb00 100644 --- a/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js +++ b/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js @@ -421,6 +421,12 @@ element.children().first().after(widget); } + // !! ODOO FIX START !! + var parentOffset = parent.offset(); + position.top = offset.top - parentOffset.top; + position.left = offset.left - parentOffset.left; + // !! ODOO FIX END !! + // Top and bottom logic if (vertical === 'auto') { if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() && diff --git a/addons/web/static/src/js/widgets/date_picker.js b/addons/web/static/src/js/widgets/date_picker.js index 353a5dc78f2..76281d9366a 100644 --- a/addons/web/static/src/js/widgets/date_picker.js +++ b/addons/web/static/src/js/widgets/date_picker.js @@ -42,6 +42,7 @@ var DateWidget = Widget.extend({ locale : moment.locale(), allowInputToggle: true, keyBinds: null, + widgetParent: 'body', }); }, /** diff --git a/addons/web/static/src/less/webclient.less b/addons/web/static/src/less/webclient.less index 2f9878fbdc3..5e84d74b599 100644 --- a/addons/web/static/src/less/webclient.less +++ b/addons/web/static/src/less/webclient.less @@ -12,6 +12,7 @@ a { // General // ------------------------------------------------------------------ .o_web_client { + position: relative; // normally useless but required by bootstrap-datepicker background-color: @odoo-webclient-background-color; } .o_text_overflow { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index c4a3cc3939f..dbd52954367 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -24,7 +24,7 @@ <div t-name="CrashManager.warning" class="o_dialog_warning"> <t t-js="d"> - var message = d.message ? d.message : d.error.data.message; + var message = (d.message !== undefined) ? d.message : d.error.data.message; d.html_error = context.engine.tools.html_escape(message).replace(/\n/g, '<br/>'); </t> <t t-raw="html_error"/> diff --git a/addons/website/models/website.py b/addons/website/models/website.py index bd7621c767d..f6fe1bc9c77 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -397,9 +397,10 @@ class Website(models.Model): @api.model def get_current_website(self): - domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0] + domain_name = request and request.httprequest.environ.get('HTTP_HOST', '').split(':')[0] or None website_id = self._get_current_website_id(domain_name) - request.context = dict(request.context, website_id=website_id) + if request: + request.context = dict(request.context, website_id=website_id) return self.browse(website_id) @tools.cache('domain_name') diff --git a/addons/website_crm_partner_assign/models/crm_lead.py b/addons/website_crm_partner_assign/models/crm_lead.py index 99a39ac9c91..424919b05ab 100644 --- a/addons/website_crm_partner_assign/models/crm_lead.py +++ b/addons/website_crm_partner_assign/models/crm_lead.py @@ -47,8 +47,6 @@ class CrmLead(models.Model): for salesman_id, leads_ids in salesmans_leads.items(): leads = self.browse(leads_ids) leads.write({'user_id': salesman_id}) - for lead in leads: - lead._onchange_user_id() @api.multi def action_assign_partner(self): diff --git a/addons/website_event_sale/static/src/js/website.tour.event_sale.js b/addons/website_event_sale/static/src/js/website.tour.event_sale.js index f6638573256..b099ebd6ebe 100644 --- a/addons/website_event_sale/static/src/js/website.tour.event_sale.js +++ b/addons/website_event_sale/static/src/js/website.tour.event_sale.js @@ -75,7 +75,7 @@ tour.register('event_buy_tickets', { trigger: 'a[href="/shop/confirm_order"]:contains("Confirm")', }, { - content: "Check that the subtotal is 5,500.00", + content: "Check that the subtotal is 5,500.00 USD", // this test will fail if the currency of the main company is not USD trigger: '#order_total_untaxed .oe_currency_value:contains("5,500.00")', run: function () {}, // it's a check }, diff --git a/addons/website_forum/i18n/website_forum.pot b/addons/website_forum/i18n/website_forum.pot index 5fddf1e74a5..2f70c77241b 100644 --- a/addons/website_forum/i18n/website_forum.pot +++ b/addons/website_forum/i18n/website_forum.pot @@ -604,6 +604,7 @@ msgid "Bad Request" msgstr "" #. module: website_forum +#: model:ir.model.fields,field_description:website_forum.field_res_users_badge_ids #: model:ir.ui.view,arch_db:website_forum.badge #: model:ir.ui.view,arch_db:website_forum.header #: model:ir.ui.view,arch_db:website_forum.user_detail_full @@ -782,6 +783,7 @@ msgstr "" #. openerp-web #: code:addons/website_forum/static/src/xml/website_forum_share_templates.xml:46 #: selection:forum.post,state:0 +#: model:ir.ui.view,arch_db:website_forum.post_description_full #, python-format msgid "Close" msgstr "" @@ -884,6 +886,16 @@ msgid "Convert all answers to comments and vice versa" msgstr "" #. module: website_forum +#: model:ir.ui.view,arch_db:website_forum.post_answers +msgid "Convert as a comment" +msgstr "" + +#. module: website_forum +#: model:ir.ui.view,arch_db:website_forum.post_comment +msgid "Convert as an answer" +msgstr "" + +#. module: website_forum #: model:ir.model.fields,field_description:website_forum.field_forum_post_karma_accept msgid "Convert comment to answer" msgstr "" @@ -969,6 +981,12 @@ msgid "Default Post" msgstr "" #. module: website_forum +#: model:ir.ui.view,arch_db:website_forum.post_answers +#: model:ir.ui.view,arch_db:website_forum.post_description_full +msgid "Delete" +msgstr "" + +#. module: website_forum #: model:ir.model.fields,field_description:website_forum.field_forum_forum_karma_unlink_all msgid "Delete all posts" msgstr "" @@ -1038,6 +1056,8 @@ msgstr "" #. module: website_forum #: model:ir.ui.view,arch_db:website_forum.edit_post +#: model:ir.ui.view,arch_db:website_forum.post_answers +#: model:ir.ui.view,arch_db:website_forum.post_description_full msgid "Edit" msgstr "" @@ -1185,6 +1205,11 @@ msgid "First upvote" msgstr "" #. module: website_forum +#: model:ir.ui.view,arch_db:website_forum.post_description_full +msgid "Flag" +msgstr "" + +#. module: website_forum #: model:ir.model.fields,field_description:website_forum.field_forum_forum_karma_flag #: model:ir.model.fields,field_description:website_forum.field_forum_post_karma_flag msgid "Flag a post as offensive" @@ -1193,6 +1218,7 @@ msgstr "" #. module: website_forum #: selection:forum.post,state:0 #: model:ir.ui.view,arch_db:website_forum.moderation_queue +#: model:ir.ui.view,arch_db:website_forum.post_description_full msgid "Flagged" msgstr "" @@ -2016,6 +2042,11 @@ msgid "Re: %s" msgstr "" #. module: website_forum +#: model:ir.ui.view,arch_db:website_forum.post_description_full +msgid "Reactivate" +msgstr "" + +#. module: website_forum #: model:ir.ui.view,arch_db:website_forum.header msgid "Read Guidelines" msgstr "" @@ -2068,6 +2099,11 @@ msgid "Relevance Computation" msgstr "" #. module: website_forum +#: model:ir.ui.view,arch_db:website_forum.post_description_full +msgid "Reopen" +msgstr "" + +#. module: website_forum #: model:ir.ui.view,arch_db:website_forum.post_answers #: model:ir.ui.view,arch_db:website_forum.post_description_full msgid "Reply" diff --git a/addons/website_forum/static/src/xml/website_forum_share_templates.xml b/addons/website_forum/static/src/xml/website_forum_share_templates.xml index ab44aa48fcb..670e143ced8 100644 --- a/addons/website_forum/static/src/xml/website_forum_share_templates.xml +++ b/addons/website_forum/static/src/xml/website_forum_share_templates.xml @@ -33,7 +33,7 @@ <t t-name="website_forum.social_message_answer"> <p>By sharing you answer, you will get additional <b>karma points</b> if your answer is selected as the right one. See what you can do with karma - <a href="https://www.odoo.com/forum/how-to/miscellaneous-14/how-does-karma-work-odoo-v8-forum-software-57845" target="_blank">here</a>.</p> + <a href="/forum/help-1/faq" target="_blank">here</a>.</p> </t> <t t-name="website_forum.social_message_default"> <p>Share this content to increase your chances to be featured on the front page and attract more visitors.</p> diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index 74df06b10cb..3608b9b47c7 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -793,9 +793,10 @@ </div> </div> <div class="text-muted mb16"> - <i t-if="question.post_type == 'question'" t-attf-class="fa fa-question-circle" t-att-title="question.post_type.capitalize()" /> - <i t-if="question.post_type == 'discussion'" t-attf-class="fa fa-comments-o" t-att-title="question.post_type.capitalize()" /> - <i t-if="question.post_type == 'link'" t-attf-class="fa fa-link" t-att-title="question.post_type.capitalize()" /> + <t t-set="type_labels" t-value="dict(question._fields['post_type']._description_selection(question.env))"/> + <i t-if="question.post_type == 'question'" t-attf-class="fa fa-question-circle" t-att-title="type_labels[question.post_type]" /> + <i t-if="question.post_type == 'discussion'" t-attf-class="fa fa-comments-o" t-att-title="type_labels[question.post_type]" /> + <i t-if="question.post_type == 'link'" t-attf-class="fa fa-link" t-att-title="type_labels[question.post_type]" /> <span>By </span> <a t-att-href="(question.create_uid.id == request.session.uid or question.create_uid.sudo().website_published) and '/forum/%s/user/%s' % (slug(forum), question.create_uid.id) or None" t-field="question.create_uid" @@ -819,7 +820,7 @@ <div class="mt16 mb24 text-center"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) + '/question/' + slug(question) + '/reopen'"/> - <t t-set="label" t-value="'Reopen'"/> + <t t-set="label">Reopen</t> <t t-set="classes" t-value="'fa-arrow-right'"/> <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/> </t> @@ -832,7 +833,7 @@ <li t-if="question.state == 'close'"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/reopen'"/> - <t t-set="label" t-value="'Reopen'"/> + <t t-set="label">Reopen</t> <t t-set="classes" t-value="'fa-undo'"/> <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/> </t> @@ -840,7 +841,7 @@ <li> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/edit'"/> - <t t-set="label" t-value="'Edit'"/> + <t t-set="label">Edit</t> <t t-set="classes" t-value="'fa-pencil-square-o'"/> <t t-set="karma" t-value="not question.can_edit and question.karma_edit or 0"/> </t> @@ -848,7 +849,7 @@ <li t-if="question.state != 'close'"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/ask_for_close'"/> - <t t-set="label" t-value="'Close'"/> + <t t-set="label">Close</t> <t t-set="classes" t-value="'fa-times'"/> <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/> </t> @@ -856,7 +857,7 @@ <li t-if="question.active"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/delete'"/> - <t t-set="label" t-value="'Delete'"/> + <t t-set="label">Delete</t> <t t-set="classes" t-value="'fa-trash-o'"/> <t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/> </t> @@ -864,7 +865,7 @@ <li t-if="not question.active and question.state != 'offensive'"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/undelete'"/> - <t t-set="label" t-value="'Reactivate'"/> + <t t-set="label">Reactivate</t> <t t-set="classes" t-value="'fa-trash-o'"/> <t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/> </t> @@ -872,7 +873,7 @@ <li t-if="not question.active and question.state == 'offensive'"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/validate'"/> - <t t-set="label" t-value="'Reactivate'"/> + <t t-set="label">Reactivate</t> <t t-set="classes" t-value="'fa-trash-o'"/> <t t-set="karma" t-value="not question.can_moderate and question.forum_id.karma_moderate or 0"/> </t> @@ -883,7 +884,12 @@ t-attf-data-karma="#{not question.can_flag and question.forum_id.karma_flag or 0}" t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(question)}/flag" > - <t class="flag_flagged_label" t-esc="question.state == 'flagged' and 'Flagged' or 'Flag'"/> + <t t-if="question.state == 'flagged'"> + Flagged + </t> + <t t-if="question.state != 'flagged'"> + Flag + </t> </a> </li> </ul> @@ -982,7 +988,7 @@ <li> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/> - <t t-set="label" t-value="'Edit'"/> + <t t-set="label">Edit</t> <t t-set="classes" t-value="'fa fa-pencil-square-o'"/> <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/> </t> @@ -990,7 +996,7 @@ <li> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/> - <t t-set="label" t-value="'Delete'"/> + <t t-set="label">Delete</t> <t t-set="classes" t-value="'fa-trash-o'"/> <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/> </t> @@ -1007,7 +1013,7 @@ <li t-if="question.post_type == 'question'"> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/> - <t t-set="label" t-value="'Convert as a comment'"/> + <t t-set="label">Convert as a comment</t> <t t-set="classes" t-value="'fa-magic'"/> <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/> </t> @@ -1081,7 +1087,7 @@ <t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_unlink_own or object.forum_id.karma_comment_unlink_all"/> <t t-call="website_forum.link_button"> <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/delete'"/> - <t t-set="label" t-value="' '"/> + <t t-set="label"> </t> <t t-set="karma" t-value="user.karma<required_karma and required_karma or 0"/> <t t-set="classes" t-value="'close comment_delete fa-times'"/> </t> @@ -1094,7 +1100,7 @@ <t t-if="allow_post_comment"> <t t-call="website_forum.link_button" > <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/> - <t t-set="label" t-value="'Convert as an answer'"/> + <t t-set="label">Convert as an answer</t> <t t-set="karma" t-value="user.karma<required_karma and required_karma or 0"/> <t t-set="classes" t-value="'fa-magic pull-right'"/> </t> diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 7ccb2f531b1..c8a39dba78a 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -244,19 +244,19 @@ class Website(models.Model): :param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo) :returns: pricelist recordset """ - website = request.website - if not request.website: + website = request and request.website or None + if not website: if self.env.context.get('website_id'): website = self.browse(self.env.context['website_id']) else: website = self.search([], limit=1) - isocountry = request.session.geoip and request.session.geoip.get('country_code') or False + isocountry = request and request.session.geoip and request.session.geoip.get('country_code') or False partner = self.env.user.partner_id order_pl = partner.last_website_so_id and partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id partner_pl = partner.property_product_pricelist pricelists = website._get_pl_partner_order(isocountry, show_visible, website.user_id.sudo().partner_id.property_product_pricelist.id, - request.session.get('website_sale_current_pl'), + request and request.session.get('website_sale_current_pl') or None, website.pricelist_ids, partner_pl=partner_pl and partner_pl.id or None, order_pl=order_pl and order_pl.id or None) @@ -280,7 +280,7 @@ class Website(models.Model): available_pricelists = self.get_pricelist_available() pl = None partner = self.env.user.partner_id - if request.session.get('website_sale_current_pl'): + if request and request.session.get('website_sale_current_pl'): # `website_sale_current_pl` is set only if the user specifically chose it: # - Either, he chose it from the pricelist selection # - Either, he entered a coupon code |
