diff options
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/crm/models/crm_team.py | 13 | ||||
| -rw-r--r-- | addons/fleet/models/fleet_vehicle_cost.py | 2 | ||||
| -rw-r--r-- | addons/l10n_tr/__manifest__.py | 5 | ||||
| -rw-r--r-- | addons/l10n_tr/data/res.country.state.csv | 82 | ||||
| -rw-r--r-- | addons/mass_mailing/models/mass_mailing.py | 31 | ||||
| -rw-r--r-- | addons/mrp/models/mrp_workorder.py | 2 | ||||
| -rw-r--r-- | addons/payment_adyen/models/payment.py | 40 | ||||
| -rw-r--r-- | addons/payment_stripe/static/src/js/stripe.js | 6 | ||||
| -rw-r--r-- | addons/payment_stripe/views/payment_stripe_templates.xml | 7 | ||||
| -rw-r--r-- | addons/stock/models/stock_move.py | 2 | ||||
| -rw-r--r-- | addons/stock/views/stock_picking_views.xml | 2 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_mail_gateway.py | 8 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_mail_message.py | 20 | ||||
| -rw-r--r-- | addons/web_editor/static/src/js/editor/snippets.editor.js | 14 | ||||
| -rw-r--r-- | addons/website_quote/models/sale_order.py | 2 | ||||
| -rw-r--r-- | addons/website_quote/views/website_quote_templates.xml | 2 |
16 files changed, 198 insertions, 40 deletions
diff --git a/addons/crm/models/crm_team.py b/addons/crm/models/crm_team.py index f24f253d230..107c2676aea 100644 --- a/addons/crm/models/crm_team.py +++ b/addons/crm/models/crm_team.py @@ -50,13 +50,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', 'probability', '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'] * datum['probability'] / 100) for datum in opportunity_data} + ]).read(['planned_revenue', 'probability', '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) * datum.get('probability', 0) / 100.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 b8b3602f851..d42d0b94c72 100644 --- a/addons/fleet/models/fleet_vehicle_cost.py +++ b/addons/fleet/models/fleet_vehicle_cost.py @@ -270,7 +270,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/l10n_tr/__manifest__.py b/addons/l10n_tr/__manifest__.py index 6cd7f6b7d96..d02f945b72f 100644 --- a/addons/l10n_tr/__manifest__.py +++ b/addons/l10n_tr/__manifest__.py @@ -13,9 +13,9 @@ 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', + 'author': 'Ahmet Altınışık, Can Tecim', 'maintainer':'https://launchpad.net/~openerp-turkey', - 'website':'https://launchpad.net/openerp-turkey', + 'website':'https://launchpad.net/openerp-turkey, http://www.cantecim.com', 'depends': [ 'account', ], @@ -24,5 +24,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/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 87fdba30447..d40c1842db0 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -668,15 +668,28 @@ class MassMailing(models.Model): """Returns a set of emails already targeted by current mailing/campaign (no duplicates)""" self.ensure_one() target = self.env[self.mailing_model_real] - mail_field = 'email' if 'email' in target._fields else 'email_from' - # avoid loading a large number of records in memory - # + use a basic heuristic for extracting emails - query = """ - SELECT lower(substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)')) - FROM mail_mail_statistics s - JOIN %(target)s t ON (s.res_id = t.id) - WHERE substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL - """ + if set(['email', 'email_from']) & set(target._fields): + mail_field = 'email' if 'email' in target._fields else 'email_from' + # avoid loading a large number of records in memory + # + use a basic heuristic for extracting emails + query = """ + SELECT lower(substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)')) + FROM mail_mail_statistics s + JOIN %(target)s t ON (s.res_id = t.id) + WHERE substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL + """ + elif 'partner_id' in target._fields: + mail_field = 'email' + query = """ + SELECT lower(substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)')) + FROM mail_mail_statistics s + JOIN %(target)s t ON (s.res_id = t.id) + JOIN res_partner p ON (t.partner_id = p.id) + WHERE substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL + """ + else: + raise UserError(_("Unsupported mass mailing model %s") % self.mailing_model_id.name) + if self.mass_mailing_campaign_id.unique_ab_testing: query +=""" AND s.mass_mailing_campaign_id = %%(mailing_campaign_id)s; diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 3459fbfced3..9935b063366 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -246,7 +246,7 @@ class MrpWorkorder(models.Model): @api.multi def write(self, values): - if ('date_planned_start' in values or 'date_planned_finished' in values) and any(workorder.state == 'done' for workorder in self): + if list(values.keys()) != ['time_ids'] and any(workorder.state == 'done' for workorder in self): raise UserError(_('You can not change the finished work order.')) return super(MrpWorkorder, self).write(values) diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index c28093f826f..03787a73233 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_native _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_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 2fc054f97ae..059bf6fede4 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/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 80b23f8635e..bd72567d2e8 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -147,7 +147,7 @@ class StockMove(models.Model): restrict_partner_id = fields.Many2one('res.partner', 'Owner ', help="Technical field used to depict a restriction on the ownership of quants to consider when marking this move as 'done'") route_ids = fields.Many2many('stock.location.route', 'stock_location_route_move', 'move_id', 'route_id', 'Destination route', help="Preferred route") warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse', help="Technical field depicting the warehouse to consider for the route selection on the next procurement (if any).") - has_tracking = fields.Selection(related='product_id.tracking', string='Product with Tracking') + has_tracking = fields.Selection(related='product_id.tracking', string='Product with Tracking', readonly=True) quantity_done = fields.Float('Quantity Done', compute='_quantity_done_compute', digits=dp.get_precision('Product Unit of Measure'), inverse='_quantity_done_set') show_operations = fields.Boolean(related='picking_id.picking_type_id.show_operations') show_details_visible = fields.Boolean('Details Visible', compute='_compute_show_details_visible') diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 640c95d3580..211d2afba95 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -353,7 +353,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/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index 327a0c7f007..b659bda25fb 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -499,7 +499,7 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.assertEqual(msg.model, False, 'message_post: private discussion: context key "thread_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( @@ -527,9 +527,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 5d747e0a207..79454dc65e4 100644 --- a/addons/test_mail/tests/test_mail_message.py +++ b/addons/test_mail/tests/test_mail_message.py @@ -28,7 +28,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') @@ -36,7 +36,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)) @@ -47,7 +47,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)) @@ -58,7 +58,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') self.assertEqual(msg.reply_to, '%s <%s@%s>' % (self.env.user.company_id.name, alias_catchall, alias_domain)) self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) @@ -69,7 +69,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)) @@ -83,7 +83,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 <%s@%s>' % (self.env.user.company_id.name, self.alias_record.name, self.alias_record.alias_name, alias_domain)) self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) @@ -97,7 +97,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 <%s@%s>' % (self.env.user.company_id.name, self.alias_record.name, self.alias_record.alias_name, alias_domain)) self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) @@ -107,9 +107,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_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index e731ec0fd99..9a486d958c0 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -374,6 +374,7 @@ var SnippetEditor = Widget.extend({ */ _onDragAndDropStart: function () { var self = this; + this.dropped = false; self.size = { width: self.$target.width(), height: self.$target.height() @@ -419,10 +420,21 @@ var SnippetEditor = Widget.extend({ * 'move' button. * * @private + * @param {Event} ev + * @param {Object} ui */ - _onDragAndDropStop: function () { + _onDragAndDropStop: function (ev, ui) { var self = this; + // 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; + } + } + $('.oe_drop_zone').droppable('destroy').remove(); var prev = this.$target.first()[0].previousSibling; diff --git a/addons/website_quote/models/sale_order.py b/addons/website_quote/models/sale_order.py index 294cce55d26..40add3901c7 100644 --- a/addons/website_quote/models/sale_order.py +++ b/addons/website_quote/models/sale_order.py @@ -272,7 +272,7 @@ class SaleOrderOption(models.Model): order_line = order.order_line.filtered(lambda line: line.product_id == self.product_id) if order_line: order_line = order_line[0] - order_line.product_uom_qty += 1 + order_line.product_uom_qty += self.quantity else: vals = { 'price_unit': self.price_unit, diff --git a/addons/website_quote/views/website_quote_templates.xml b/addons/website_quote/views/website_quote_templates.xml index b649f501370..f2724642d13 100644 --- a/addons/website_quote/views/website_quote_templates.xml +++ b/addons/website_quote/views/website_quote_templates.xml @@ -243,7 +243,7 @@ </div> - <div class="text-center mb16" t-if="quotation.amount_undiscounted > quotation.amount_untaxed"> + <div class="text-center mb16" t-if="quotation.amount_undiscounted - quotation.amount_untaxed > 0.01"> <p class="text-muted mb8">Your advantage:</p> <t t-if="quotation.amount_untaxed == quotation.amount_total"> <strong t-field="quotation.amount_total" |
