Skip to content
Merged
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
108 changes: 108 additions & 0 deletions account_move_order_partner/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
==========================
Account Move Order 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/18.0/account_move_order_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-18-0/account-invoicing-18-0-account_move_order_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=18.0
:alt: Try me on Runboat

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

Adds the order partner (sold-to partner) to invoices and prints it on
the report. If multiple partners are involved, the sale partner defaults
to the invoice partner.

**Table of contents**

.. contents::
:local:

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

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

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

When enabled, invoices will only be grouped if the order partner is the
same across all sale orders. Even if the invoice partner is the same,
sale orders with different order 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_order_partner%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
-------

* 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.

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

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

|maintainer-yostashiro| |maintainer-aungkokolin1997|

This module is part of the `OCA/account-invoicing <https://github.com/OCA/account-invoicing/tree/18.0/account_move_order_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_order_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
19 changes: 19 additions & 0 deletions account_move_order_partner/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Account Move Order Partner",
"category": "Invoice",
"version": "18.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",
"maintainers": ["yostashiro", "aungkokolin1997"],
"installable": True,
}
45 changes: 45 additions & 0 deletions account_move_order_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(env):
if not column_exists(env.cr, "account_move", "order_partner_id"):
env.cr.execute(
"""
ALTER TABLE account_move
ADD COLUMN order_partner_id INTEGER
REFERENCES res_partner(id)
ON DELETE SET NULL;
"""
)
env.cr.execute(
"""
WITH spc AS (
SELECT
am.id AS move_id,
COUNT(DISTINCT sol.order_partner_id) AS cnt,
MIN(sol.order_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
WHERE am.move_type IN ('out_invoice', 'out_refund')
GROUP BY am.id
)
UPDATE account_move am
SET order_partner_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.order_partner_id IS NULL;
"""
)
4 changes: 4 additions & 0 deletions account_move_order_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
28 changes: 28 additions & 0 deletions account_move_order_partner/models/account_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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"

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

@api.depends(
"move_type", "partner_id", "invoice_line_ids.sale_line_ids.order_partner_id"
)
def _compute_order_partner_id(self):
for move in self:
move.order_partner_id = move.partner_id
sale_partners = move.move_type in [
"out_invoice",
"out_refund",
] and move.invoice_line_ids.mapped("sale_line_ids.order_partner_id")
if sale_partners and len(sale_partners) == 1:
move.order_partner_id = sale_partners.id
10 changes: 10 additions & 0 deletions account_move_order_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_order_partner = fields.Boolean()
12 changes: 12 additions & 0 deletions account_move_order_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_order_partner = fields.Boolean(
related="company_id.invoice_group_by_order_partner", readonly=False
)
20 changes: 20 additions & 0 deletions account_move_order_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["order_partner_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_order_partner:
keys.append("order_partner_id")
return keys
3 changes: 3 additions & 0 deletions account_move_order_partner/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
11 changes: 11 additions & 0 deletions account_move_order_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 order partner:

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

When enabled, invoices will only be grouped if the order partner is the same across all sale
orders. Even if the invoice partner is the same, sale orders with different order 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.
2 changes: 2 additions & 0 deletions account_move_order_partner/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Quartile \<<https://www.quartile.co>\>
- Aung Ko Ko Lin
2 changes: 2 additions & 0 deletions account_move_order_partner/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Adds the order partner (sold-to partner) to invoices and prints it on the report. If
multiple partners are involved, the sale partner defaults to the invoice partner.
46 changes: 46 additions & 0 deletions account_move_order_partner/reports/report_invoice_document.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template
id="report_invoice_order_partner"
inherit_id="account.report_invoice_document"
>
<xpath
expr="//div[@name='shipping_address_block']/strong"
position="attributes"
>
<attribute
name="t-if"
>o.order_partner_id != o.partner_shipping_id</attribute>
</xpath>
<xpath expr="//div[@name='shipping_address_block']/strong" position="after">
<t t-if="o.order_partner_id == o.partner_shipping_id">
<strong>Sold-to and Shipping Address:</strong>
</t>
</xpath>
<xpath
expr="//t[@t-if='o.partner_shipping_id and (o.partner_shipping_id != o.partner_id)']"
position="attributes"
>
<attribute
name="t-if"
>o.partner_shipping_id and (o.partner_shipping_id != o.partner_id) or o.order_partner_id and (o.order_partner_id != o.partner_id) and (o.order_partner_id != o.partner_shipping_id)</attribute>
</xpath>
<xpath expr="//div[@name='shipping_address_block']" position="before">
<div
t-if="o.order_partner_id and (o.order_partner_id != o.partner_id) and (o.order_partner_id != o.partner_shipping_id)"
name="order_partner"
>
<strong>Sold-to:</strong>
<div
t-field="o.order_partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'
/>
</div>
</xpath>
<xpath expr="//div[@name='shipping_address_block']" position="attributes">
<attribute
name="t-if"
>o.partner_shipping_id and (o.partner_shipping_id != o.partner_id)</attribute>
</xpath>
</template>
</odoo>
Loading