diff --git a/addons/sale_stock/models/account_move.py b/addons/sale_stock/models/account_move.py
index 9c34d5bb955e9ce9db2e151b737c49d9bc7d10fc..26513f9ccc543b4f181e02f00763cc9d829ba45d 100644
--- a/addons/sale_stock/models/account_move.py
+++ b/addons/sale_stock/models/account_move.py
@@ -33,11 +33,23 @@ class AccountMove(models.Model):
         all_invoices_amls = current_invoice_amls.sale_line_ids.invoice_lines.filtered(lambda aml: aml.move_id.state == 'posted').sorted(lambda aml: (aml.date, aml.move_name, aml.id))
         index = all_invoices_amls.ids.index(current_invoice_amls[:1].id) if current_invoice_amls[:1] in all_invoices_amls else 0
         previous_amls = all_invoices_amls[:index]
-
-        previous_qties_invoiced = previous_amls._get_invoiced_qty_per_product()
         invoiced_qties = current_invoice_amls._get_invoiced_qty_per_product()
         invoiced_products = invoiced_qties.keys()
 
+        if self.move_type == 'out_invoice':
+            # filter out the invoices that have been fully refund and re-invoice otherwise, the quantities would be
+            # consumed by the reversed invoice and won't be print on the new draft invoice
+            previous_amls = previous_amls.filtered(lambda aml: aml.move_id.payment_state != 'reversed')
+
+        previous_qties_invoiced = previous_amls._get_invoiced_qty_per_product()
+
+        if self.move_type == 'out_refund':
+            # we swap the sign because it's a refund, and it would print negative number otherwise
+            for p in previous_qties_invoiced:
+                previous_qties_invoiced[p] = -previous_qties_invoiced[p]
+            for p in invoiced_qties:
+                invoiced_qties[p] = -invoiced_qties[p]
+
         qties_per_lot = defaultdict(float)
         previous_qties_delivered = defaultdict(float)
         stock_move_lines = current_invoice_amls.sale_line_ids.move_ids.move_line_ids.filtered(lambda sml: sml.state == 'done' and sml.lot_id).sorted(lambda sml: (sml.date, sml.id))
@@ -48,7 +60,13 @@ class AccountMove(models.Model):
             product_uom = product.uom_id
             qty_done = sml.product_uom_id._compute_quantity(sml.qty_done, product_uom)
 
-            if sml.location_id.usage == 'customer':
+            # is it a stock return considering the document type (should it be it thought of as positively or negatively?)
+            is_stock_return = (
+                    self.move_type == 'out_invoice' and (sml.location_id.usage, sml.location_dest_id.usage) == ('customer', 'internal')
+                    or
+                    self.move_type == 'out_refund' and (sml.location_id.usage, sml.location_dest_id.usage) == ('internal', 'customer')
+            )
+            if is_stock_return:
                 returned_qty = min(qties_per_lot[sml.lot_id], qty_done)
                 qties_per_lot[sml.lot_id] -= returned_qty
                 qty_done = returned_qty - qty_done
@@ -60,7 +78,7 @@ class AccountMove(models.Model):
             # try to reach the previous_qty_invoiced
             if float_compare(qty_done, 0, precision_rounding=product_uom.rounding) < 0 or \
                     float_compare(previous_qty_delivered, previous_qty_invoiced, precision_rounding=product_uom.rounding) < 0:
-                previously_done = qty_done if sml.location_id.usage == 'customer' else min(previous_qty_invoiced - previous_qty_delivered, qty_done)
+                previously_done = qty_done if is_stock_return else min(previous_qty_invoiced - previous_qty_delivered, qty_done)
                 previous_qties_delivered[product] += previously_done
                 qty_done -= previously_done
 
diff --git a/addons/sale_stock/tests/test_report.py b/addons/sale_stock/tests/test_report.py
index c4513d8c84784e04b4885d585eee6260b5f162e3..0a098d70232f347f595b757409ac97a8a54b83da 100644
--- a/addons/sale_stock/tests/test_report.py
+++ b/addons/sale_stock/tests/test_report.py
@@ -40,6 +40,8 @@ class TestSaleStockInvoices(TestSaleCommon):
             'product_id': self.product_by_usn.id,
             'company_id': self.env.company.id,
         })
+        self.usn01 = usn01
+        self.usn02 = usn02
         self.env['stock.quant']._update_available_quantity(self.product_by_lot, self.stock_location, 10, lot_id=lot)
         self.env['stock.quant']._update_available_quantity(self.product_by_usn, self.stock_location, 1, lot_id=usn01)
         self.env['stock.quant']._update_available_quantity(self.product_by_usn, self.stock_location, 1, lot_id=usn02)
@@ -281,3 +283,109 @@ class TestSaleStockInvoices(TestSaleCommon):
         self.assertRegex(text, r'Product By Lot\n6.00\nUnits\nLOT0002', "There should be a line that specifies 6 x LOT0002")
         self.assertRegex(text, r'Product By Lot\n2.00\nUnits\nLOT0003', "There should be a line that specifies 2 x LOT0003")
         self.assertNotIn('LOT0001', text)
+
+    def test_refund_cancel_invoices(self):
+        """
+        Suppose the lots are printed on the invoices.
+        The user sells 2 tracked-by-usn products, he delivers 2 products and invoices them
+        Then he adds credit notes and issues a full refund. Receive the products.
+        The reversed invoice should also have correct USN
+        """
+
+        report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments')
+        display_lots = self.env.ref('sale_stock.group_lot_on_invoice')
+        display_uom = self.env.ref('uom.group_uom')
+        self.env.user.write({'groups_id': [(4, display_lots.id), (4, display_uom.id)]})
+
+        so = self.env['sale.order'].create({
+            'partner_id': self.partner_a.id,
+            'order_line': [
+                (0, 0, {'name': self.product_by_usn.name, 'product_id': self.product_by_usn.id, 'product_uom_qty': 2}),
+            ],
+        })
+        so.action_confirm()
+
+        picking = so.picking_ids
+        picking.move_lines.move_line_ids[0].qty_done = 1
+        picking.move_lines.move_line_ids[1].qty_done = 1
+        picking.button_validate()
+
+        invoice01 = so._create_invoices()
+        invoice01.action_post()
+
+        html = report._render_qweb_html(invoice01.ids)[0]
+        text = html2plaintext(html)
+        self.assertRegex(text, r'Product By USN\n1.00\nUnits\nUSN0001', "There should be a line that specifies 1 x USN0001")
+        self.assertRegex(text, r'Product By USN\n1.00\nUnits\nUSN0002', "There should be a line that specifies 1 x USN0002")
+
+        # Refund the invoice
+        refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=[invoice01.id]).create({
+            'refund_method': 'cancel',
+        })
+        refund_invoice = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id'])
+
+        # recieve the returned product
+        stock_return_picking_form = Form(self.env['stock.return.picking'].with_context(active_ids=picking.ids, active_id=picking.sorted().ids[0], active_model='stock.picking'))
+        return_wiz = stock_return_picking_form.save()
+        res = return_wiz.create_returns()
+        pick_return = self.env['stock.picking'].browse(res['res_id'])
+
+        move_form = Form(pick_return.move_lines, view='stock.view_stock_move_nosuggest_operations')
+        with move_form.move_line_nosuggest_ids.new() as line:
+            line.lot_id = self.usn01
+            line.qty_done = 1
+        with move_form.move_line_nosuggest_ids.new() as line:
+            line.lot_id = self.usn02
+            line.qty_done = 1
+        move_form.save()
+        pick_return.button_validate()
+
+        # reversed invoice
+        html = report._render_qweb_html(refund_invoice.ids)[0]
+        text = html2plaintext(html)
+        self.assertRegex(text, r'Product By USN\n1.00\nUnits\nUSN0001', "There should be a line that specifies 1 x USN0001")
+        self.assertRegex(text, r'Product By USN\n1.00\nUnits\nUSN0002', "There should be a line that specifies 1 x USN0002")
+
+    def test_refund_modify_invoices(self):
+        """
+        Suppose the lots are printed on the invoices.
+        The user sells 1 tracked-by-usn products, he delivers 1 and invoices it
+        Then he adds credit notes and issues full refund and new draft invoice.
+        The new draft invoice should have correct USN
+        """
+
+        report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments')
+        display_lots = self.env.ref('sale_stock.group_lot_on_invoice')
+        display_uom = self.env.ref('uom.group_uom')
+        self.env.user.write({'groups_id': [(4, display_lots.id), (4, display_uom.id)]})
+
+        so = self.env['sale.order'].create({
+            'partner_id': self.partner_a.id,
+            'order_line': [
+                (0, 0, {'name': self.product_by_usn.name, 'product_id': self.product_by_usn.id, 'product_uom_qty': 1}),
+            ],
+        })
+        so.action_confirm()
+
+        picking = so.picking_ids
+        picking.move_lines.move_line_ids[0].qty_done = 1
+        picking.button_validate()
+
+        invoice01 = so._create_invoices()
+        invoice01.action_post()
+
+        html = report._render_qweb_html(invoice01.ids)[0]
+        text = html2plaintext(html)
+        self.assertRegex(text, r'Product By USN\n1.00\nUnits\nUSN0001', "There should be a line that specifies 1 x USN0001")
+
+        # Refund the invoice with full refund and new draft invoice
+        refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=[invoice01.id]).create({
+            'refund_method': 'modify',
+        })
+        invoice02 = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id'])
+        invoice02.action_post()
+
+        # new draft invoice
+        html = report._render_qweb_html(invoice02.ids)[0]
+        text = html2plaintext(html)
+        self.assertRegex(text, r'Product By USN\n1.00\nUnits\nUSN0001', "There should be a line that specifies 1 x USN0001")