Skip to content

Commit

Permalink
[IMP] mis_builder_cash_flow_sale
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiocorato committed Jan 4, 2024
1 parent 46a1a6a commit ee058ef
Show file tree
Hide file tree
Showing 16 changed files with 624 additions and 0 deletions.
3 changes: 3 additions & 0 deletions mis_builder_cash_flow_sale/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import models
from . import report
from .hooks import create_cashflow_lines
23 changes: 23 additions & 0 deletions mis_builder_cash_flow_sale/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2022-2023 Sergio Corato <https://github.com/sergiocorato>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "MIS Builder sale cash flow",
"version": "14.0.1.0.0",
"category": "other",
"author": "Sergio Corato",
"summary": "Generate automatically cash flow lines from sale order line.",
"website": "https://github.com/sergiocorato/e-account",
"license": "AGPL-3",
"depends": [
"mis_builder_cash_flow_inheritable",
"account_payment_sale",
"sale",
"sale_order_line_date",
],
"data": [
"views/sale.xml",
"views/cashflow_line.xml",
],
"installable": True,
"post_init_hook": "create_cashflow_lines",
}
22 changes: 22 additions & 0 deletions mis_builder_cash_flow_sale/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2022 Sergio Corato <https://github.com/sergiocorato>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging

from odoo import SUPERUSER_ID
from odoo.api import Environment

_logger = logging.getLogger(__name__)


def create_cashflow_lines(cr, registry):
with Environment.manage():
env = Environment(cr, SUPERUSER_ID, {})
sales = env["sale.order"].search([], order="id")
i_max = len(sales)
i = 0
for sale in sales:
i += 1
sale.order_line._refresh_cashflow_line()
_logger.info(
"Creating cashflow line for sale order #%s/%s" % (i, i_max)
)
96 changes: 96 additions & 0 deletions mis_builder_cash_flow_sale/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mis_builder_cash_flow_purchase
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-01 14:57+0000\n"
"PO-Revision-Date: 2023-05-01 14:57+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: mis_builder_cash_flow_purchase
#: model_terms:ir.ui.view,arch_db:mis_builder_cash_flow_purchase.purchase_order_form
msgid "Cash flow"
msgstr ""

#. module: mis_builder_cash_flow_purchase
#: model_terms:ir.ui.view,arch_db:mis_builder_cash_flow_purchase.purchase_order_form
msgid "Cash flow lines"
msgstr "Righe cash flow"

#. module: mis_builder_cash_flow_purchase
#: code:addons/mis_builder_cash_flow_purchase/models/purchase.py:119
#, python-format
msgid "Due line #%s/%s of Purchase order %s"
msgstr "Riga cash flow #%s/%s dell'ordine di acquisto %s"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model.fields,field_description:mis_builder_cash_flow_purchase.field_mis_cash_flow_forecast_line__purchase_balance_forecast
msgid "Forecast balance"
msgstr "Saldo previsto"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model.fields,field_description:mis_builder_cash_flow_purchase.field_purchase_order_line__cashflow_line_ids
msgid "Forecast cashflow line"
msgstr "Riga saldo previsto"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model,name:mis_builder_cash_flow_purchase.model_mis_cash_flow
msgid "MIS Cash Flow"
msgstr "MIS Cash flow"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model,name:mis_builder_cash_flow_purchase.model_mis_cash_flow_forecast_line
msgid "MIS Cash Flow Forecast Line"
msgstr "MIS Cash flow riga previsione"

#. module: mis_builder_cash_flow_purchase
#: code:addons/mis_builder_cash_flow_purchase/models/purchase.py:35
#, python-format
msgid "Payment mode %s used in purchase orders must be of type fixed."
msgstr "Il modo di pagamento %s usato negli ordini di acquisto deve essere di tipo fisso."

#. module: mis_builder_cash_flow_purchase
#: model:ir.model.fields,field_description:mis_builder_cash_flow_purchase.field_mis_cash_flow_forecast_line__purchase_balance_currency
msgid "Purchase Balance Currency"
msgstr "Saldo acquisto in valuta"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model.fields,field_description:mis_builder_cash_flow_purchase.field_mis_cash_flow_forecast_line__purchase_invoiced_percent
msgid "Purchase Invoiced Percent"
msgstr "Fatturazione acquisto (%)"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model,name:mis_builder_cash_flow_purchase.model_purchase_order
msgid "Purchase Order"
msgstr "Ordine di acquisto"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model,name:mis_builder_cash_flow_purchase.model_purchase_order_line
msgid "Purchase Order Line"
msgstr "Riga ordine di acquisto"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model.fields,help:mis_builder_cash_flow_purchase.field_mis_cash_flow_forecast_line__purchase_balance_currency
msgid "Purchase amount in vendor currency recomputed with delivered qty"
msgstr "L'importo dell'acquisto in valuta del fornitore ricalcolato sulla quantità consegnata"

#. module: mis_builder_cash_flow_purchase
#: model:ir.model.fields,field_description:mis_builder_cash_flow_purchase.field_mis_cash_flow_forecast_line__purchase_line_id
msgid "Purchase order line"
msgstr "Riga ordine di acquisto"

#. module: mis_builder_cash_flow_purchase
#: model_terms:ir.ui.view,arch_db:mis_builder_cash_flow_purchase.mis_cash_flow_forecast_line_view_form
#: model_terms:ir.ui.view,arch_db:mis_builder_cash_flow_purchase.mis_cash_flow_forecast_line_view_tree
#: model_terms:ir.ui.view,arch_db:mis_builder_cash_flow_purchase.purchase_order_form
msgid "Total forecast balance"
msgstr "Totale saldo previsto"

2 changes: 2 additions & 0 deletions mis_builder_cash_flow_sale/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import cashflow_line
from . import sale
57 changes: 57 additions & 0 deletions mis_builder_cash_flow_sale/models/cashflow_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2022-2023 Sergio Corato <https://github.com/sergiocorato>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models


class CashFlowForecastLine(models.Model):
_inherit = "mis.cash_flow.forecast_line"

sale_line_id = fields.Many2one(
comodel_name="sale.order.line",
ondelete="cascade",
string="Sale order line",
)
sale_balance_currency = fields.Monetary(
currency_field="currency_id",
help="Sale amount in vendor currency recomputed with delivered qty",
)
sale_invoiced_percent = fields.Float(
compute="_compute_balance_forecast", store=True
)
sale_balance_forecast = fields.Float(
compute="_compute_balance_forecast",
string="Forecast balance",
store=True,
)

@api.depends(
"balance",
"sale_balance_currency",
"sale_line_id.qty_invoiced",
"sale_line_id.product_uom_qty",
"sale_line_id.qty_delivered",
"sale_line_id.order_id.commitment_date",
"sale_line_id.order_id.date_order",
"sale_line_id.order_id.currency_id.rate",
)
def _compute_balance_forecast(self):
for line in self:
if line.sale_line_id:
line.sale_invoiced_percent = line.sale_line_id.qty_invoiced / (
max(
[
line.sale_line_id.product_uom_qty,
line.sale_line_id.qty_delivered,
1,
]
)
)
line.sale_balance_forecast = -line.currency_id._convert(
line.sale_balance_currency or line.balance,
line.sale_line_id.order_id.company_id.currency_id,
line.sale_line_id.order_id.company_id,
line.date,
) * (1 - line.sale_invoiced_percent)
else:
line.sale_invoiced_percent = 0
line.sale_balance_forecast = line.balance
160 changes: 160 additions & 0 deletions mis_builder_cash_flow_sale/models/sale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Copyright 2022-2023 Sergio Corato <https://github.com/sergiocorato>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import float_is_zero, float_round


class SaleOrder(models.Model):
_inherit = "sale.order"

def action_confirm(self):
res = super().action_confirm()
self.filtered(lambda x: x.state == "sale").mapped(
"order_line"
)._refresh_cashflow_line()
return res

def write(self, vals):
res = super().write(vals)
for sale_order in self:
if (
vals.get("payment_term_id")
or vals.get("commitment_date")
or vals.get("payment_mode_id")
):
sale_order.order_line._refresh_cashflow_line()
return res

@api.constrains("payment_mode_id")
def _check_payment_mode(self):
for record in self:
if (
record.payment_mode_id
and record.payment_mode_id.bank_account_link != "fixed"
):
raise ValidationError(
_("Payment mode %s used in sale orders must be of type fixed.")
% record.payment_mode_id.name
)


class SaleOrderLine(models.Model):
_inherit = "sale.order.line"

cashflow_line_ids = fields.One2many(
comodel_name="mis.cash_flow.forecast_line",
inverse_name="sale_line_id",
string="Forecast cashflow line",
)

@api.model
def create(self, vals):
line = super().create(vals)
line._refresh_cashflow_line()
return line

def write(self, vals):
res = super().write(vals)
if (
vals.get("price_unit")
or vals.get("commitment_date")
or vals.get("product_uom_qty")
or vals.get("discount")
or vals.get("discount2")
or vals.get("discount3")
):
self._refresh_cashflow_line()
return res

def _refresh_cashflow_line(self):
for line in self:
line.cashflow_line_ids.unlink()
if line.order_id.payment_mode_id.fixed_journal_id:
journal_id = line.order_id.payment_mode_id.fixed_journal_id
if line.price_total < 0:
account_id = journal_id.payment_credit_account_id
else:
account_id = journal_id.payment_debit_account_id
else:
account_ids = self.env["account.account"].search(
[
(
"user_type_id",
"=",
self.env.ref("account.data_account_type_liquidity").id,
),
("company_id", "=", line.order_id.company_id.id),
],
limit=1,
)
if not account_ids:
return False
account_id = account_ids[0]

# check is there is a residual prevision of amount to pay
# compute actual value of sale_order row
# as price_total do not change if delivered is more than ordered
# (net unit price row * max between ordered and invoiced qty)
max_qty = max([line.product_uom_qty, line.qty_delivered, 1])
sale_balance_total_currency = (
float_round(
line.price_total / (line.product_uom_qty or 1),
precision_rounding=line.order_id.currency_id.rounding,
)
) * max_qty
# with this value compute not invoiced amount (delivered or not)
# residual balance must be computed on cashflow line as it depends on
# current invoice factor and currency rate
# residual_balance = actual_row_balance *
# (1 - (line.qty_invoiced / max_qty))

if not float_is_zero(
sale_balance_total_currency,
precision_rounding=line.order_id.currency_id.rounding,
):
totlines = [
(
(
line.commitment_date
or line.order_id.commitment_date
or line.order_id.date_order
).strftime("%Y-%m-%d"),
sale_balance_total_currency,
)
]
if line.order_id.payment_term_id:
totlines = line.order_id.payment_term_id.compute(
sale_balance_total_currency,
line.commitment_date
or line.order_id.commitment_date
or line.order_id.date_order,
)
for i, dueline in enumerate(totlines, start=1):
line.write(
{
"cashflow_line_ids": [
(
0,
0,
{
"name": _(
"Due line #%s/%s of Sale order %s"
)
% (i, len(totlines), line.order_id.name),
"date": dueline[0],
"sale_balance_currency": dueline[1],
"currency_id": line.order_id.currency_id.id,
"balance": 0,
"sale_line_id": line.id,
"account_id": account_id.id,
"partner_id": line.order_id.partner_id.id,
"res_id": line.id,
"res_model_id": self.env.ref(
"sale.model_sale_order_line"
).id,
},
)
]
}
)
1 change: 1 addition & 0 deletions mis_builder_cash_flow_sale/report/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import mis_cash_flow
Loading

0 comments on commit ee058ef

Please sign in to comment.