summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-01-11 18:56:24 +0100
committerChristophe Simonis <chs@odoo.com>2019-01-11 18:56:24 +0100
commit6a0675d36dd888daa4183f3d609ce334ed3cb493 (patch)
tree398886eba7df477300b1f433f295caa8c18d8ff1
parent57ccf70a32f677a9076ec2973100c1025f412d85 (diff)
parente033114879cfe4a487549c0abbe37ec18bc151c9 (diff)
[MERGE] forward port branch saas-11.3 up to e033114879c
-rw-r--r--addons/account/models/account_invoice.py4
-rw-r--r--addons/account/tests/test_account_customer_invoice.py63
-rw-r--r--addons/payment_authorize/models/authorize_request.py2
-rw-r--r--addons/point_of_sale/models/pos_order.py15
-rw-r--r--addons/point_of_sale/static/src/js/screens.js5
-rw-r--r--addons/sale_timesheet/static/src/js/timesheet_plan.js8
-rw-r--r--addons/sale_timesheet/static/tests/timesheet_plan_tests.js4
-rw-r--r--addons/stock/models/stock_picking.py4
-rw-r--r--addons/stock/views/stock_picking_views.xml3
-rw-r--r--addons/web_editor/static/src/js/widgets/widgets.js1
-rw-r--r--addons/website_sale/static/src/scss/website_sale.scss2
-rw-r--r--odoo/addons/base/models/res_users.py22
12 files changed, 111 insertions, 22 deletions
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 69a7443f3da..0f8d901c4f4 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -992,6 +992,7 @@ class AccountInvoice(models.Model):
@api.multi
def get_taxes_values(self):
tax_grouped = {}
+ round_curr = self.currency_id.round
for line in self.invoice_line_ids:
if not line.account_id:
continue
@@ -1003,9 +1004,10 @@ class AccountInvoice(models.Model):
if key not in tax_grouped:
tax_grouped[key] = val
+ tax_grouped[key]['base'] = round_curr(val['base'])
else:
tax_grouped[key]['amount'] += val['amount']
- tax_grouped[key]['base'] += val['base']
+ tax_grouped[key]['base'] += round_curr(val['base'])
return tax_grouped
@api.multi
diff --git a/addons/account/tests/test_account_customer_invoice.py b/addons/account/tests/test_account_customer_invoice.py
index a6b3459c9b9..83822ef8ffb 100644
--- a/addons/account/tests/test_account_customer_invoice.py
+++ b/addons/account/tests/test_account_customer_invoice.py
@@ -103,3 +103,66 @@ class TestAccountCustomerInvoice(AccountTestUsers):
# I clicked on Add Credit Note button.
self.account_invoice_refund_0.invoice_refund()
+
+ def test_customer_invoice_tax(self):
+
+ self.env.user.company_id.tax_calculation_rounding_method = 'round_globally'
+
+ payment_term = self.env.ref('account.account_payment_term_advance')
+ journalrec = self.env['account.journal'].search([('type', '=', 'sale')])[0]
+ partner3 = self.env.ref('base.res_partner_3')
+ account_id = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1).id
+
+ tax = self.env['account.tax'].create({
+ 'name': 'Tax 15.0',
+ 'amount': 15.0,
+ 'amount_type': 'percent',
+ 'type_tax_use': 'sale',
+ })
+
+ invoice_line_data = [
+ (0, 0,
+ {
+ 'product_id': self.env.ref('product.product_product_1').id,
+ 'quantity': 40.0,
+ 'account_id': account_id,
+ 'name': 'product test 1',
+ 'discount' : 10.00,
+ 'price_unit': 2.27,
+ 'invoice_line_tax_ids': [(6, 0, [tax.id])],
+ }
+ ),
+ (0, 0,
+ {
+ 'product_id': self.env.ref('product.product_product_2').id,
+ 'quantity': 21.0,
+ 'account_id': self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1).id,
+ 'name': 'product test 2',
+ 'discount' : 10.00,
+ 'price_unit': 2.77,
+ 'invoice_line_tax_ids': [(6, 0, [tax.id])],
+ }
+ ),
+ (0, 0,
+ {
+ 'product_id': self.env.ref('product.product_product_3').id,
+ 'quantity': 21.0,
+ 'account_id': self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1).id,
+ 'name': 'product test 3',
+ 'discount' : 10.00,
+ 'price_unit': 2.77,
+ 'invoice_line_tax_ids': [(6, 0, [tax.id])],
+ }
+ )
+ ]
+
+ invoice = self.env['account.invoice'].create(dict(
+ name="Test Customer Invoice",
+ reference_type="none",
+ payment_term_id=payment_term.id,
+ journal_id=journalrec.id,
+ partner_id=partner3.id,
+ invoice_line_ids=invoice_line_data
+ ))
+
+ self.assertEquals(invoice.amount_untaxed, sum([x.base for x in invoice.tax_line_ids]))
diff --git a/addons/payment_authorize/models/authorize_request.py b/addons/payment_authorize/models/authorize_request.py
index e4bd3382caa..bca2164dac1 100644
--- a/addons/payment_authorize/models/authorize_request.py
+++ b/addons/payment_authorize/models/authorize_request.py
@@ -149,7 +149,7 @@ class AuthorizeAPI():
root = self._base_tree('createCustomerProfileRequest')
profile = etree.SubElement(root, "profile")
etree.SubElement(profile, "merchantCustomerId").text = 'ODOO-%s-%s' % (partner.id, uuid4().hex[:8])
- etree.SubElement(profile, "email").text = partner.email
+ etree.SubElement(profile, "email").text = partner.email or ''
payment_profile = etree.SubElement(profile, "paymentProfiles")
etree.SubElement(payment_profile, "customerType").text = 'business' if partner.is_company else 'individual'
billTo = etree.SubElement(payment_profile, "billTo")
diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index 9321d224ea7..af93a311658 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -839,21 +839,18 @@ class PosOrder(models.Model):
lots_necessary = True
if picking_type:
lots_necessary = picking_type and picking_type.use_existing_lots
- qty = 0
qty_done = 0
pack_lots = []
pos_pack_lots = PosPackOperationLot.search([('order_id', '=', order.id), ('product_id', '=', move.product_id.id)])
- pack_lot_names = [pos_pack.lot_name for pos_pack in pos_pack_lots]
- if pack_lot_names and lots_necessary:
- for lot_name in list(set(pack_lot_names)):
- stock_production_lot = StockProductionLot.search([('name', '=', lot_name), ('product_id', '=', move.product_id.id)])
+ if pos_pack_lots and lots_necessary:
+ for pos_pack_lot in pos_pack_lots:
+ stock_production_lot = StockProductionLot.search([('name', '=', pos_pack_lot.lot_name), ('product_id', '=', move.product_id.id)])
if stock_production_lot:
+ # a serialnumber always has a quantity of 1 product, a lot number takes the full quantity of the order line
+ qty = 1.0
if stock_production_lot.product_id.tracking == 'lot':
- # if a lot nr is set through the frontend it will refer to the full quantity
- qty = move.product_uom_qty
- else: # serial numbers
- qty = 1.0
+ qty = pos_pack_lot.pos_order_line_id.qty
qty_done += qty
pack_lots.append({'lot_id': stock_production_lot.id, 'qty': qty})
else:
diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js
index 7b80a8c98fd..6939aff72f2 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -1970,16 +1970,11 @@ var PaymentScreenWidget = ScreenWidget.extend({
$('body').keypress(this.keyboard_handler);
// that one comes from the pos, but we prefer to cover all the basis
$('body').keydown(this.keyboard_keydown_handler);
- // legacy vanilla JS listeners
- window.document.body.addEventListener('keypress',this.keyboard_handler);
- window.document.body.addEventListener('keydown',this.keyboard_keydown_handler);
this._super();
},
hide: function(){
$('body').off('keypress', this.keyboard_handler);
$('body').off('keydown', this.keyboard_keydown_handler);
- window.document.body.removeEventListener('keypress',this.keyboard_handler);
- window.document.body.removeEventListener('keydown',this.keyboard_keydown_handler);
this._super();
},
// sets up listeners to watch for order changes
diff --git a/addons/sale_timesheet/static/src/js/timesheet_plan.js b/addons/sale_timesheet/static/src/js/timesheet_plan.js
index 90cbcd98379..e2c199ad545 100644
--- a/addons/sale_timesheet/static/src/js/timesheet_plan.js
+++ b/addons/sale_timesheet/static/src/js/timesheet_plan.js
@@ -107,7 +107,13 @@ var ProjectPlan = AbstractAction.extend(ControlPanelMixin, {
* @param {string|html} dom
*/
_refreshPlan: function (dom) {
- this.$el.html(dom);
+ // TODO: Not forward port this fix on master
+ var $dom = $(dom);
+ $dom.find('div.o_timesheet_plan_sale_timesheet_dashboard > table.table, ' +
+ 'div.o_timesheet_plan_sale_timesheet_people_time > table.table, ' +
+ 'div.o_project_plan_project_timesheet_forecast > table.table')
+ .wrap('<div class="table-responsive"></div>');
+ this.$el.html($dom);
},
/**
diff --git a/addons/sale_timesheet/static/tests/timesheet_plan_tests.js b/addons/sale_timesheet/static/tests/timesheet_plan_tests.js
index d1d71c4face..12ccea8e53b 100644
--- a/addons/sale_timesheet/static/tests/timesheet_plan_tests.js
+++ b/addons/sale_timesheet/static/tests/timesheet_plan_tests.js
@@ -48,7 +48,7 @@ QUnit.module('Timesheet Plan', {
mockRPC: function (route) {
assert.step(route);
if (route === '/timesheet/plan') {
- return $.when({html_content: 'Banach-Tarski'});
+ return $.when({html_content: '<p>Banach-Tarski</p>'});
}
return this._super.apply(this, arguments);
},
@@ -81,7 +81,7 @@ QUnit.module('Timesheet Plan', {
action: {name: 'Fibonacci'},
mockRPC: function (route) {
if (route === '/timesheet/plan') {
- return $.when({html_content: 'Banach-Tarski'});
+ return $.when({html_content: '<p>Banach-Tarski</p>'});
}
return this._super.apply(this, arguments);
},
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 2b46709335a..0fbdcf7e7d4 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -533,6 +533,10 @@ class Picking(models.Model):
def action_assign_owner(self):
self.move_line_ids.write({'owner_id': self.owner_id.id})
+ def action_assign_partner(self):
+ for picking in self:
+ picking.move_lines.write({'partner_id': picking.partner_id.id})
+
@api.multi
def do_print_picking(self):
self.write({'printed': True})
diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml
index b4f47463482..78bc346495b 100644
--- a/addons/stock/views/stock_picking_views.xml
+++ b/addons/stock/views/stock_picking_views.xml
@@ -247,6 +247,9 @@
<group>
<group>
<field name="partner_id"/>
+ <button name="action_assign_partner" string="Assign Partner" type="object" help="Assign the partner to the Operations. Use only if the partner is manually changed!"
+ attrs="{'invisible': ['|', '|', ('move_line_exist', '=', False), ('state', 'not in', ('draft', 'assigned', 'confirmed')), ('picking_type_code', '=', 'internal')]}"
+ class="oe_link oe_edit_only"/>
<field name="picking_type_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="location_id" groups="stock.group_stock_multi_locations" attrs="{'invisible': [('picking_type_code', '=', 'incoming')]}"/>
<field name="location_dest_id" groups="stock.group_stock_multi_locations" attrs="{'invisible': [('picking_type_code', '=', 'outgoing')]}"/>
diff --git a/addons/web_editor/static/src/js/widgets/widgets.js b/addons/web_editor/static/src/js/widgets/widgets.js
index 30de8171e53..34a45f7193d 100644
--- a/addons/web_editor/static/src/js/widgets/widgets.js
+++ b/addons/web_editor/static/src/js/widgets/widgets.js
@@ -736,6 +736,7 @@ var IconWidget = MediaWidget.extend({
this.$('div.font-icons-icons').html(
QWeb.render('web_editor.dialog.font-icons.icons', {iconsParser: iconsParser})
);
+ return $.when();
},
//--------------------------------------------------------------------------
diff --git a/addons/website_sale/static/src/scss/website_sale.scss b/addons/website_sale/static/src/scss/website_sale.scss
index 29e685b8b4a..6a5d755ad64 100644
--- a/addons/website_sale/static/src/scss/website_sale.scss
+++ b/addons/website_sale/static/src/scss/website_sale.scss
@@ -690,7 +690,7 @@ a.no-decoration {
.o_website_sale_animate {
opacity: 0.7;
- position: absolute;
+ position: absolute !important;
height: 150px;
width: 150px;
z-index: 1020;
diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py
index 083607f9807..fef68d537d0 100644
--- a/odoo/addons/base/models/res_users.py
+++ b/odoo/addons/base/models/res_users.py
@@ -868,8 +868,26 @@ class GroupsImplied(models.Model):
if values.get('users') or values.get('implied_ids'):
# add all implied groups (to all users of each group)
for group in self:
- vals = {'users': list(pycompat.izip(repeat(4), group.with_context(active_test=False).users.ids))}
- super(GroupsImplied, group.trans_implied_ids).write(vals)
+ self._cr.execute("""
+ WITH RECURSIVE group_imply(gid, hid) AS (
+ SELECT gid, hid
+ FROM res_groups_implied_rel
+ UNION
+ SELECT i.gid, r.hid
+ FROM res_groups_implied_rel r
+ JOIN group_imply i ON (i.hid = r.gid)
+ )
+ INSERT INTO res_groups_users_rel (gid, uid)
+ SELECT i.hid, r.uid
+ FROM group_imply i, res_groups_users_rel r
+ WHERE r.gid = i.gid
+ AND i.gid = %(gid)s
+ EXCEPT
+ SELECT r.gid, r.uid
+ FROM res_groups_users_rel r
+ JOIN group_imply i ON (r.gid = i.hid)
+ WHERE i.gid = %(gid)s
+ """, dict(gid=group.id))
return res
class UsersImplied(models.Model):