14.0 account budget forecast #4
@@ -77,7 +77,6 @@ This module is maintained by ELABORE.
|
|||||||
"wizard/budget_forecast_model_choice.xml",
|
"wizard/budget_forecast_model_choice.xml",
|
||||||
"views/account_analytic_account.xml",
|
"views/account_analytic_account.xml",
|
||||||
"views/account_analytic_account_categories.xml",
|
"views/account_analytic_account_categories.xml",
|
||||||
"views/account_invoice.xml",
|
|
||||||
"views/sale_order.xml",
|
"views/sale_order.xml",
|
||||||
"views/budget_forecast.xml",
|
"views/budget_forecast.xml",
|
||||||
"views/budget_coefficient.xml",
|
"views/budget_coefficient.xml",
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from . import account_analytic_account
|
from . import account_analytic_account
|
||||||
from . import account_analytic_line
|
from . import account_analytic_line
|
||||||
from . import account_move
|
|
||||||
from . import budget_forecast
|
from . import budget_forecast
|
||||||
from . import budget_forecast_model
|
from . import budget_forecast_model
|
||||||
from . import sale_order
|
from . import sale_order
|
||||||
|
@@ -6,4 +6,16 @@ from odoo import models, fields, api
|
|||||||
class AccountAnalyticLine(models.Model):
|
class AccountAnalyticLine(models.Model):
|
||||||
_inherit = "account.analytic.line"
|
_inherit = "account.analytic.line"
|
||||||
|
|
||||||
budget_forecast_id = fields.Many2one("budget.forecast", store=True)
|
timesheet_entry = fields.Boolean(
|
||||||
|
help="Technical field to identify analytic lines created from timesheet vies",
|
||||||
|
store=True,
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.model_create_multi
|
||||||
|
def create(self, vals_list):
|
||||||
|
lines = super(AccountAnalyticLine, self).create(vals_list)
|
||||||
|
for line, values in zip(lines, vals_list):
|
||||||
|
if line.project_id: # applied only for timesheet
|
||||||
|
line.timesheet_entry = True
|
||||||
|
return lines
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
|
|
||||||
|
|
||||||
class AccountMoveLine(models.Model):
|
|
||||||
_inherit = "account.move.line"
|
|
||||||
|
|
||||||
budget_forecast_id = fields.Many2one(
|
|
||||||
"budget.forecast",
|
|
||||||
string="Budget line",
|
|
||||||
index=True,
|
|
||||||
store=True,
|
|
||||||
readonly=False,
|
|
||||||
copy=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.depends("budget_forecast_id")
|
|
||||||
def _transfer_budget_forecast_line(self):
|
|
||||||
for record in self:
|
|
||||||
import pdb
|
|
||||||
|
|
||||||
pdb.set_trace()
|
|
||||||
record.analytic_line_ids.budget_forecast_id = record.budget_forecast_id.id
|
|
@@ -19,6 +19,13 @@ class BudgetForecast(models.Model):
|
|||||||
index=True,
|
index=True,
|
||||||
copy=True,
|
copy=True,
|
||||||
)
|
)
|
||||||
|
analytic_tag = fields.Many2one(
|
||||||
|
"account.analytic.tag",
|
||||||
|
"Analytic tag",
|
||||||
|
index=True,
|
||||||
|
copy=False,
|
||||||
|
ondelete="cascade",
|
||||||
|
)
|
||||||
|
|
||||||
budget_category = fields.Selection(
|
budget_category = fields.Selection(
|
||||||
[
|
[
|
||||||
@@ -61,9 +68,6 @@ class BudgetForecast(models.Model):
|
|||||||
copy=False,
|
copy=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
analytic_line_ids = fields.One2many(
|
|
||||||
"account.analytic.line", "budget_forecast_id", copy=False
|
|
||||||
)
|
|
||||||
actual_qty = fields.Float(
|
actual_qty = fields.Float(
|
||||||
"Actual Quantity",
|
"Actual Quantity",
|
||||||
compute="_calc_actual",
|
compute="_calc_actual",
|
||||||
@@ -114,6 +118,9 @@ class BudgetForecast(models.Model):
|
|||||||
"line_subsection",
|
"line_subsection",
|
||||||
]:
|
]:
|
||||||
record._create_category_sections()
|
record._create_category_sections()
|
||||||
|
record.analytic_tag = self.env["account.analytic.tag"].create(
|
||||||
|
{"name": record._calculate_name()}
|
||||||
|
)
|
||||||
return records
|
return records
|
||||||
|
|
||||||
def _create_category_sections(self):
|
def _create_category_sections(self):
|
||||||
@@ -193,6 +200,12 @@ class BudgetForecast(models.Model):
|
|||||||
values = {"name": record._calculate_name()}
|
values = {"name": record._calculate_name()}
|
||||||
record.write(values, False)
|
record.write(values, False)
|
||||||
|
|
||||||
|
@api.onchange("name")
|
||||||
|
def _compute_analytic_tag_name(self):
|
||||||
|
for record in self:
|
||||||
|
if record.analytic_tag:
|
||||||
|
record.analytic_tag.name = record.name
|
||||||
|
|
||||||
def _sync_sections_data(self):
|
def _sync_sections_data(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.display_type in ["line_section", "line_subsection"]:
|
if record.display_type in ["line_section", "line_subsection"]:
|
||||||
@@ -329,29 +342,66 @@ class BudgetForecast(models.Model):
|
|||||||
elif record.display_type == "line_note":
|
elif record.display_type == "line_note":
|
||||||
record.plan_price = 0.00
|
record.plan_price = 0.00
|
||||||
|
|
||||||
|
def _find_analytic_lines(self, move_type, with_timesheets=False):
|
||||||
|
self.ensure_one()
|
||||||
|
if with_timesheets:
|
||||||
|
domain = [
|
||||||
|
"|",
|
||||||
|
(
|
||||||
|
"move_id.move_id.move_type",
|
||||||
|
"in",
|
||||||
|
move_type,
|
||||||
|
),
|
||||||
|
("timesheet_entry", "=", True),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
domain = [
|
||||||
|
(
|
||||||
|
"move_id.move_id.move_type",
|
||||||
|
"in",
|
||||||
|
move_type,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
analytic_lines = (
|
||||||
|
self.env["account.analytic.line"]
|
||||||
|
.search(domain)
|
||||||
|
.filtered(lambda x: self.analytic_tag in x.tag_ids)
|
||||||
|
)
|
||||||
|
return analytic_lines
|
||||||
|
|
||||||
|
def _find_draft_invoice_lines(self, move_type):
|
||||||
|
self.ensure_one()
|
||||||
|
domain = [
|
||||||
|
("analytic_account_id", "=", self.analytic_id.id),
|
||||||
|
("parent_state", "in", ["draft"]),
|
||||||
|
("move_id.move_type", "in", move_type),
|
||||||
|
]
|
||||||
|
invoice_lines = (
|
||||||
|
self.env["account.move.line"]
|
||||||
|
.search(domain)
|
||||||
|
.filtered(lambda x: self.analytic_tag in x.analytic_tag_ids)
|
||||||
|
)
|
||||||
|
return invoice_lines
|
||||||
|
|
||||||
@api.depends("analytic_id.line_ids.amount")
|
@api.depends("analytic_id.line_ids.amount")
|
||||||
def _calc_actual(self):
|
def _calc_actual(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
|
# Section or Sub-section
|
||||||
if record.display_type in ["line_section", "line_subsection"]:
|
if record.display_type in ["line_section", "line_subsection"]:
|
||||||
if record.child_ids:
|
if record.child_ids:
|
||||||
# Actual expenses are calculated with the child lines
|
# Actual expenses are calculated with the child lines
|
||||||
record.actual_qty = sum(record.mapped("child_ids.actual_qty"))
|
record.actual_qty = sum(record.mapped("child_ids.actual_qty"))
|
||||||
record.actual_amount = sum(record.mapped("child_ids.actual_amount"))
|
record.actual_amount = sum(record.mapped("child_ids.actual_amount"))
|
||||||
|
|
||||||
# Incomes are calculated with the analytic lines
|
# Incomes are calculated with the analytic lines
|
||||||
line_ids = record.analytic_line_ids.filtered(
|
line_ids = record._find_analytic_lines(
|
||||||
lambda x: x.move_id.move_id.move_type
|
["out_invoice", "out_refund", "out_receipt"]
|
||||||
in ["out_invoice", "out_refund"]
|
|
||||||
)
|
)
|
||||||
record.incomes = sum(line_ids.mapped("amount"))
|
record.incomes = sum(line_ids.mapped("amount"))
|
||||||
|
# Add Draft Invoice lines ids to incomes
|
||||||
# Add Invoice lines ids
|
invoice_lines = record._find_draft_invoice_lines(
|
||||||
domain = [
|
["out_invoice", "out_refund"]
|
||||||
("analytic_account_id", "=", record.analytic_id.id),
|
)
|
||||||
("parent_state", "in", ["draft", "posted"]),
|
|
||||||
("budget_forecast_id", "=", record.id),
|
|
||||||
("move_id.move_type", "in", ["out_invoice", "out_refund"]),
|
|
||||||
]
|
|
||||||
invoice_lines = self.env["account.move.line"].search(domain)
|
|
||||||
for invoice_line in invoice_lines:
|
for invoice_line in invoice_lines:
|
||||||
if invoice_line.move_id.move_type == "out_invoice":
|
if invoice_line.move_id.move_type == "out_invoice":
|
||||||
record.incomes = (
|
record.incomes = (
|
||||||
@@ -363,25 +413,23 @@ class BudgetForecast(models.Model):
|
|||||||
)
|
)
|
||||||
record.balance = record.incomes - record.actual_amount
|
record.balance = record.incomes - record.actual_amount
|
||||||
|
|
||||||
|
# Note
|
||||||
elif record.display_type == "line_note":
|
elif record.display_type == "line_note":
|
||||||
record.actual_qty = 0
|
record.actual_qty = 0
|
||||||
record.actual_amount = 0.00
|
record.actual_amount = 0.00
|
||||||
|
|
||||||
|
# Product
|
||||||
else:
|
else:
|
||||||
line_ids = record.analytic_line_ids.filtered(
|
line_ids = record._find_analytic_lines(
|
||||||
lambda x: x.move_id.move_id.move_type
|
["in_invoice", "in_refund", "in_receipt"], True
|
||||||
not in ["out_invoice", "out_refund"]
|
|
||||||
)
|
)
|
||||||
record.actual_qty = abs(sum(line_ids.mapped("unit_amount")))
|
record.actual_qty = abs(sum(line_ids.mapped("unit_amount")))
|
||||||
record.actual_amount = -sum(line_ids.mapped("amount"))
|
record.actual_amount = -sum(line_ids.mapped("amount"))
|
||||||
|
|
||||||
# Add Invoice lines ids
|
# Add Draft Invoice lines ids
|
||||||
domain = [
|
invoice_lines = record._find_draft_invoice_lines(
|
||||||
("analytic_account_id", "=", record.analytic_id.id),
|
["in_invoice", "in_refund"]
|
||||||
("parent_state", "in", ["draft", "posted"]),
|
)
|
||||||
("budget_forecast_id", "=", record.id),
|
|
||||||
("move_id.move_type", "in", ["in_invoice", "in_refund"]),
|
|
||||||
]
|
|
||||||
invoice_lines = self.env["account.move.line"].search(domain)
|
|
||||||
for invoice_line in invoice_lines:
|
for invoice_line in invoice_lines:
|
||||||
if invoice_line.move_id.move_type == "in_invoice":
|
if invoice_line.move_id.move_type == "in_invoice":
|
||||||
record.actual_qty = record.actual_qty + invoice_line.quantity
|
record.actual_qty = record.actual_qty + invoice_line.quantity
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<record id="invoice_budget_form" model="ir.ui.view">
|
|
||||||
<field name="name">account.invoice.budget.form</field>
|
|
||||||
<field name="model">account.move</field>
|
|
||||||
<field name="inherit_id" ref="account.view_move_form" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='analytic_tag_ids']" position="after">
|
|
||||||
<field name="budget_forecast_id" domain="[('analytic_id', '=', analytic_account_id), ('product_id', '=', product_id)]" />
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
@@ -9,8 +9,10 @@
|
|||||||
<sheet>
|
<sheet>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
|
<field name="name" />
|
||||||
<field name="product_id" />
|
<field name="product_id" />
|
||||||
<field name="description" />
|
<field name="description" />
|
||||||
|
<field name="analytic_tag" />
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="analytic_id" />
|
<field name="analytic_id" />
|
||||||
@@ -36,7 +38,8 @@
|
|||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group string="Analytic Lines">
|
<group string="Analytic Lines">
|
||||||
<field name="analytic_line_ids" nolabel="1">
|
<!-- TODO: Ajouter bouton vers vue Tree affichant les lignes analytics -->
|
||||||
|
<!-- <field name="analytic_line_ids" nolabel="1">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="date" />
|
<field name="date" />
|
||||||
<field name="employee_id" />
|
<field name="employee_id" />
|
||||||
@@ -45,7 +48,7 @@
|
|||||||
<field name="unit_amount" string="Quantity" />
|
<field name="unit_amount" string="Quantity" />
|
||||||
<field name="amount" />
|
<field name="amount" />
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>-->
|
||||||
</group>
|
</group>
|
||||||
<group string="Childs" attrs="{'invisible' : [('child_ids','=', False)]}">
|
<group string="Childs" attrs="{'invisible' : [('child_ids','=', False)]}">
|
||||||
<field name="child_ids" nolabel="1">
|
<field name="child_ids" nolabel="1">
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree" />
|
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree" />
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='task_id']" position="after">
|
<xpath expr="//field[@name='task_id']" position="after">
|
||||||
<field name="budget_forecast_id" domain="[('display_type', '=', 'line_article')]" />
|
<field name="tag_ids" widget="many2many_tags" /> <!--domain="[('display_type', '=', 'line_article')]" />-->
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
<field name="inherit_id" ref="hr_timesheet.view_task_form2_inherited" />
|
<field name="inherit_id" ref="hr_timesheet.view_task_form2_inherited" />
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='timesheet_ids']/tree/field[@name='name']" position="after">
|
<xpath expr="//field[@name='timesheet_ids']/tree/field[@name='name']" position="after">
|
||||||
<field name="budget_forecast_id" domain="[('display_type', '=', 'line_article')]" />
|
<field name="tag_ids" /> <!--domain="[('display_type', '=', 'line_article')]" />-->
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
Reference in New Issue
Block a user