diff --git a/addons/account/static/src/scss/account_reconciliation.scss b/addons/account/static/src/scss/account_reconciliation.scss index 6c21d14e8f2..6e218b9f11b 100644 --- a/addons/account/static/src/scss/account_reconciliation.scss +++ b/addons/account/static/src/scss/account_reconciliation.scss @@ -289,6 +289,10 @@ overflow: auto; border: 1px solid #ddd; border-radius: 0 0 5px 5px; + > div.quick_add > .o_reconcile_models { + max-height: 54px; + overflow: auto; + } } .quick_add { margin-bottom: 7px; @@ -357,4 +361,4 @@ } } } -} \ No newline at end of file +} diff --git a/addons/event_sale/wizard/event_edit_registration.xml b/addons/event_sale/wizard/event_edit_registration.xml index 92a69107ba7..25422c2947a 100644 --- a/addons/event_sale/wizard/event_edit_registration.xml +++ b/addons/event_sale/wizard/event_edit_registration.xml @@ -12,7 +12,7 @@ - + diff --git a/addons/hr_org_chart/static/src/xml/hr_org_chart.xml b/addons/hr_org_chart/static/src/xml/hr_org_chart.xml index e4e7f9fa231..1dfa693fa40 100644 --- a/addons/hr_org_chart/static/src/xml/hr_org_chart.xml +++ b/addons/hr_org_chart/static/src/xml/hr_org_chart.xml @@ -105,6 +105,7 @@
…
diff --git a/addons/l10n_be_invoice_bba/data/mail_template_data.xml b/addons/l10n_be_invoice_bba/data/mail_template_data.xml index e12f7745b91..5e6bfecdfb7 100644 --- a/addons/l10n_be_invoice_bba/data/mail_template_data.xml +++ b/addons/l10n_be_invoice_bba/data/mail_template_data.xml @@ -25,7 +25,7 @@ This invoice is already paid. % else: Please remit payment at your earliest convenience. - % if object.reference_type == 'bba' and object.reference: + % if object.invoice_reference_type=='structured' and object.reference: Please use the following communication for your payment: ${object.reference}. % endif

diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index f14542398be..77295665439 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -486,7 +486,10 @@ class MrpProduction(models.Model): if move: old_qty = move[0].product_uom_qty if quantity > 0: - move[0].write({'product_uom_qty': quantity}) + move[0]._decrease_reserved_quanity(quantity) + move[0].with_context(do_not_unreserve=True).write({'product_uom_qty': quantity}) + move[0]._recompute_state() + move[0]._action_assign() move.unit_factor = quantity / move.raw_material_production_id.product_qty elif quantity < 0: # Do not remove 0 lines if move[0].quantity_done > 0: diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index 83444b708a7..f5e931a71d5 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -182,6 +182,24 @@ class StockMove(models.Model): self.sudo().unlink() return processed_moves + def _decrease_reserved_quanity(self, quantity): + """ Decrease the reservation on move lines but keeps the + all other data. + """ + move_line_to_unlink = self.env['stock.move.line'] + for move in self: + reserved_quantity = quantity + for move_line in self.move_line_ids: + if move_line.product_uom_qty > reserved_quantity: + move_line.product_uom_qty = reserved_quantity + else: + move_line.product_uom_qty = 0 + reserved_quantity -= move_line.product_uom_qty + if not move_line.product_uom_qty and not move_line.qty_done: + move_line_to_unlink |= move_line + move_line_to_unlink.unlink() + return True + def _prepare_phantom_move_values(self, bom_line, quantity): return { 'picking_id': self.picking_id.id if self.picking_id else False, diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index e3bd7c3a72e..6dfe4c08e4b 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -629,6 +629,52 @@ class TestMrpOrder(TestMrpCommon): mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") + def test_product_produce_5(self): + """ Build 5 final products with different consumed lots, + then edit the finished quantity and update the Manufacturing + order quantity. Then check if the produced quantity do not + change and it is possible to close the MO. + """ + self.stock_location = self.env.ref('stock.stock_location_stock') + mo, bom, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot') + self.assertEqual(len(mo), 1, 'MO should have been created') + + lot_1 = self.env['stock.production.lot'].create({ + 'name': 'lot1', + 'product_id': p1.id, + }) + lot_2 = self.env['stock.production.lot'].create({ + 'name': 'lot2', + 'product_id': p1.id, + }) + + self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 10, lot_id=lot_1) + self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 10, lot_id=lot_2) + + self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5) + mo.action_assign() + + produce_wizard = self.env['mrp.product.produce'].with_context({ + 'active_id': mo.id, + 'active_ids': [mo.id], + }).create({ + 'product_qty': 5.0, + }) + + for produce_line in produce_wizard.produce_line_ids: + produce_line.qty_done = produce_line.qty_to_consume + produce_wizard.do_produce() + + mo.move_finished_ids.move_line_ids.qty_done -= 1 + update_quantity_wizard = self.env['change.production.qty'].create({ + 'mo_id': mo.id, + 'product_qty': 4, + }) + update_quantity_wizard.change_prod_qty() + + self.assertEqual(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity_done, 20, 'Update the produce quantity should not impact already produced quantity.') + mo.button_mark_done() + def test_product_produce_uom(self): plastic_laminate = self.env.ref('mrp.product_product_plastic_laminate') bom = self.env.ref('mrp.mrp_bom_plastic_laminate') diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py index 6cda5d64f9b..b92616c9a50 100644 --- a/addons/mrp/wizard/change_production_qty.py +++ b/addons/mrp/wizard/change_production_qty.py @@ -53,7 +53,6 @@ class ChangeProductionQty(models.TransientModel): factor = production.product_uom_id._compute_quantity(production.product_qty - qty_produced, production.bom_id.product_uom_id) / production.bom_id.product_qty boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id) documents = {} - done_quantities = {move: move.quantity_done for move in production.move_raw_ids} for line, line_data in lines: move, old_qty, new_qty = production._update_raw_move(line, line_data) iterate_key = production._get_document_iterate_key(move) @@ -73,9 +72,6 @@ class ChangeProductionQty(models.TransientModel): production._log_downside_manufactured_quantity(finished_moves_modification) moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel')) moves._action_assign() - for move in production.move_raw_ids: - if move.quantity_done != done_quantities[move]: - move._set_quantity_done(done_quantities[move]) for wo in production.workorder_ids: operation = wo.operation_id if operation_bom_qty.get(operation.id): diff --git a/addons/purchase/models/res_partner.py b/addons/purchase/models/res_partner.py index dd120858885..ec6fb75d5f8 100644 --- a/addons/purchase/models/res_partner.py +++ b/addons/purchase/models/res_partner.py @@ -11,15 +11,38 @@ class res_partner(models.Model): @api.multi def _compute_purchase_order_count(self): - PurchaseOrder = self.env['purchase.order'] - for partner in self: - partner.purchase_order_count = PurchaseOrder.search_count([('partner_id', 'child_of', partner.id)]) + # retrieve all children partners and prefetch 'parent_id' on them + all_partners = self.search([('id', 'child_of', self.ids)]) + all_partners.read(['parent_id']) + + purchase_order_groups = self.env['purchase.order'].read_group( + domain=[('partner_id', 'in', all_partners.ids)], + fields=['partner_id'], groupby=['partner_id'] + ) + for group in purchase_order_groups: + partner = self.browse(group['partner_id'][0]) + while partner: + if partner in self: + partner.purchase_order_count += group['partner_id_count'] + partner = partner.parent_id @api.multi def _compute_supplier_invoice_count(self): - Invoice = self.env['account.invoice'] - for partner in self: - partner.supplier_invoice_count = Invoice.search_count([('partner_id', 'child_of', partner.id), ('type', '=', 'in_invoice')]) + # retrieve all children partners and prefetch 'parent_id' on them + all_partners = self.search([('id', 'child_of', self.ids)]) + all_partners.read(['parent_id']) + + supplier_invoice_groups = self.env['account.invoice'].read_group( + domain=[('partner_id', 'in', all_partners.ids), + ('type', '=', 'in_invoice')], + fields=['partner_id'], groupby=['partner_id'] + ) + for group in supplier_invoice_groups: + partner = self.browse(group['partner_id'][0]) + while partner: + if partner in self: + partner.supplier_invoice_count += group['partner_id_count'] + partner = partner.parent_id @api.model def _commercial_fields(self): diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml index 5679d565c9c..65729354471 100644 --- a/addons/purchase/views/purchase_views.xml +++ b/addons/purchase/views/purchase_views.xml @@ -218,6 +218,7 @@ + @@ -227,6 +228,7 @@ + diff --git a/addons/sale/views/sale_views.xml b/addons/sale/views/sale_views.xml index e980ad2e61d..258beba4b91 100644 --- a/addons/sale/views/sale_views.xml +++ b/addons/sale/views/sale_views.xml @@ -313,6 +313,7 @@ +