Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
97 changes: 97 additions & 0 deletions account_move_sale_partner/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
=========================
Account Move Sale Partner
=========================

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

.. |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--invoicing-lightgray.png?logo=github
:target: https://github.com/OCA/account-invoicing/tree/16.0/account_move_sale_partner
:alt: OCA/account-invoicing
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/account-invoicing-16-0/account-invoicing-16-0-account_move_sale_partner
: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-invoicing&target_branch=16.0
:alt: Try me on Runboat

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

This module adds the sale_partner_id field to invoices and displays it
in the invoice report. It assumes that each invoice is linked to a
single sale partner.

**Table of contents**

.. contents::
:local:

Configuration
=============

To make sure each invoice is linked to a single sale partner:

1. Navigate to Sales ▸ Configuration ▸ Settings.
2. Enable the option Group invoices by sale partner.

When enabled, invoices will only be grouped if the sale partner is the
same across all sale orders. Even if the invoice partner is the same,
sale orders with different sale partners will result in separate
invoices.

If you'd like to control the grouping behavior per invoice partner,
consider disabling this configuration and installing the
sale_order_invoicing_grouping_criteria module.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-invoicing/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-invoicing/issues/new?body=module:%20account_move_sale_partner%0Aversion:%2016.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
-------

* Quartile

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

- ``Quartile <https://www.quartile.co>``\ \_\_:

- Aung Ko Ko Lin

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.

This module is part of the `OCA/account-invoicing <https://github.com/OCA/account-invoicing/tree/16.0/account_move_sale_partner>`_ 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 account_move_sale_partner/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from .hooks import pre_init_hook
18 changes: 18 additions & 0 deletions account_move_sale_partner/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Account Move Sale Partner",
"category": "Invoice",
"version": "16.0.1.0.0",
"author": "Quartile, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-invoicing",
"license": "AGPL-3",
"depends": ["sale"],
"data": [
"reports/report_invoice_document.xml",
"views/account_move_views.xml",
"views/res_config_settings_views.xml",
],
"pre_init_hook": "pre_init_hook",
"installable": True,
}
45 changes: 45 additions & 0 deletions account_move_sale_partner/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo.tools.sql import column_exists


def pre_init_hook(cr):
if not column_exists(cr, "account_move", "partner_sale_id"):
cr.execute(
"""
ALTER TABLE account_move
ADD COLUMN partner_sale_id INTEGER REFERENCES res_partner(id) ON DELETE SET NULL;
"""
)
cr.execute(
"""
WITH spc AS (
SELECT
am.id AS move_id,
COUNT(DISTINCT so.partner_id) AS cnt,
MIN(so.partner_id) AS single_partner_id
FROM account_move am
LEFT JOIN account_move_line aml
ON aml.move_id = am.id
LEFT JOIN sale_order_line_invoice_rel rel
ON rel.invoice_line_id = aml.id
LEFT JOIN sale_order_line sol
ON sol.id = rel.order_line_id
LEFT JOIN sale_order so
ON so.id = sol.order_id
WHERE am.move_type IN ('out_invoice', 'out_refund')
GROUP BY am.id
)
UPDATE account_move am
SET partner_sale_id = CASE
WHEN spc.cnt = 1 AND spc.single_partner_id IS NOT NULL
THEN spc.single_partner_id
ELSE am.partner_id
END
FROM spc
WHERE am.id = spc.move_id
AND am.move_type IN ('out_invoice', 'out_refund')
AND am.partner_sale_id IS NULL;
"""
)
4 changes: 4 additions & 0 deletions account_move_sale_partner/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import account_move
from . import res_company
from . import res_config_settings
from . import sale_order
26 changes: 26 additions & 0 deletions account_move_sale_partner/models/account_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


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

partner_sale_id = fields.Many2one(
"res.partner",
string="Sold-to Partner",
compute="_compute_partner_sale_id",
store=True,
)

@api.depends("move_type", "invoice_line_ids.sale_line_ids.order_id.partner_id")
def _compute_partner_sale_id(self):
for move in self:
move.partner_sale_id = move.partner_id.id
sale_partners = move.move_type in [
"out_invoice",
"out_refund",
] and move.invoice_line_ids.mapped("sale_line_ids.order_id.partner_id")
if sale_partners and len(sale_partners) == 1:
move.partner_sale_id = sale_partners.id
10 changes: 10 additions & 0 deletions account_move_sale_partner/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


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

invoice_group_by_sale_partner = fields.Boolean()
12 changes: 12 additions & 0 deletions account_move_sale_partner/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


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

invoice_group_by_sale_partner = fields.Boolean(
related="company_id.invoice_group_by_sale_partner", readonly=False
)
20 changes: 20 additions & 0 deletions account_move_sale_partner/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import models


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

def _prepare_invoice(self):
vals = super()._prepare_invoice()
# Set for use in _get_invoice_grouping_keys
vals["partner_sale_id"] = self.partner_id.id
return vals

def _get_invoice_grouping_keys(self):
keys = super()._get_invoice_grouping_keys()
if self.env.company.invoice_group_by_sale_partner:
keys.append("partner_sale_id")
return keys
11 changes: 11 additions & 0 deletions account_move_sale_partner/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
To make sure each invoice is linked to a single sale partner:

1. Navigate to Sales ▸ Configuration ▸ Settings.
2. Enable the option Group invoices by sale partner.

When enabled, invoices will only be grouped if the sale partner is the same across all sale
orders. Even if the invoice partner is the same, sale orders with different sale partners will
result in separate invoices.

If you'd like to control the grouping behavior per invoice partner, consider disabling this
configuration and installing the sale_order_invoicing_grouping_criteria module.
3 changes: 3 additions & 0 deletions account_move_sale_partner/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Quartile <https://www.quartile.co>`__:

* Aung Ko Ko Lin
2 changes: 2 additions & 0 deletions account_move_sale_partner/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module adds the sale_partner_id field to invoices and displays it in the invoice
report. It assumes that each invoice is linked to a single sale partner.
50 changes: 50 additions & 0 deletions account_move_sale_partner/reports/report_invoice_document.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template
id="report_invoice_sale_partner"
inherit_id="account.report_invoice_document"
>
<xpath
expr="//t[@t-if='o.partner_shipping_id and (o.partner_shipping_id != o.partner_id)']"
position="before"
>
<t
t-if="o.partner_sale_id and (o.partner_sale_id != o.partner_id) and (o.partner_sale_id != o.partner_shipping_id)"
>
<div class="col-6">
<t t-set="sale_partner_block">
<div name="sale_partner">
<strong>Sold-to:</strong>
<div
t-field="o.partner_sale_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'
/>
</div>
</t>
</div>
</t>
</xpath>
<xpath
expr="//div[@name='shipping_address_block']/strong"
position="attributes"
>
<attribute
name="t-if"
>o.partner_sale_id != o.partner_shipping_id</attribute>
</xpath>
<xpath expr="//div[@name='shipping_address_block']/strong" position="after">
<t t-if="o.partner_sale_id == o.partner_shipping_id">
<strong>Sold-to and Shipping Address:</strong>
</t>
</xpath>
</template>
<template id="report_invoice_sale_partner_address" inherit_id="web.address_layout">
<xpath expr="//div[@class='address row']" position="before">
<t t-if="sale_partner_block">
<div name="sale_partner_block" class="col-6 mb-2">
<t t-out="sale_partner_block" />
</div>
</t>
</xpath>
</template>
</odoo>
Loading