File: account_move_line.py

package info (click to toggle)
odoo 18.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 878,716 kB
  • sloc: javascript: 927,937; python: 685,670; xml: 388,524; sh: 1,033; sql: 415; makefile: 26
file content (74 lines) | stat: -rw-r--r-- 3,250 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import models
from odoo.osv.expression import AND, OR


class AccountMoveLine(models.Model):
    _inherit = 'account.move.line'

    def _compute_analytic_distribution(self):
        # when a project creates an aml, it adds an analytic account to it. the following filter is to save this
        # analytic account from being overridden by analytic default rules and lack thereof
        project_amls = self.filtered(lambda aml: aml.analytic_distribution and any(aml.sale_line_ids.project_id))
        super(AccountMoveLine, self - project_amls)._compute_analytic_distribution()
        project_id = self._context.get('project_id', False)
        if project_id:
            project = self.env['project.project'].browse(project_id)
            self.analytic_distribution = project._get_analytic_distribution()

    def _get_so_mapping_domain(self):
        return OR([
            OR([
                AND([
                    [(self.env['account.analytic.account'].browse(int(account_id)).root_plan_id._column_name(), "=", int(account_id))]
                    for account_id in key.split(",")
                ])
                for key in line.analytic_distribution
            ])
            for line in self
        ])

    def _get_so_mapping_from_project(self):
        """ Get the mapping of move.line with the sale.order record on which its analytic entries should be reinvoiced.
            A sale.order matches a move.line if the sale.order's project contains all the same analytic accounts
            as the ones in the distribution of the move.line.
            :return a dict where key is the move line id, and value is sale.order record (or None).
        """
        mapping = {}
        projects = self.env['project.project'].search(domain=self._get_so_mapping_domain())
        orders_per_project = dict(self.env['sale.order']._read_group(
            domain=[('project_id', 'in', projects.ids)],
            groupby=['project_id'],
            aggregates=['id:recordset']
        ))
        project_per_accounts = {
            next(iter(project._get_analytic_distribution())): project
            for project in projects
        }

        for move_line in self:
            analytic_distribution = move_line.analytic_distribution
            if not analytic_distribution:
                continue

            for accounts in analytic_distribution:
                project = project_per_accounts.get(accounts)
            if not project:
                continue

            orders = orders_per_project.get(project)
            if not orders:
                continue
            orders = orders.sorted('create_date')
            in_sale_state_orders = orders.filtered(lambda s: s.state == 'sale')

            mapping[move_line.id] = in_sale_state_orders[0] if in_sale_state_orders else orders[0]

        # map the move line index with the SO on which it needs to be reinvoiced. May be empty if no SO found
        return mapping

    def _sale_determine_order(self):
        mapping_from_invoice = super()._sale_determine_order()
        mapping_from_invoice.update(self._get_so_mapping_from_project())
        return mapping_from_invoice