Skip to content
Snippets Groups Projects
account_move.py 5.16 KiB
Newer Older
##############################################################################
#
#    Accounting periods, for Odoo
#    Copyright (C) 2018 XCG Consulting <http://odoo.consulting>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

import datetime
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
from odoo import _, api, exceptions, fields, models


class AccountMove(models.Model):
    """Add a period & dates onto accounting documents.
    """

    _inherit = "account.move"

    period_id = fields.Many2one(
        comodel_name="account.period",
        string="Period",
        help="The period this accounting document is in.",
        ondelete="restrict",
        states={"posted": [("readonly", True), ("required", True)]},
    )

    transaction_date = fields.Date(
        string="Transaction date",
            "Invoicing date when provided; otherwise this is the accounting "
            "date."
        states={"posted": [("readonly", True)]},
    )

    @api.model
    def create(self, vals):
        """Override to set a transaction date from invoices.
        """

        if not vals.get("date"):
            vals["date"] = fields.Date.context_today(self)

        invoice = self.env.context.get("invoice")
        if invoice and isinstance(invoice, models.BaseModel):
            if not isinstance(vals, dict):
                vals = {}
            vals["transaction_date"] = invoice.date_invoice

        return super(AccountMove, self).create(vals)

    @api.model
    def fields_get(self, allfields=None, attributes=None):
        """Override to tweak the default "date" field.
        """

        ret = super(AccountMove, self).fields_get(
            allfields=allfields, attributes=attributes
        date_field = ret.get("date")
        if date_field:
            date_field.update(
                {
                    "string": _("Accounting date"),
                    "help": _("Validation date of the accounting document."),
                    "readonly": True,
                    "states": {},
                }
            )

        return ret

    @api.multi
    def post(self):
        """Override accounting document validation to:
        - Set accounting dates (default "date" field).
        - Also set the transaction date ("transaction_date" field) when empty.
        """

        self.fill_accounting_dates()

        return super(AccountMove, self).post()

    @api.multi
    def fill_accounting_dates(self):
        """- Set accounting dates (default "date" field).
        - Also set the transaction date ("transaction_date" field) when empty.
        - Force the period to always be around the current date.
        """

        acc_date = datetime.date.today()
            # Cache some data.
            company = accdoc.company_id
            # Set the acc_date only if the force_period_on_date
            # context has provided.
            if self.env.context.get("force_period_on_date"):
                # If accounting document date is empty, get today date.
                acc_date = fields.Date.from_string(accdoc.date) or acc_date

            # Periods are ordered by date so selecting the first one is fine.
            period = self.env["account.period"].search(
                [
                    ("company_id", "=", company.id),
                    ("date_start", "<=", acc_date),
                    ("date_effective_cutoff", ">=", acc_date),
            if not period:
                raise exceptions.Warning(
                    _('No period found around %s in the "%s" company.')
                    % (acc_date, company.sudo().name)
            # When we are between the period end and cut-off date, force the
            # last day of the period.
            if accdoc.journal_id.type == "sale":
                period_end = fields.Date.from_string(period.date_stop)
                in_cutoff = acc_date > period_end
                acc_date = period_end if in_cutoff else acc_date
            # The data to update the accounting document with.
            accdoc_values = {"date": acc_date, "period_id": period.id}
            # Set a transaction date when no previous one set. Also, force it
            # during cut-off.
            if in_cutoff or not accdoc.transaction_date:
                accdoc_values["transaction_date"] = acc_date

            # Ready! Update the accounting document.
            accdoc.write(accdoc_values)