summaryrefslogtreecommitdiff
path: root/addons/sale_stock/models/account_move.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/sale_stock/models/account_move.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/sale_stock/models/account_move.py')
-rw-r--r--addons/sale_stock/models/account_move.py125
1 files changed, 125 insertions, 0 deletions
diff --git a/addons/sale_stock/models/account_move.py b/addons/sale_stock/models/account_move.py
new file mode 100644
index 00000000..7827f827
--- /dev/null
+++ b/addons/sale_stock/models/account_move.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from collections import defaultdict
+
+from odoo import fields, models
+from odoo.tools import float_is_zero
+
+
+class AccountMove(models.Model):
+ _inherit = 'account.move'
+
+ def _stock_account_get_last_step_stock_moves(self):
+ """ Overridden from stock_account.
+ Returns the stock moves associated to this invoice."""
+ rslt = super(AccountMove, self)._stock_account_get_last_step_stock_moves()
+ for invoice in self.filtered(lambda x: x.move_type == 'out_invoice'):
+ rslt += invoice.mapped('invoice_line_ids.sale_line_ids.move_ids').filtered(lambda x: x.state == 'done' and x.location_dest_id.usage == 'customer')
+ for invoice in self.filtered(lambda x: x.move_type == 'out_refund'):
+ rslt += invoice.mapped('reversed_entry_id.invoice_line_ids.sale_line_ids.move_ids').filtered(lambda x: x.state == 'done' and x.location_id.usage == 'customer')
+ # Add refunds generated from the SO
+ rslt += invoice.mapped('invoice_line_ids.sale_line_ids.move_ids').filtered(lambda x: x.state == 'done' and x.location_id.usage == 'customer')
+ return rslt
+
+ def _get_invoiced_lot_values(self):
+ """ Get and prepare data to show a table of invoiced lot on the invoice's report. """
+ self.ensure_one()
+
+ if self.state == 'draft':
+ return []
+
+ sale_orders = self.mapped('invoice_line_ids.sale_line_ids.order_id')
+ stock_move_lines = sale_orders.mapped('picking_ids.move_lines.move_line_ids')
+
+ # Get the other customer invoices and refunds.
+ ordered_invoice_ids = sale_orders.mapped('invoice_ids')\
+ .filtered(lambda i: i.state not in ['draft', 'cancel'])\
+ .sorted(lambda i: (i.invoice_date, i.id))
+
+ # Get the position of self in other customer invoices and refunds.
+ self_index = None
+ i = 0
+ for invoice in ordered_invoice_ids:
+ if invoice.id == self.id:
+ self_index = i
+ break
+ i += 1
+
+ # Get the previous invoice if any.
+ previous_invoices = ordered_invoice_ids[:self_index]
+ last_invoice = previous_invoices[-1] if len(previous_invoices) else None
+
+ # Get the incoming and outgoing sml between self.invoice_date and the previous invoice (if any).
+ write_dates = [wd for wd in self.invoice_line_ids.mapped('write_date') if wd]
+ self_datetime = max(write_dates) if write_dates else None
+ last_write_dates = last_invoice and [wd for wd in last_invoice.invoice_line_ids.mapped('write_date') if wd]
+ last_invoice_datetime = max(last_write_dates) if last_write_dates else None
+ def _filter_incoming_sml(ml):
+ if ml.state == 'done' and ml.location_id.usage == 'customer' and ml.lot_id:
+ if last_invoice_datetime:
+ return last_invoice_datetime <= ml.date <= self_datetime
+ else:
+ return ml.date <= self_datetime
+ return False
+
+ def _filter_outgoing_sml(ml):
+ if ml.state == 'done' and ml.location_dest_id.usage == 'customer' and ml.lot_id:
+ if last_invoice_datetime:
+ return last_invoice_datetime <= ml.date <= self_datetime
+ else:
+ return ml.date <= self_datetime
+ return False
+
+ incoming_sml = stock_move_lines.filtered(_filter_incoming_sml)
+ outgoing_sml = stock_move_lines.filtered(_filter_outgoing_sml)
+
+ # Prepare and return lot_values
+ qties_per_lot = defaultdict(lambda: 0)
+ if self.move_type == 'out_refund':
+ for ml in outgoing_sml:
+ qties_per_lot[ml.lot_id] -= ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
+ for ml in incoming_sml:
+ qties_per_lot[ml.lot_id] += ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
+ else:
+ for ml in outgoing_sml:
+ qties_per_lot[ml.lot_id] += ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
+ for ml in incoming_sml:
+ qties_per_lot[ml.lot_id] -= ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
+ lot_values = []
+ for lot_id, qty in qties_per_lot.items():
+ if float_is_zero(qty, precision_rounding=lot_id.product_id.uom_id.rounding):
+ continue
+ lot_values.append({
+ 'product_name': lot_id.product_id.display_name,
+ 'quantity': qty,
+ 'uom_name': lot_id.product_uom_id.name,
+ 'lot_name': lot_id.name,
+ # The lot id is needed by localizations to inherit the method and add custom fields on the invoice's report.
+ 'lot_id': lot_id.id
+ })
+ return lot_values
+
+
+class AccountMoveLine(models.Model):
+ _inherit = "account.move.line"
+
+ def _sale_can_be_reinvoice(self):
+ self.ensure_one()
+ return not self.is_anglo_saxon_line and super(AccountMoveLine, self)._sale_can_be_reinvoice()
+
+
+ def _stock_account_get_anglo_saxon_price_unit(self):
+ self.ensure_one()
+ price_unit = super(AccountMoveLine, self)._stock_account_get_anglo_saxon_price_unit()
+
+ so_line = self.sale_line_ids and self.sale_line_ids[-1] or False
+ if so_line:
+ qty_to_invoice = self.product_uom_id._compute_quantity(self.quantity, self.product_id.uom_id)
+ qty_invoiced = sum([x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id) for x in so_line.invoice_lines if x.move_id.state == 'posted'])
+ average_price_unit = self.product_id._compute_average_price(qty_invoiced, qty_to_invoice, so_line.move_ids)
+
+ price_unit = average_price_unit or price_unit
+ price_unit = self.product_id.uom_id._compute_price(price_unit, self.product_uom_id)
+ return price_unit
+