Initial commit: Odoo 18.0-20251222 extra-addons
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled

This commit is contained in:
tocmo0nlord
2026-03-13 20:43:25 +00:00
parent 36e847a7df
commit adbe430761
9472 changed files with 1265727 additions and 0 deletions

113
sale_fixed_discount/README.rst Executable file
View File

@@ -0,0 +1,113 @@
===================
Sale Fixed Discount
===================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:9fbc48c4968018c610d6befda6c7804ced8212bb8b51c5a1f3bb97d9cde0baad
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/18.0/sale_fixed_discount
:alt: OCA/sale-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/sale-workflow-18-0/sale-workflow-18-0-sale_fixed_discount
: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/sale-workflow&target_branch=18.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends the functionality of Sales to allow you to apply
fixed amount discount at sales order line level.
The module also extends the sales order report to show fixed discount.
**Table of contents**
.. contents::
:local:
Installation
============
This module depends on module 'account_invoice_fixed_discount',
available in
https://github.com/OCA/account-invoicing/tree/18.0/account_invoice_fixed_discount
Configuration
=============
To configure this module, you need to:
1. Go to *Sales > Configuration > Settings*.
2. In the *Pricing* section select *Discounts* option to grant discounts
on sales order lines.
Usage
=====
To use this module, you need to:
1. Go to *Sales*.
2. Create a Sales Order and specify the type of discount and
fixed/percent discount in a line.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/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/sale-workflow/issues/new?body=module:%20sale_fixed_discount%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
Contributors
------------
- Lois Rilo <lois.rilo@forgeflow.com>
(`www.forgeflow.com <http://www.forgeflow.com>`__)
- Jordi Ballester <jordi.ballester@forgeflow.com>
(`www.forgeflow.com <http://www.forgeflow.com>`__)
- Pieter Paulussen <pieterpaulussen@code-source.be>
(`www.code-source.be <http://www.code-source.be>`__)
- OERP Canada <https://www.oerp.ca/>:
- Foram Darji <fd@oerp.ca>
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/sale-workflow <https://github.com/OCA/sale-workflow/tree/18.0/sale_fixed_discount>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

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

View File

@@ -0,0 +1,21 @@
# Copyright 2017-20 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Sale Fixed Discount",
"summary": "Allows to apply fixed amount discounts in sales orders.",
"version": "18.0.1.0.0",
"category": "Sales",
"website": "https://github.com/OCA/sale-workflow",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": ["sale", "account_invoice_fixed_discount"],
"data": [
"security/res_groups.xml",
"reports/report_sale_order.xml",
"views/account_invoice_views.xml",
"views/sale_order_views.xml",
"views/sale_portal_templates.xml",
],
}

78
sale_fixed_discount/i18n/es.po Executable file
View File

@@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_fixed_discount
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-02-14 17:32+0000\n"
"PO-Revision-Date: 2024-04-23 08:39+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> %)</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> (or</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.sale_order_portal_content
msgid "<span>Disc. Fixed Amount</span>"
msgstr "<span>Desc. Monto fijo</span>"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span>Discount Amount (%)</span>"
msgstr "<span>Importe del descuento (%)</span>"
#. module: sale_fixed_discount
#: model:ir.model.fields,field_description:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Discount (Fixed)"
msgstr "Descuento (Fijo)"
#. module: sale_fixed_discount
#: model:ir.model.fields,help:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Fixed amount discount."
msgstr "Importe fijo de descuento."
#. module: sale_fixed_discount
#: model:ir.model,name:sale_fixed_discount.model_sale_order_line
msgid "Sales Order Line"
msgstr "Línea Pedido de Venta"
#. module: sale_fixed_discount
#. odoo-python
#: code:addons/sale_fixed_discount/models/sale_order_line.py:0
#, python-format
msgid ""
"The fixed discount %(fixed)s does not match the calculateddiscount "
"%(discount)s %%.Please correct one of the discounts."
msgstr ""
"El descuento fijo %(fixed)s no coincide con el descuento calculado "
"%(discount)s %%.Por favor, corrija uno de los descuentos."
#~ msgid "(or"
#~ msgstr "(o"
#~ msgid "<span>Disc. %</span>"
#~ msgstr "<span>Desc. %</span>"
#, python-format
#~ msgid ""
#~ "The fixed discount %(fixed)s does not match the calculated discount "
#~ "%(discount)s %%. Please correct one of the discounts."
#~ msgstr ""
#~ "El descuento fijo %(fixed)s no coincide con el descuento calculado "
#~ "%(discount)s %%. Por favor, corrija uno de los descuentos."

61
sale_fixed_discount/i18n/fr.po Executable file
View File

@@ -0,0 +1,61 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_fixed_discount
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-02-14 17:31+0000\n"
"PO-Revision-Date: 2024-02-14 17:31+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> %)</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> (or</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.sale_order_portal_content
msgid "<span>Disc. Fixed Amount</span>"
msgstr "<span>Remise en montant fixe</span>"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span>Discount Amount (%)</span>"
msgstr ""
#. module: sale_fixed_discount
#: model:ir.model.fields,field_description:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Discount (Fixed)"
msgstr "Remise (fixe)"
#. module: sale_fixed_discount
#: model:ir.model.fields,help:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Fixed amount discount."
msgstr "Remise en montant fixe."
#. module: sale_fixed_discount
#: model:ir.model,name:sale_fixed_discount.model_sale_order_line
msgid "Sales Order Line"
msgstr "Ligne de bons de commande"
#. module: sale_fixed_discount
#. odoo-python
#: code:addons/sale_fixed_discount/models/sale_order_line.py:0
#, python-format
msgid ""
"The fixed discount %(fixed)s does not match the calculateddiscount "
"%(discount)s %%.Please correct one of the discounts."
msgstr ""

78
sale_fixed_discount/i18n/it.po Executable file
View File

@@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_fixed_discount
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-02-14 17:30+0000\n"
"PO-Revision-Date: 2024-06-12 16:38+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: \n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> %)</span>"
msgstr "<span class=\"text-nowrap\"> %)</span>"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> (or</span>"
msgstr "<span class=\"text-nowrap\"> (o</span>"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.sale_order_portal_content
msgid "<span>Disc. Fixed Amount</span>"
msgstr "<span>Importo sconto fisso</span>"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span>Discount Amount (%)</span>"
msgstr "<span>Valore sconto (%)</span>"
#. module: sale_fixed_discount
#: model:ir.model.fields,field_description:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Discount (Fixed)"
msgstr "Sconto (fisso)"
#. module: sale_fixed_discount
#: model:ir.model.fields,help:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Fixed amount discount."
msgstr "Importo sconto fisso."
#. module: sale_fixed_discount
#: model:ir.model,name:sale_fixed_discount.model_sale_order_line
msgid "Sales Order Line"
msgstr "Riga ordine di vendita"
#. module: sale_fixed_discount
#. odoo-python
#: code:addons/sale_fixed_discount/models/sale_order_line.py:0
#, python-format
msgid ""
"The fixed discount %(fixed)s does not match the calculateddiscount "
"%(discount)s %%.Please correct one of the discounts."
msgstr ""
"Lo sconto fisso %(fixed)s non corrisponde allo sconto calcolato %(discount)s "
"%%. Correggere uno degli sconti."
#~ msgid "(or"
#~ msgstr "(o"
#~ msgid "<span>Disc. %</span>"
#~ msgstr "<span>Sconto %</span>"
#, python-format
#~ msgid ""
#~ "The fixed discount %(fixed)s does not match the calculated discount "
#~ "%(discount)s %%. Please correct one of the discounts."
#~ msgstr ""
#~ "Lo sconto fisso %(fixed)s non corrisponde allo sconto calcolato "
#~ "%(discount)s %%. Correggere uno degli sconti."

View File

@@ -0,0 +1,75 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_fixed_discount
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-02-14 17:29+0000\n"
"PO-Revision-Date: 2024-02-14 17:29+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> %)</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> (or</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.sale_order_portal_content
msgid "<span>Disc. Fixed Amount</span>"
msgstr "<span>Desc. Valor</span>"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span>Discount Amount (%)</span>"
msgstr "<span>Valor Desconto (%)</span>"
#. module: sale_fixed_discount
#: model:ir.model.fields,field_description:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Discount (Fixed)"
msgstr "Desconto (Fixo)"
#. module: sale_fixed_discount
#: model:ir.model.fields,help:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Fixed amount discount."
msgstr "Desconto Valor Fixo."
#. module: sale_fixed_discount
#: model:ir.model,name:sale_fixed_discount.model_sale_order_line
msgid "Sales Order Line"
msgstr "Linha Pedido de Venda"
#. module: sale_fixed_discount
#. odoo-python
#: code:addons/sale_fixed_discount/models/sale_order_line.py:0
#, python-format
msgid ""
"The fixed discount %(fixed)s does not match the calculateddiscount "
"%(discount)s %%.Please correct one of the discounts."
msgstr ""
#~ msgid "(or"
#~ msgstr "(ou"
#~ msgid "<span>Disc. %</span>"
#~ msgstr "<span>Desc. %</span>"
#, python-format
#~ msgid ""
#~ "The fixed discount %(fixed)s does not match the calculated discount "
#~ "%(discount)s %%. Please correct one of the discounts."
#~ msgstr ""
#~ "O desconto fixo %(fixed)s não corresponde ao desconto calculado "
#~ "%(discount)s %%. Corrija um dos descontos."

View File

@@ -0,0 +1,57 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_fixed_discount
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> %)</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span class=\"text-nowrap\"> (or</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.sale_order_portal_content
msgid "<span>Disc. Fixed Amount</span>"
msgstr ""
#. module: sale_fixed_discount
#: model_terms:ir.ui.view,arch_db:sale_fixed_discount.report_saleorder_document
msgid "<span>Discount Amount (%)</span>"
msgstr ""
#. module: sale_fixed_discount
#: model:ir.model.fields,field_description:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Discount (Fixed)"
msgstr ""
#. module: sale_fixed_discount
#: model:ir.model.fields,help:sale_fixed_discount.field_sale_order_line__discount_fixed
msgid "Fixed amount discount."
msgstr ""
#. module: sale_fixed_discount
#: model:ir.model,name:sale_fixed_discount.model_sale_order_line
msgid "Sales Order Line"
msgstr ""
#. module: sale_fixed_discount
#. odoo-python
#: code:addons/sale_fixed_discount/models/sale_order_line.py:0
msgid ""
"The fixed discount %(fixed)s does not match the calculateddiscount "
"%(discount)s %%.Please correct one of the discounts."
msgstr ""

View File

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

View File

@@ -0,0 +1,104 @@
# Copyright 2017-20 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare, float_round
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
discount_fixed = fields.Float(
string="Discount (Fixed)",
digits="Product Price",
help="Fixed amount discount.",
)
@api.constrains("discount_fixed", "discount")
def _check_discounts(self):
"""Check that the fixed discount and the discount percentage are consistent."""
for line in self:
if line.discount_fixed and line.discount:
currency = line.currency_id
calculated_fixed_discount = float_round(
line._get_discount_from_fixed_discount(),
precision_rounding=currency.rounding,
)
if (
float_compare(
calculated_fixed_discount,
line.discount,
precision_rounding=currency.rounding,
)
!= 0
):
raise ValidationError(
self.env._(
"The fixed discount %(fixed)s does not match the calculated"
"discount %(discount)s %%."
"Please correct one of the discounts.",
fixed=line.discount_fixed,
discount=line.discount,
)
)
def _prepare_base_line_for_taxes_computation(self, **kwargs):
"""Prior to calculating the tax toals for a line, update the discount value
used in the tax calculation to the full float value. Otherwise, we get rounding
errors in the resulting calculated totals.
For example:
- price_unit = 750.0
- discount_fixed = 100.0
- discount = 13.33
=> price_subtotal = 650.03
:return: A python dictionary.
"""
self.ensure_one()
# Accurately pass along the fixed discount amount to the tax computation method.
if self.discount_fixed:
return self.env["account.tax"]._prepare_base_line_for_taxes_computation(
self,
**{
"tax_ids": self.tax_id,
"quantity": self.product_uom_qty,
"partner_id": self.order_id.partner_id,
"currency_id": self.order_id.currency_id
or self.order_id.company_id.currency_id,
"rate": self.order_id.currency_rate,
"discount": self._get_discount_from_fixed_discount(),
**kwargs,
},
)
return super()._prepare_base_line_for_taxes_computation(**kwargs)
@api.depends("discount_fixed", "price_unit")
def _compute_discount(self):
lines_with_discount_fixed = self.filtered(lambda sol: sol.discount_fixed)
for line in lines_with_discount_fixed:
line.discount = line._get_discount_from_fixed_discount()
return super(
SaleOrderLine, self - lines_with_discount_fixed
)._compute_discount()
def _get_discount_from_fixed_discount(self):
"""Calculate the discount percentage from the fixed discount amount."""
self.ensure_one()
if not self.discount_fixed:
return 0.0
return (
(self.price_unit != 0)
and ((self.discount_fixed) / self.price_unit) * 100
or 0.00
)
def _prepare_invoice_line(self, **optional_values):
res = super()._prepare_invoice_line(**optional_values)
res.update({"discount_fixed": self.discount_fixed})
return res

View File

@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"

View File

@@ -0,0 +1,5 @@
To configure this module, you need to:
1. Go to *Sales \> Configuration \> Settings*.
2. In the *Pricing* section select *Discounts* option to grant
discounts on sales order lines.

View File

@@ -0,0 +1,7 @@
- Lois Rilo \<<lois.rilo@forgeflow.com>\> (www.forgeflow.com)
- Jordi Ballester \<<jordi.ballester@forgeflow.com>\>
(www.forgeflow.com)
- Pieter Paulussen \<<pieterpaulussen@code-source.be>\>
(www.code-source.be)
* OERP Canada \<<https://www.oerp.ca/>\>:
- Foram Darji \<<fd@oerp.ca>\>

View File

@@ -0,0 +1,4 @@
This module extends the functionality of Sales to allow you to apply
fixed amount discount at sales order line level.
The module also extends the sales order report to show fixed discount.

View File

@@ -0,0 +1,3 @@
This module depends on module 'account_invoice_fixed_discount',
available in
<https://github.com/OCA/account-invoicing/tree/18.0/account_invoice_fixed_discount>

View File

@@ -0,0 +1,5 @@
To use this module, you need to:
1. Go to *Sales*.
2. Create a Sales Order and specify the type of discount and
fixed/percent discount in a line.

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017-20 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<template
id="report_saleorder_document"
inherit_id="sale.report_saleorder_document"
>
<xpath expr="//t[@t-set='display_discount']" position="after">
<t
t-set="display_discount_fixed"
t-value="any([l.discount_fixed for l in doc.order_line])"
/>
</xpath>
<xpath expr="//th[@name='th_discount']/span" position="attributes">
<attribute name="t-if">not display_discount_fixed</attribute>
</xpath>
<xpath expr="//th[@t-if='display_discount']/span" position="before">
<t t-if="display_discount_fixed">
<span>Discount Amount (%)</span>
</t>
</xpath>
<span t-field="line.discount" position="before">
<t t-if="display_discount_fixed">
<span class="text-nowrap" t-field="line.discount_fixed" />
<span class="text-nowrap"> (or</span>
</t>
</span>
<span t-field="line.discount" position="after">
<t t-if="display_discount_fixed">
<span class="text-nowrap"> %)</span>
</t>
</span>
</template>
</odoo>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo noupdate="1">
<record id="sale.group_discount_per_so_line" model="res.groups">
<field
name="implied_ids"
eval="[(4, ref('account_invoice_fixed_discount.group_fixed_discount'))]"
/>
</record>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,461 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Sale Fixed Discount</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="sale-fixed-discount">
<h1 class="title">Sale Fixed Discount</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:9fbc48c4968018c610d6befda6c7804ced8212bb8b51c5a1f3bb97d9cde0baad
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/sale-workflow/tree/18.0/sale_fixed_discount"><img alt="OCA/sale-workflow" src="https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/sale-workflow-18-0/sale-workflow-18-0-sale_fixed_discount"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module extends the functionality of Sales to allow you to apply
fixed amount discount at sales order line level.</p>
<p>The module also extends the sales order report to show fixed discount.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-3">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>This module depends on module account_invoice_fixed_discount,
available in
<a class="reference external" href="https://github.com/OCA/account-invoicing/tree/18.0/account_invoice_fixed_discount">https://github.com/OCA/account-invoicing/tree/18.0/account_invoice_fixed_discount</a></p>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1>
<p>To configure this module, you need to:</p>
<ol class="arabic simple">
<li>Go to <em>Sales &gt; Configuration &gt; Settings</em>.</li>
<li>In the <em>Pricing</em> section select <em>Discounts</em> option to grant discounts
on sales order lines.</li>
</ol>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1>
<p>To use this module, you need to:</p>
<ol class="arabic simple">
<li>Go to <em>Sales</em>.</li>
<li>Create a Sales Order and specify the type of discount and
fixed/percent discount in a line.</li>
</ol>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/sale-workflow/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_fixed_discount%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-6">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<ul class="simple">
<li>Lois Rilo &lt;<a class="reference external" href="mailto:lois.rilo&#64;forgeflow.com">lois.rilo&#64;forgeflow.com</a>&gt;
(<a class="reference external" href="http://www.forgeflow.com">www.forgeflow.com</a>)</li>
<li>Jordi Ballester &lt;<a class="reference external" href="mailto:jordi.ballester&#64;forgeflow.com">jordi.ballester&#64;forgeflow.com</a>&gt;
(<a class="reference external" href="http://www.forgeflow.com">www.forgeflow.com</a>)</li>
<li>Pieter Paulussen &lt;<a class="reference external" href="mailto:pieterpaulussen&#64;code-source.be">pieterpaulussen&#64;code-source.be</a>&gt;
(<a class="reference external" href="http://www.code-source.be">www.code-source.be</a>)</li>
<li>OERP Canada &lt;<a class="reference external" href="https://www.oerp.ca/">https://www.oerp.ca/</a>&gt;:<ul>
<li>Foram Darji &lt;<a class="reference external" href="mailto:fd&#64;oerp.ca">fd&#64;oerp.ca</a>&gt;</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/sale-workflow/tree/18.0/sale_fixed_discount">OCA/sale-workflow</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

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

View File

@@ -0,0 +1,137 @@
# Copyright 2017-18 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.exceptions import ValidationError
from odoo.tests import Form
from odoo.addons.base.tests.common import BaseCommon
class TestSaleFixedDiscount(BaseCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env.user.groups_id |= cls.env.ref("sale.group_discount_per_so_line")
cls.partner = cls.env["res.partner"].create({"name": "Test"})
cls.tax = cls.env["account.tax"].create(
{
"name": "TAX 15%",
"amount_type": "percent",
"type_tax_use": "sale",
"amount": 15.0,
}
)
cls.product = cls.env["product.product"].create(
{"name": "Test product", "type": "consu"}
)
cls.product2 = cls.env["product.product"].create(
{"name": "Test product 2", "type": "consu"}
)
cls.sale = cls.env["sale.order"].create(
{"name": "Test Sale Order", "partner_id": cls.partner.id}
)
cls.so_line = cls.env["sale.order.line"]
cls.sale_line1 = cls.so_line.create(
{
"order_id": cls.sale.id,
"name": "Line 1",
"price_unit": 200.0,
"product_uom_qty": 1,
"product_id": cls.product.id,
"tax_id": [(6, 0, [cls.tax.id])],
}
)
def test_01_discounts(self):
"""Tests multiple discounts in line with taxes."""
with Form(self.sale) as sale_order:
with sale_order.order_line.edit(0) as line:
line.discount_fixed = 20.0
self.assertEqual(line.discount, 10.0)
self.assertEqual(line.price_subtotal, 180.0)
self.assertEqual(self.sale.amount_total, 207.00)
with Form(self.sale) as sale_order:
with sale_order.order_line.edit(0) as line:
line.product_uom_qty = 2
line.price_unit = 200.0
self.assertEqual(line.discount, 10.0)
self.assertEqual(line.price_subtotal, 360.0)
self.assertEqual(self.sale.amount_total, 414.00)
with Form(self.sale) as sale_order:
with sale_order.order_line.edit(0) as line:
line.product_uom_qty = 1
line.price_unit = 200.0
line.discount_fixed = 0.0
line.discount = 50.0
self.assertEqual(line.price_subtotal, 100.0)
self.assertEqual(self.sale.amount_total, 115.00)
with Form(self.sale) as sale_order:
with sale_order.order_line.new() as line2:
line2.product_id = self.product2
line2.product_uom_qty = 1
line2.price_unit = 100.0
line2.discount_fixed = 5.0
self.assertEqual(line2.discount, 5.0)
self.assertEqual(line2.price_subtotal, 95.0)
#
self.assertEqual(self.sale.amount_total, 224.25)
def test_02_fixed_discount_mismatch(self):
"""Tests fixed discount mismatch."""
with self.assertRaisesRegex(
ValidationError,
"Please correct one of the discounts",
):
with Form(self.sale) as sale_order:
with sale_order.order_line.edit(0) as line:
line.discount_fixed = 20.0
line.discount = 5.0
def test_03_fixed_discount_invoice(self):
"""Test discount_fixed value propagation to account.move.
Case of editing order line by using UI.
"""
with Form(self.sale) as sale_order:
with sale_order.order_line.edit(0) as line:
line.discount_fixed = 20.0
self.sale.action_confirm()
self.sale._create_invoices()
self.assertEqual(self.sale.invoice_ids.invoice_line_ids.discount_fixed, 20.0)
self.assertEqual(self.sale.invoice_ids.invoice_line_ids.discount, 10.0)
self.assertEqual(self.sale.invoice_ids.tax_totals["base_amount"], 180.0)
self.assertEqual(self.sale.invoice_ids.tax_totals["total_amount"], 207.0)
def test_04_fixed_discount_without_price(self):
with Form(self.sale) as sale_order:
with sale_order.order_line.edit(0) as line:
line.product_uom_qty = 1.0
line.price_unit = 0.0
line.discount_fixed = 50.0
self.assertEqual(line.discount, 0.0)
self.assertEqual(line.price_subtotal, 0.0)
self.assertEqual(self.sale.amount_total, 0.0)
def test_05_fixed_discount_invoice(self):
"""Test discount_fixed value propagation to account.move.
Case of editing order line without using UI (onchange would be not triggered).
"""
self.sale.order_line.discount_fixed = 20.0
self.sale.action_confirm()
self.sale._create_invoices()
self.assertEqual(self.sale.invoice_ids.invoice_line_ids.discount_fixed, 20.0)
self.assertEqual(self.sale.invoice_ids.invoice_line_ids.discount, 10.0)
self.assertEqual(self.sale.invoice_ids.tax_totals["base_amount"], 180.0)
self.assertEqual(self.sale.invoice_ids.tax_totals["total_amount"], 207.0)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Update account invoice !-->
<record id="view_move_form" model="ir.ui.view">
<field name="name">account.move - </field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account_invoice_fixed_discount.view_move_form" />
<field name="arch" type="xml">
<field name="discount_fixed" position="attributes">
<attribute name="groups">sale.group_discount_per_so_line</attribute>
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017-20 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_order_form" model="ir.ui.view">
<field name="name">sale.order.form - sale_fixed_discount</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<xpath
expr="//field[@name='order_line']/form//label[@for='discount']"
position="before"
>
<field name="discount_fixed" groups="sale.group_discount_per_so_line" />
</xpath>
<xpath
expr="//field[@name='order_line']/list/field[@name='discount']"
position="before"
>
<field name="discount_fixed" groups="sale.group_discount_per_so_line" />
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template
id="sale_order_portal_content"
inherit_id="sale.sale_order_portal_content"
>
<xpath
expr="//section[@id='details']//t[@t-set='display_discount']"
position="after"
>
<t
t-set="display_discount_fixed"
t-value="True in [line.discount_fixed > 0 for line in sale_order.order_line]"
/>
</xpath>
<xpath
expr="//section[@id='details']//table/thead//th[@t-if='display_discount']"
position="before"
>
<th
t-if="display_discount_fixed"
t-attf-class="text-end {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}"
>
<span>Disc. Fixed Amount</span>
</th>
</xpath>
<xpath expr="//div[@t-field='line.price_unit']" position="attributes">
<attribute
name="t-if"
>line.discount &gt;= 0 or line.fixed_discount &gt;= 0</attribute>
<attribute
name="t-att-style"
>(line.discount or line.discount_fixed) and 'text-decoration: line-through' or None</attribute>
<attribute
name="t-att-class"
>((line.discount or line.discount_fixed) and 'text-danger' or '') + ' text-right'</attribute>
</xpath>
<xpath expr="//div[@t-if='line.discount']/t" position="attributes">
<attribute name="t-out">line.price_unit - line.discount_fixed</attribute>
</xpath>
<xpath expr="//td[@t-if='display_discount']" position="before">
<td
t-if="display_discount_fixed"
t-attf-class="text-end {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}"
>
<strong t-if="line.discount_fixed &gt; 0" class="text-info">
<t t-esc="line.discount_fixed" />
</strong>
</td>
</xpath>
</template>
</odoo>