[IMP] sale_stock: decrease delivered quantity

The commit adds a "Refund" field on the stock move, in the module
sale_stock. This allows to decrease the quantity delivered in the
associated SO, and therefore to generate refunds more easily.
This commit is contained in:
Nicolas Martinelli
2016-03-22 16:19:01 +01:00
parent d3714770d9
commit f37681e74e
3 changed files with 56 additions and 9 deletions
+26 -2
View File
@@ -166,10 +166,10 @@ class SaleOrderLine(models.Model):
super(SaleOrderLine, self)._get_delivered_qty()
qty = 0.0
for move in self.procurement_ids.mapped('move_ids').filtered(lambda r: r.state == 'done' and not r.scrapped):
#Note that we don't decrease quantity for customer returns on purpose: these are exeptions that must be treated manually. Indeed,
#modifying automatically the delivered quantity may trigger an automatic reinvoicing (refund) of the SO, which is definitively not wanted
if move.location_dest_id.usage == "customer":
qty += self.env['product.uom']._compute_qty_obj(move.product_uom, move.product_uom_qty, self.product_uom)
elif move.location_dest_id.usage == "internal" and move.to_refund_so:
qty -= self.env['product.uom']._compute_qty_obj(move.product_uom, move.product_uom_qty, self.product_uom)
return qty
@api.multi
@@ -249,6 +249,9 @@ class ProcurementOrder(models.Model):
class StockMove(models.Model):
_inherit = "stock.move"
to_refund_so = fields.Boolean(string="To Refund in SO", default=False,
help='Trigger a decrease of the delivered quantity in the associated Sale Order')
@api.multi
def action_done(self):
result = super(StockMove, self).action_done()
@@ -279,6 +282,27 @@ class StockPicking(models.Model):
sale_id = fields.Many2one(comodel_name='sale.order', string="Sale Order", compute='_compute_sale_id')
class StockReturnPicking(models.TransientModel):
_inherit = "stock.return.picking"
@api.multi
def _create_returns(self):
new_picking_id, pick_type_id = super(StockReturnPicking, self)._create_returns()
new_picking = self.env['stock.picking'].browse([new_picking_id])
for move in new_picking.move_lines:
return_picking_line = self.product_return_moves.filtered(lambda r: r.move_id == move.origin_returned_move_id)
if return_picking_line and return_picking_line.to_refund_so:
move.to_refund_so = True
return new_picking_id, pick_type_id
class StockReturnPickingLine(models.TransientModel):
_inherit = "stock.return.picking.line"
to_refund_so = fields.Boolean(string="To Refund in SO", help='Trigger a decrease of the delivered quantity in the associated Sale Order')
class AccountInvoiceLine(models.Model):
_inherit = "account.invoice.line"
+11
View File
@@ -50,6 +50,17 @@
</field>
</record>
<record id="view_stock_return_picking_form_inherit_sale_stock" model="ir.ui.view">
<field name="name">stock.return.picking.sale.stock.form</field>
<field name="inherit_id" ref="stock.view_stock_return_picking_form"/>
<field name="model">stock.return.picking</field>
<field name="arch" type="xml">
<field name="quantity" position="after">
<field name="to_refund_so"/>
</field>
</field>
</record>
<template id="report_saleorder_document_inherit_sale_stock" inherit_id="sale.report_saleorder_document">
<xpath expr="//div[@name='payment_term']" position="after">
<div class="col-xs-3" t-if="doc.incoterm" groups="sale.group_display_incoterm">
+19 -7
View File
@@ -132,7 +132,7 @@ class TestSaleStock(TestSale):
self.assertTrue(self.so.picking_ids, 'Sale Stock: no picking created for "invoice on delivery" stockable products')
# invoice in on delivery, nothing should be invoiced
self.assertEqual(self.so.invoice_status, 'no', 'Sale Stock: so invoice_status should be "nothing to invoice"')
self.assertEqual(self.so.invoice_status, 'no', 'Sale Stock: so invoice_status should be "no" instead of "%s".' % self.so.invoice_status)
# deliver completely
pick = self.so.picking_ids
@@ -142,27 +142,39 @@ class TestSaleStock(TestSale):
# Check quantity delivered
del_qty = sum(sol.qty_delivered for sol in self.so.order_line)
self.assertEqual(del_qty, 5.0, 'Sale Stock: delivered quantity should be 5.0 after complete delivery')
self.assertEqual(del_qty, 5.0, 'Sale Stock: delivered quantity should be 5.0 instead of %s after complete delivery' % del_qty)
# Check invoice
self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale Stock: so invoice_status should be "to invoice" before invoicing')
self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale Stock: so invoice_status should be "to invoice" instead of "%s" before invoicing' % self.so.invoice_status)
inv_1_id = self.so.action_invoice_create()
self.assertEqual(self.so.invoice_status, 'invoiced', 'Sale Stock: so invoice_status should be "invoiced" after invoicing')
self.assertEqual(len(inv_1_id), 1, 'Sale Stock: only one invoice should be created')
self.assertEqual(self.so.invoice_status, 'invoiced', 'Sale Stock: so invoice_status should be "invoiced" instead of "%s" after invoicing' % self.so.invoice_status)
self.assertEqual(len(inv_1_id), 1, 'Sale Stock: only one invoice instead of "%s" should be created' % len(inv_1_id))
self.inv_1 = self.env['account.invoice'].browse(inv_1_id)
self.assertEqual(self.inv_1.amount_untaxed, self.inv_1.amount_untaxed, 'Sale Stock: amount in SO and invoice should be the same')
self.inv_1.signal_workflow('invoice_open')
# Create return picking
StockReturnPicking = self.env['stock.return.picking']
default_data = StockReturnPicking.with_context(active_ids=pick.ids, active_id=pick.ids[0]).default_get(['move_dest_exists', 'original_location_id', 'product_return_moves', 'parent_location_id', 'location_id'])
return_wiz = StockReturnPicking.with_context(active_ids=pick.ids, active_id=pick.ids[0]).create(default_data)
return_wiz.product_return_moves.quantity = 2.0 # Return only 2
return_wiz.product_return_moves.to_refund_so = True # Refund these 2
res = return_wiz.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])
# Validate picking
return_pick.force_assign()
return_pick.pack_operation_product_ids.write({'qty_done': 5})
return_pick.pack_operation_product_ids.write({'qty_done': 2})
return_pick.do_new_transfer()
# Check invoice
self.assertEqual(self.so.invoice_status, 'invoiced', 'Sale Stock: so invoice_status should be "invoiced" after picking return')
self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale Stock: so invoice_status should be "to invoice" instead of "%s" after picking return' % self.so.invoice_status)
self.assertEqual(self.so.order_line[0].qty_delivered, 3.0, 'Sale Stock: delivered quantity should be 3.0 instead of "%s" after picking return' % self.so.order_line[0].qty_delivered)
# let's do an invoice with refunds
adv_wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=[self.so.id]).create({
'advance_payment_method': 'all',
})
adv_wiz.with_context(open_invoices=True).create_invoices()
self.inv_2 = self.so.invoice_ids.filtered(lambda r: r.state == 'draft')
self.assertEqual(self.inv_2.invoice_line_ids[0].quantity, 2.0, 'Sale Stock: refund quantity on the invoice should be 2.0 instead of "%s".' % self.inv_2.invoice_line_ids[0].quantity)
self.assertEqual(self.so.invoice_status, 'no', 'Sale Stock: so invoice_status should be "no" instead of "%s" after invoicing the return' % self.so.invoice_status)