Initial commit: Akretion Odoo packages (2 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:49:21 +02:00
commit 087ad2c1de
54 changed files with 2381 additions and 0 deletions

View file

@ -0,0 +1,53 @@
# Account Invoice Margin
This module copies the field *standard_price* of the product on the invoice line when the invoice line is created. The allows the computation of the margin of the invoice.
A new measure *Margin* is available in the Invoice Analysis.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
## Installation
```bash
pip install odoo-bringout-akretion-account_invoice_margin
```
## Dependencies
This addon depends on:
- account
## Manifest Information
- **Name**: Account Invoice Margin
- **Version**: 16.0.1.0.0
- **Category**: Invoicing Management
- **License**: AGPL-3
- **Installable**: True
## Source
Custom addon from bringout-akretion vendor, addon `account_invoice_margin`.
## License
This package maintains the original AGPL-3 license from the addon.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1 @@
from . import models

View file

@ -0,0 +1,26 @@
# Copyright 2015-2025 Akretion France (https://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Invoice Margin',
'version': '16.0.1.0.0',
'category': 'Invoicing Management',
'license': 'AGPL-3',
'summary': 'Copy standard price on invoice line and compute margins',
'description': """
This module copies the field *standard_price* of the product on the invoice line when the invoice line is created. The allows the computation of the margin of the invoice.
A new measure *Margin* is available in the Invoice Analysis.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'https://github.com/akretion/odoo-usability',
'depends': ['account'],
'data': [
'views/account_move.xml',
],
'installable': True,
}

View file

@ -0,0 +1,98 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_invoice_margin
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-16 16:24+0000\n"
"PO-Revision-Date: 2025-01-16 16:24+0000\n"
"Last-Translator: Alexis de Lattre <alexis.delattre@akretion.com>\n"
"Language-Team: \n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_invoice_margin
#: model:ir.model,name:account_invoice_margin.model_account_invoice_report
msgid "Invoices Statistics"
msgstr "Statistiques des factures"
#. module: account_invoice_margin
#: model:ir.model,name:account_invoice_margin.model_account_move
msgid "Journal Entry"
msgstr "Pièce comptable"
#. module: account_invoice_margin
#: model:ir.model,name:account_invoice_margin.model_account_move_line
msgid "Journal Item"
msgstr "Écriture comptable"
#. module: account_invoice_margin
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_invoice_report__margin
#: model_terms:ir.ui.view,arch_db:account_invoice_margin.view_invoice_tree
#: model_terms:ir.ui.view,arch_db:account_invoice_margin.view_move_form
msgid "Margin"
msgstr "Marge"
#. module: account_invoice_margin
#: model_terms:ir.ui.view,arch_db:account_invoice_margin.view_move_form
msgid "Margin %"
msgstr "Marge %"
#. module: account_invoice_margin
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move_line__margin_rate
msgid "Margin Rate"
msgstr "Taux de marge"
#. module: account_invoice_margin
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_bank_statement_line__margin_company_currency
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move__margin_company_currency
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move_line__margin_company_currency
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_payment__margin_company_currency
msgid "Margin in Company Currency"
msgstr "Marge dans la devise de la société"
#. module: account_invoice_margin
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_bank_statement_line__margin_invoice_currency
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move__margin_invoice_currency
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move_line__margin_invoice_currency
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_payment__margin_invoice_currency
msgid "Margin in Invoice Currency"
msgstr "Marge dans la devise de la facture"
#. module: account_invoice_margin
#: model:ir.model.fields,help:account_invoice_margin.field_account_move_line__margin_rate
msgid "Margin rate in percentage of the sale price"
msgstr "Taux de marge en pourcentage du prix de vente"
#. module: account_invoice_margin
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move_line__standard_price_company_currency
msgid "Unit Cost in Company Currency"
msgstr "Coût unitaire dans la devise de la société"
#. module: account_invoice_margin
#: model:ir.model.fields,field_description:account_invoice_margin.field_account_move_line__standard_price_invoice_currency
msgid "Unit Cost in Invoice Currency"
msgstr "Coût unitaire dans la devise de la facture"
#. module: account_invoice_margin
#: model:ir.model.fields,help:account_invoice_margin.field_account_move_line__standard_price_company_currency
msgid ""
"Unit Cost in company currency in the unit of measure of the invoice line "
"(which may be different from the unit of measure of the product)."
msgstr ""
"Coût unitaire dans la devise de la société dans l'unité de mesure de la "
"ligne de facture (qui peut être différente de l'unité de mesure du produit)."
#. module: account_invoice_margin
#: model:ir.model.fields,help:account_invoice_margin.field_account_move_line__standard_price_invoice_currency
msgid ""
"Unit Cost in invoice currency in the unit of measure of the invoice line "
"(which may be different from the unit of measure of the product)."
msgstr ""
"Coût unitaire dans la devise de la facture dans l'unité de mesure "
"de la ligne de la facture (qui peut être différente de l'unité de mesure du produit)."

View file

@ -0,0 +1,2 @@
from . import account_move
from . import account_invoice_report

View file

@ -0,0 +1,17 @@
# Copyright 2018-2025 Akretion France (https://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class AccountInvoiceReport(models.Model):
_inherit = 'account.invoice.report'
margin = fields.Float(string='Margin', readonly=True)
@api.model
def _select(self):
select_str = super()._select()
select_str += ", line.margin_company_currency * currency_table.rate AS margin"
return select_str

View file

@ -0,0 +1,109 @@
# Copyright 2015-2025 Akretion France (https://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
standard_price_company_currency = fields.Float(
compute='_compute_margin', store=True, digits='Product Price',
string='Unit Cost in Company Currency',
help="Unit Cost in company currency in the unit of measure "
"of the invoice line (which may be different from the unit "
"of measure of the product).")
standard_price_invoice_currency = fields.Float(
compute='_compute_margin', store=True, digits='Product Price',
string='Unit Cost in Invoice Currency',
help="Unit Cost in invoice currency in the unit of measure "
"of the invoice line (which may be different from the unit "
"of measure of the product).")
margin_invoice_currency = fields.Monetary(
compute='_compute_margin', store=True,
string='Margin in Invoice Currency', currency_field='currency_id')
margin_company_currency = fields.Monetary(
compute='_compute_margin', store=True,
string='Margin in Company Currency',
currency_field='company_currency_id')
margin_rate = fields.Float(
string="Margin Rate", readonly=True, store=True,
compute='_compute_margin',
digits=(16, 2), help="Margin rate in percentage of the sale price")
@api.depends(
'product_id', 'product_uom_id', 'display_type', 'quantity', 'price_subtotal',
'move_id.currency_id', 'move_id.move_type', 'move_id.company_id', 'move_id.date')
def _compute_margin(self):
for ml in self:
standard_price_comp_cur = 0.0
standard_price_inv_cur = 0.0
margin_inv_cur = 0.0
margin_comp_cur = 0.0
margin_rate = 0.0
if (
ml.display_type == 'product' and
ml.product_id and
ml.move_type in ('out_invoice', 'out_refund')):
move = ml.move_id
date = move.date
company = move.company_id
company_currency = company.currency_id
move_currency = move.currency_id
standard_price_comp_cur = ml.product_id.with_company(company.id).standard_price
if ml.product_uom_id and ml.product_uom_id != ml.product_id.uom_id:
standard_price_comp_cur = ml.product_id.uom_id._compute_price(
standard_price_comp_cur, ml.product_uom_id)
standard_price_inv_cur = company_currency._convert(
standard_price_comp_cur, move_currency, company, date)
margin_inv_cur =\
ml.price_subtotal - (ml.quantity * standard_price_inv_cur)
margin_comp_cur = move_currency._convert(
margin_inv_cur, company_currency, company, date)
if ml.price_subtotal:
margin_rate = 100 * margin_inv_cur / ml.price_subtotal
# for a refund, margin should be negative
# but margin rate should stay positive
if ml.move_type == 'out_refund':
margin_inv_cur *= -1
margin_comp_cur *= -1
ml.standard_price_company_currency = standard_price_comp_cur
ml.standard_price_invoice_currency = standard_price_inv_cur
ml.margin_invoice_currency = margin_inv_cur
ml.margin_company_currency = margin_comp_cur
ml.margin_rate = margin_rate
class AccountMove(models.Model):
_inherit = 'account.move'
margin_invoice_currency = fields.Monetary(
string='Margin in Invoice Currency',
compute='_compute_margin', store=True,
currency_field='currency_id')
margin_company_currency = fields.Monetary(
string='Margin in Company Currency',
compute='_compute_margin', store=True,
currency_field='company_currency_id')
@api.depends(
'move_type',
'invoice_line_ids.margin_invoice_currency',
'invoice_line_ids.margin_company_currency')
def _compute_margin(self):
rg_res = self.env['account.move.line'].read_group(
[
('move_id', 'in', self.ids),
('display_type', '=', 'product'),
('move_id.move_type', 'in', ('out_invoice', 'out_refund')),
],
['move_id', 'margin_invoice_currency:sum', 'margin_company_currency:sum'],
['move_id'])
mapped_data = dict([(x['move_id'][0], {
'margin_invoice_currency': x['margin_invoice_currency'],
'margin_company_currency': x['margin_company_currency'],
}) for x in rg_res])
for move in self:
move.margin_invoice_currency = mapped_data.get(move.id, {}).get('margin_invoice_currency')
move.margin_company_currency = mapped_data.get(move.id, {}).get('margin_company_currency')

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2025 Akretion (https://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_move_form" model="ir.ui.view">
<field name="name">margin.account.move.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<group name="sale_info_group" position="inside">
<field name="margin_invoice_currency"
groups="base.group_no_one"
attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<field name="margin_company_currency"
groups="base.group_no_one"
attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</group>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='price_total']" position="after">
<field name="standard_price_invoice_currency" optional="hide" attrs="{'column_invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<field name="margin_invoice_currency" optional="hide" attrs="{'column_invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}" string="Margin"/>
<field name="margin_rate" optional="hide" string="Margin %" attrs="{'column_invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</xpath>
<xpath expr="//field[@name='invoice_line_ids']/form//field[@name='price_total']/.." position="inside">
<field name="standard_price_company_currency"
groups="base.group_no_one" attrs="{'invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<field name="standard_price_invoice_currency"
groups="base.group_no_one" attrs="{'invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<field name="margin_invoice_currency"
groups="base.group_no_one" attrs="{'invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<field name="margin_company_currency"
groups="base.group_no_one" attrs="{'invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<label for="margin_rate" groups="base.group_no_one" attrs="{'invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
<div name="margin_rate" groups="base.group_no_one" attrs="{'invisible': [('parent.move_type', 'not in', ('out_invoice', 'out_refund'))]}">
<field name="margin_rate" class="oe_inline"/> %
</div>
</xpath>
</field>
</record>
<record id="view_invoice_tree" model="ir.ui.view">
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_invoice_tree"/>
<field name="arch" type="xml">
<field name="amount_residual_signed" position="after">
<field name="margin_company_currency" optional="hide" sum="1" invisible="context.get('default_move_type') not in ('out_invoice', 'out_refund')" string="Margin"/>
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Account_invoice_margin Module - account_invoice_margin
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for account_invoice_margin. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,5 @@
# Dependencies
This addon depends on:
- [account](../../odoo-bringout-oca-ocb-account)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon account_invoice_margin or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-akretion-account_invoice_margin"
# or
uv pip install odoo-bringout-akretion-account_invoice_margin"
```

View file

@ -0,0 +1,14 @@
# Models
Detected core models and extensions in account_invoice_margin.
```mermaid
classDiagram
class account_invoice_report
class account_move
class account_move_line
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: account_invoice_margin. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon account_invoice_margin
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,8 @@
# Security
This module does not define custom security rules or access controls beyond Odoo defaults.
Default Odoo security applies:
- Base user access through standard groups
- Model access inherited from dependencies
- No custom row-level security rules

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon account_invoice_margin
```

View file

@ -0,0 +1,3 @@
# Wizards
This module does not include UI wizards.

View file

@ -0,0 +1,42 @@
[project]
name = "odoo-bringout-akretion-account_invoice_margin"
version = "16.0.0"
description = "Account Invoice Margin - Copy standard price on invoice line and compute margins"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-ocb-account>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["account_invoice_margin"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]