diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index adca204ce3e..ebd507f1aae 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -560,20 +560,25 @@ class account_payment(models.Model): @api.multi def button_invoices(self): - if self.partner_type == 'supplier': - views = [(self.env.ref('account.invoice_supplier_tree').id, 'tree'), (self.env.ref('account.invoice_supplier_form').id, 'form')] - else: - views = [(self.env.ref('account.invoice_tree').id, 'tree'), (self.env.ref('account.invoice_form').id, 'form')] - return { + action = { 'name': _('Paid Invoices'), 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'account.invoice', 'view_id': False, - 'views': views, 'type': 'ir.actions.act_window', 'domain': [('id', 'in', [x.id for x in self.reconciled_invoice_ids])], } + if self.partner_type == 'supplier': + action['views'] = [(self.env.ref('account.invoice_supplier_tree').id, 'tree'), (self.env.ref('account.invoice_supplier_form').id, 'form')] + action['context'] = { + 'journal_type': 'purchase', + 'type': 'in_invoice', + 'default_type': 'in_invoice', + } + else: + action['views'] = [(self.env.ref('account.invoice_tree').id, 'tree'), (self.env.ref('account.invoice_form').id, 'form')] + return action @api.multi def button_dummy(self): diff --git a/addons/account_payment/views/account_portal_templates.xml b/addons/account_payment/views/account_portal_templates.xml index bdc9c9da488..4945eb9b5bc 100644 --- a/addons/account_payment/views/account_portal_templates.xml +++ b/addons/account_payment/views/account_portal_templates.xml @@ -48,7 +48,7 @@
- + diff --git a/addons/delivery/__manifest__.py b/addons/delivery/__manifest__.py index 17583ac4324..7c06e139b1d 100644 --- a/addons/delivery/__manifest__.py +++ b/addons/delivery/__manifest__.py @@ -27,6 +27,7 @@ invoices from picking, the system is able to add and compute the shipping line. 'views/report_package_barcode.xml', 'views/res_config_settings_views.xml', 'wizard/choose_delivery_package_views.xml', + 'views/assets.xml', ], 'demo': ['data/delivery_demo.xml'], 'installable': True, diff --git a/addons/delivery/static/src/js/delivery_translations.js b/addons/delivery/static/src/js/delivery_translations.js new file mode 100644 index 00000000000..565adbcb69f --- /dev/null +++ b/addons/delivery/static/src/js/delivery_translations.js @@ -0,0 +1,16 @@ +// TODO Remove me >=saas-12.5, this is a disgrace +// This is an hack to get the string_* and hover_* options translated on the +// boolean_button terminology widget. The terms are translated through +// _t(opt_terms.string_true) which will only work if the terms are already +// present in the translation map. +// This code does nothing but marks the strings as translatable +var _t = function(x) { return x; }; + +_t("Production Environment"); +_t("Switch to test environment"); +_t("Test Environment"); +_t("Switch to production environment"); +_t("Debug requests"); +_t("Disable debug"); +_t("No debug"); +_t("Enable debug"); diff --git a/addons/delivery/views/assets.xml b/addons/delivery/views/assets.xml new file mode 100644 index 00000000000..851aaca55c9 --- /dev/null +++ b/addons/delivery/views/assets.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/addons/fleet/views/fleet_vehicle_cost_views.xml b/addons/fleet/views/fleet_vehicle_cost_views.xml index a3df5e74e33..e7f30238762 100644 --- a/addons/fleet/views/fleet_vehicle_cost_views.xml +++ b/addons/fleet/views/fleet_vehicle_cost_views.xml @@ -206,7 +206,7 @@ - + diff --git a/addons/payment/static/src/js/payment_translations.js b/addons/payment/static/src/js/payment_translations.js new file mode 100644 index 00000000000..199dcc2a276 --- /dev/null +++ b/addons/payment/static/src/js/payment_translations.js @@ -0,0 +1,10 @@ +// TODO Remove me >=saas-12.5, this is a disgrace +// This is an hack to get the string_true and hover_false options translated on +// the boolean_button terminology widget. The terms are translated through +// _t(opt_terms.string_true) which will only work if the terms are already +// present in the translation map. +// This code does nothing but marks the strings as translatable +var _t = function(x) { return x; }; + +_t("Published"); +_t("Publish"); diff --git a/addons/payment/views/assets.xml b/addons/payment/views/assets.xml index 62fe9d2455f..49cc88c5536 100644 --- a/addons/payment/views/assets.xml +++ b/addons/payment/views/assets.xml @@ -13,4 +13,11 @@ + + + diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py index 6361a211f16..b1d9a2e6a1e 100644 --- a/addons/payment_authorize/models/payment.py +++ b/addons/payment_authorize/models/payment.py @@ -25,6 +25,7 @@ class PaymentAcquirerAuthorize(models.Model): provider = fields.Selection(selection_add=[('authorize', 'Authorize.Net')]) authorize_login = fields.Char(string='API Login Id', required_if_provider='authorize', groups='base.group_user') authorize_transaction_key = fields.Char(string='API Transaction Key', required_if_provider='authorize', groups='base.group_user') + authorize_signature_key = fields.Char(string='API Signature Key', groups='base.group_user', compute="_compute_auth_signature_key", inverse="_inverse_auth_signature_key") def _get_feature_support(self): """Get advanced feature support by provider. @@ -42,6 +43,16 @@ class PaymentAcquirerAuthorize(models.Model): res['tokenize'].append('authorize') return res + def _compute_auth_signature_key(self): + ICP = self.env['ir.config_parameter'].sudo() + for acquirer in self.filtered(lambda a: a.provider == 'authorize'): + acquirer.authorize_signature_key = ICP.get_param('payment_authorize.signature_key_%s' % acquirer.id) + + def _inverse_auth_signature_key(self): + ICP = self.env['ir.config_parameter'].sudo() + for acquirer in self.filtered(lambda a: a.provider == 'authorize'): + ICP.set_param('payment_authorize.signature_key_%s' % acquirer.id, acquirer.authorize_signature_key) + def _get_authorize_urls(self, environment): """ Authorize URLs """ if environment == 'prod': @@ -57,13 +68,22 @@ class PaymentAcquirerAuthorize(models.Model): values['x_amount'], values['x_currency_code']]).encode('utf-8') - # [BACKWARD COMPATIBILITY] Check that the merchant did update his transaction - # key to signature key (end of MD5 support from Authorize.net) + # [BACKWARD COMPATIBILITY, 2nd edition] # The signature key is now '128-character hexadecimal format', while the # transaction key was only 16-character. - if len(values['x_trans_key']) == 128: - key = bytes.fromhex(values['x_trans_key']) - return hmac.new(key, data, hashlib.sha512).hexdigest().upper() + # One of 2 things should have happened: + # 1/ the Transaction Key has been replaced with the Signature Key value (patch from March 2019) + # => Use that to sign, but server-to-server won't work since it uses transaction key + # as its credentials + # 2/ the Signature key is a new field (patch from July 2019) + # => Use that field for the signature + + # FORWARD-PORT NOTE: forward part to saas-12.4 but no further + if len(values['x_trans_key']) == 128 and not self.authorize_signature_key: + self.authorize_signature_key = values['x_trans_key'] # store in the correct field + return hmac.new(bytes.fromhex(values['x_trans_key']), data, hashlib.sha512).hexdigest().upper() + elif self.authorize_signature_key: + return hmac.new(bytes.fromhex(self.authorize_signature_key), data, hashlib.sha512).hexdigest().upper() else: return hmac.new(values['x_trans_key'].encode('utf-8'), data, hashlib.md5).hexdigest() diff --git a/addons/payment_authorize/views/payment_views.xml b/addons/payment_authorize/views/payment_views.xml index 0237325e0c2..b60385ed9f0 100644 --- a/addons/payment_authorize/views/payment_views.xml +++ b/addons/payment_authorize/views/payment_views.xml @@ -9,6 +9,7 @@ + How to get paid with Authorize.Net diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index dd0269d81ff..bbb6f301834 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -162,9 +162,23 @@ class Product(models.Model): company_id = self.env.user.company_id.id return ( [('location_id.company_id', '=', company_id), ('location_id.usage', 'in', ['internal', 'transit'])], - [('location_id.company_id', '=', False), ('location_dest_id.company_id', '=', company_id)], - [('location_id.company_id', '=', company_id), ('location_dest_id.company_id', '=', False), - ]) + ['&', + ('location_dest_id.company_id', '=', company_id), + '|', + ('location_id.company_id', '=', False), + '&', + ('location_id.usage', 'in', ['inventory', 'production']), + ('location_id.company_id', '=', company_id), + ], + ['&', + ('location_id.company_id', '=', company_id), + '|', + ('location_dest_id.company_id', '=', False), + '&', + ('location_dest_id.usage', 'in', ['inventory', 'production']), + ('location_dest_id.company_id', '=', company_id), + ] + ) location_ids = [] if self.env.context.get('location', False): if isinstance(self.env.context['location'], pycompat.integer_types): diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py index 889fa9d7863..c744638bcff 100644 --- a/addons/stock_account/models/stock.py +++ b/addons/stock_account/models/stock.py @@ -201,7 +201,7 @@ class StockMove(models.Model): '|', ('location_dest_id.company_id', '=', False), '&', - ('location_dest_id.usage', '=', 'inventory'), + ('location_dest_id.usage', 'in', ['inventory', 'production']), ('location_dest_id.company_id', '=', company_id or self.env.user.company_id.id), ] return domain diff --git a/addons/stock_account/tests/test_stockvaluation.py b/addons/stock_account/tests/test_stockvaluation.py index 5efd5ca5bbc..d7097fe10d7 100644 --- a/addons/stock_account/tests/test_stockvaluation.py +++ b/addons/stock_account/tests/test_stockvaluation.py @@ -3944,3 +3944,51 @@ class TestStockValuation(TransactionCase): self.assertAlmostEqual(move1.remaining_qty, 0.0) self.assertAlmostEqual(self.product1.stock_value, 0.0) + + def test_at_date_average_1(self): + """ Set a company on the inventory loss, take items from there then put items there, check + the values and quantities at date. + """ + now = Datetime.from_string(Date.today()) + date1 = now - timedelta(days=8) + date2 = now - timedelta(days=7) + + self.product1.standard_price = 10 + self.env['product.price.history'].search([ + ('product_id', '=', self.product1.id) + ], order='datetime desc, id DESC', limit=1).datetime = date1 + self.product1.product_tmpl_id.cost_method = 'average' + self.inventory_location.company_id = self.env.user.company_id.id + + move1 = self.env['stock.move'].create({ + 'name': 'Adjustment of 10 units', + 'location_id': self.inventory_location.id, + 'location_dest_id': self.stock_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 10.0, + }) + move1._action_confirm() + move1._action_assign() + move1.move_line_ids.qty_done = 10.0 + move1._action_done() + move1.date = date1 + + move2 = self.env['stock.move'].create({ + 'name': 'Sell 5 units', + 'location_id': self.stock_location.id, + 'location_dest_id': self.inventory_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 5.0, + }) + move2._action_confirm() + move2._action_assign() + move2.move_line_ids.qty_done = 5.0 + move2._action_done() + move2.date = date2 + + self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 5) + self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 50) diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 47dd679ba31..306186b841f 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -346,6 +346,7 @@