[MERGE] Forward port of saas-11.3 to 12.0 up to 06f8f04699

closes odoo/odoo#35064

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
This commit is contained in:
Martin Trigaux
2019-07-22 11:43:54 +00:00
15 changed files with 155 additions and 17 deletions
+11 -6
View File
@@ -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):
@@ -48,7 +48,7 @@
<div t-if="pms or acquirers" id="payment_method" class="text-left col-md-13">
<t t-call="payment.payment_tokens_list">
<t t-set="mode" t-value="'payment'"/>
<t t-set="partner_id" t-value="request.env.user.partner_id.id"/>
<t t-set="partner_id" t-value="invoice.partner_id.id if request.env.user._is_public() else request.env.user.partner_id.id"/>
<t t-set="success_url" t-value="invoice.get_portal_url()"/>
<t t-set="error_url" t-value="invoice.get_portal_url()"/>
<t t-set="access_token" t-value="access_token or ''"/>
+1
View File
@@ -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,
@@ -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");
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="delivery_assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/delivery/static/src/js/delivery_translations.js"></script>
</xpath>
</template>
</odoo>
@@ -206,7 +206,7 @@
<group>
<field name="date" string="Invoice Date"/>
<field name="start_date"/>
<field name="expiration_date" />
<field name="expiration_date" attrs="{'required': [('cost_frequency', '!=', 'no')]}"/>
</group>
<group>
<field name="insurer_id" context="{'default_supplier': True}"/>
@@ -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");
+7
View File
@@ -13,4 +13,11 @@
<script type="text/javascript" src="/payment/static/src/js/payment_processing.js"></script>
</xpath>
</template>
<template id="assets_backend" name="payment_assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/payment/static/src/js/payment_translations.js"></script>
</xpath>
</template>
</odoo>
+25 -5
View File
@@ -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()
@@ -9,6 +9,7 @@
<group attrs="{'invisible': [('provider', '!=', 'authorize')]}">
<field name="authorize_login"/>
<field name="authorize_transaction_key" password="True"/>
<field name="authorize_signature_key" password="True"/>
<a colspan="2" href="https://www.odoo.com/documentation/user/online/ecommerce/shopper_experience/authorize.html" target="_blank">How to get paid with Authorize.Net</a>
</group>
</xpath>
+17 -3
View File
@@ -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):
+1 -1
View File
@@ -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
@@ -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)
+1
View File
@@ -346,6 +346,7 @@
<template id="products_attributes" inherit_id="website_sale.products" active="False" customize_show="True" name="Product Attribute's Filters">
<xpath expr="//div[@id='products_grid_before']" position="inside">
<form class="js_attributes" method="get">
<input t-if="category" type="hidden" name="category" t-att-value="category.id" />
<input type="hidden" name="search" t-att-value="search" />
<ul class="nav nav-pills flex-column mt16">
<t t-foreach="attributes" t-as="a">
+5
View File
@@ -490,6 +490,11 @@ on the extended template to select *context nodes* to which the specified
the node's body replaces the context node's children
``replace``
the node's body is used to replace the context node itself
``attributes``
the nodes's body should be any number of ``attribute`` elements,
each with a ``name`` attribute and some textual content, the named
attribute of the context node will be set to the specified value
(either replaced if it already existed or added if not)
No operation
if no ``t-operation`` is specified, the template body is interpreted as
javascript code and executed with the context node as ``this``