Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ea79bed
[14.0][ADD] sale_unreconciled
AaronHForgeFlow Nov 27, 2021
82fec54
[IMP] sale_unreconciled: black, isort, prettier
AaronHForgeFlow Dec 29, 2021
700fb1b
[15.0][MIG] sale_unreconciled
AaronHForgeFlow Dec 29, 2021
be87223
[FIX] sale_unreconciled: do not create empty write-offs
AaronHForgeFlow Mar 2, 2022
1b34e1c
[15.0][FIX] sale_unreconciled: reconcile exit condition
AaronHForgeFlow May 12, 2022
24c4d80
[IMP] sale_unreconciled: allow companies to decide automatic reconcil…
AaronHForgeFlow Jul 13, 2022
1029b18
[FIX]sale_unreconciled: reconcile by currency
AaronHForgeFlow Aug 23, 2022
e51bdfa
[IMP] sale_unreconciled: add tolerance parameter
AaronHForgeFlow Oct 29, 2022
77020c0
[FIX] sale_unreconciled: if journals have no residual but are full re…
AaronHForgeFlow Nov 7, 2022
4619fc0
[FIX] sale_unreconciled: multicompany for get unreconciled base domain
AaronHForgeFlow Nov 21, 2022
c9e7591
[FIX] sale_unreconciled: action to see unreconciled journal items has…
AaronHForgeFlow Dec 22, 2022
97b6aab
[IMP] sale_unreconciled: reconcile by groups
AaronHForgeFlow Feb 21, 2023
aad0476
[FIX] sale_unreconcile: bad FW code
AaronHForgeFlow Apr 4, 2023
7c8ef51
[FIX] sale_unreconciled: sudo in search ir.model
AaronHForgeFlow Jul 17, 2023
7887f21
[IMP] sale_unreconciled: text
AaronHForgeFlow Oct 10, 2023
815b146
[IMP] sale_unreconciled: add hook for custom write-off date
AaronHForgeFlow Oct 26, 2023
1aee644
[FIX] sale_unreconciled: unreconciled base domain to match standard
AaronHForgeFlow Nov 29, 2023
88f50a2
[IMP]sale_unreconciled: reconcile cancelled SO
AaronHForgeFlow Dec 18, 2023
988b31d
fix sale_unrec
AaronHForgeFlow Dec 27, 2023
19a7305
[FIX]sale_unreconciled: condition when no product
AaronHForgeFlow Dec 28, 2023
bd9a7e3
[IMP] sale_unreconciled: amount unreconciled in tree view
AaronHForgeFlow Dec 29, 2023
32ff007
[FIX] sale_unreconciled: do the write-off on the latest date of the j…
AaronHForgeFlow Jan 8, 2024
ca7fa82
[FIX] sale_unreconciled: do not show warning unreonciled message when…
AaronHForgeFlow Feb 23, 2024
45e85ce
[MIG] sale_unreconciled: Migration to v16
AaronHForgeFlow Sep 17, 2024
ee7f74a
[IMP] sale_unreconciled: pre-commit auto fixes
AaronHForgeFlow Nov 3, 2025
62f5e46
[MIG] sale_unreconciled: Migration to v18
AaronHForgeFlow Nov 3, 2025
60ad4c4
[IMP] sale_unreconciled: mark write-offs entries
AaronHForgeFlow Nov 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions sale_unreconciled/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
=================
Sale Unreconciled
=================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0660eae9dc9154a47a87338820960db556d160b50027b7052b0e2e2886afa142
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github
:target: https://github.com/OCA/account-financial-tools/tree/18.0/sale_unreconciled
:alt: OCA/account-financial-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/account-financial-tools-18-0/account-financial-tools-18-0-sale_unreconciled
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/account-financial-tools&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds a new field "Unreconciled" on Sales Orders, that allows
to find SO's with unreconciled journal items related.

This module allows to reconcile those SO in a single click. In
accounting settings users will be able to set up a specific account for
write-off.

**Table of contents**

.. contents::
:local:

Usage
=====

Accountants will be able to find a filter in Sale Orders that shows
outstanding balances in interim accounts. Also there is a link in the SO
to those outstanding journal items.

Locking the SO will automatically reconcile the outstanding balance for
the stock interim accounts.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-financial-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20sale_unreconciled%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* ForgeFlow S.L.

Contributors
------------

- ForgeFlow S.L. <[email protected]>

- Aaron Henriquez <[email protected]>

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-AaronHForgeFlow| image:: https://github.com/AaronHForgeFlow.png?size=40px
:target: https://github.com/AaronHForgeFlow
:alt: AaronHForgeFlow

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-AaronHForgeFlow|

This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/18.0/sale_unreconciled>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions sale_unreconciled/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import wizards
21 changes: 21 additions & 0 deletions sale_unreconciled/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2021 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

{
"name": "Sale Unreconciled",
"version": "18.0.1.0.0",
"author": "ForgeFlow S.L., Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-financial-tools",
"category": "Accounting",
"depends": ["sale_mrp", "account_move_line_sale_info"],
"data": [
"security/ir.model.access.csv",
"views/sale_order_view.xml",
"views/res_config_settings_view.xml",
"wizards/sale_unreconciled_exceeded_view.xml",
],
"license": "AGPL-3",
"installable": True,
"development_status": "Beta",
"maintainers": ["AaronHForgeFlow"],
}
5 changes: 5 additions & 0 deletions sale_unreconciled/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import sale_order
from . import company
from . import res_config_settings
from . import account_move
from . import account_move_line
7 changes: 7 additions & 0 deletions sale_unreconciled/models/account_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from odoo import fields, models


class AccountMove(models.Model):
_inherit = "account.move"

sale_order_writeoff = fields.Boolean()
91 changes: 91 additions & 0 deletions sale_unreconciled/models/account_move_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Copyright 2019-21 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from datetime import datetime

from odoo import _, models
from odoo.exceptions import ValidationError


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

def _get_so_writeoff_amounts(self):
precision = self.env["decimal.precision"].precision_get("Account")
writeoff_amount = round(
sum(line["amount_residual"] for line in self), precision
)
writeoff_amount_curr = round(
sum(line["amount_residual_currency"] for line in self), precision
)
if writeoff_amount_curr and not writeoff_amount:
# Data inconsistency, do not create the write-off
return (0.0, 0.0, True)
first_currency = self[0]["currency_id"]
if all([line["currency_id"] == first_currency for line in self]):
same_curr = True
else:
same_curr = False

return (
writeoff_amount,
writeoff_amount_curr,
same_curr,
)

def _create_so_writeoff(self, writeoff_vals):
(
amount_writeoff,
amount_writeoff_curr,
same_curr,
) = self._get_so_writeoff_amounts()
if not amount_writeoff:
return self.env["account.move.line"]
partners = self.mapped("partner_id")
move_date = writeoff_vals.get("date", datetime.now())
write_off_vals = {
"name": _("Automatic writeoff"),
"amount_currency": same_curr and amount_writeoff_curr or amount_writeoff,
"debit": amount_writeoff > 0.0 and amount_writeoff or 0.0,
"credit": amount_writeoff < 0.0 and -amount_writeoff or 0.0,
"partner_id": len(partners) == 1 and partners.id or False,
"account_id": writeoff_vals["account_id"],
"date": move_date,
"sale_order_id": writeoff_vals["sale_order_id"],
"journal_id": writeoff_vals["journal_id"],
"currency_id": writeoff_vals["currency_id"],
"product_id": writeoff_vals["product_id"],
"sale_line_id": writeoff_vals["sale_line_id"],
}
counterpart_account = self.mapped("account_id")
if len(counterpart_account) != 1:
raise ValidationError(_("Cannot write-off more than one account"))
counter_part = write_off_vals.copy()
counter_part["debit"] = write_off_vals["credit"]
counter_part["credit"] = write_off_vals["debit"]
counter_part["amount_currency"] = -write_off_vals["amount_currency"]
counter_part["account_id"] = (counterpart_account.id,)

move = self.env["account.move"].create(
{
"date": move_date,
"journal_id": writeoff_vals["journal_id"],
"currency_id": writeoff_vals["currency_id"],
"line_ids": [(0, 0, write_off_vals), (0, 0, counter_part)],
"sale_order_writeoff": True,
}
)
if writeoff_vals.get("sale_order_id", False):
# done this way because sale_order_id is a related field and will
# not being assign on create. Cannot assign purchase_line_id because
# it is a generic write-off for the whole SO
self.env.cr.execute(
"""UPDATE account_move_line SET sale_order_id = %s
WHERE id in %s
""",
(writeoff_vals["sale_order_id"], tuple(move.line_ids.ids)),
)
move.action_post()
return move.line_ids.filtered(
lambda line: line.account_id.id == counterpart_account.id
)
29 changes: 29 additions & 0 deletions sale_unreconciled/models/company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2021 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ResCompany(models.Model):
_inherit = "res.company"

sale_reconcile_account_id = fields.Many2one(
"account.account",
domain=lambda self: [("deprecated", "=", False)],
string="Write-Off Account On Sales",
ondelete="restrict",
copy=False,
help="Write-off account to reconcile Unreconciled Sale Orders",
)

sale_reconcile_journal_id = fields.Many2one(
"account.journal", string="Writeoff Journal for Sales"
)
sale_lock_auto_reconcile = fields.Boolean()

sale_reconcile_tolerance = fields.Float(
string="Tolerance (%)",
default=0.0,
help="Percentage of tolerance of residual amount vs total amount of the Sales "
"Order. Leave zero to accept all discrepancies",
)
21 changes: 21 additions & 0 deletions sale_unreconciled/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2021 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

sale_reconcile_account_id = fields.Many2one(
related="company_id.sale_reconcile_account_id", readonly=False
)
sale_reconcile_journal_id = fields.Many2one(
related="company_id.sale_reconcile_journal_id", readonly=False
)
sale_lock_auto_reconcile = fields.Boolean(
related="company_id.sale_lock_auto_reconcile", readonly=False
)
sale_reconcile_tolerance = fields.Float(
related="company_id.sale_reconcile_tolerance", readonly=False
)
Loading
Loading