[ADD] create sale_order_invoice_untaxed_amount add-on
This commit is contained in:
2
sale_order_invoice_untaxed_amount/.gitignore
vendored
Normal file
2
sale_order_invoice_untaxed_amount/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.*~
|
||||
*pyc
|
43
sale_order_invoice_untaxed_amount/README.rst
Normal file
43
sale_order_invoice_untaxed_amount/README.rst
Normal file
@@ -0,0 +1,43 @@
|
||||
=================================
|
||||
sale_order_invoice_untaxed_amount
|
||||
=================================
|
||||
|
||||
Display the invoiced and uninvoiced untaxed total in the sale order
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Use Odoo normal module installation procedure to install
|
||||
``sale_order_invoice_untaxed_amount``.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
None yet.
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `our issues website <https://github.com/elabore-coop/sale-tools/issues>`_. In case of
|
||||
trouble, please check there if your issue has already been
|
||||
reported. If you spotted it first, help us smashing it by providing a
|
||||
detailed and welcomed feedback.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Stéphan Sainléger
|
||||
|
||||
Funders
|
||||
-------
|
||||
|
||||
The development of this module has been financially supported by:
|
||||
* Elabore (https://elabore.coop)
|
||||
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
This module is maintained by Elabore.
|
4
sale_order_invoice_untaxed_amount/__init__.py
Normal file
4
sale_order_invoice_untaxed_amount/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
|
37
sale_order_invoice_untaxed_amount/__manifest__.py
Normal file
37
sale_order_invoice_untaxed_amount/__manifest__.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright 2022 Stéphan Sainléger (Elabore)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
"name": "sale_order_invoice_untaxed_amount",
|
||||
"version": "14.0.1.0.0",
|
||||
"author": "Elabore",
|
||||
"website": "https://elabore.coop",
|
||||
"maintainer": "Stéphan Sainléger",
|
||||
"license": "AGPL-3",
|
||||
"category": "Tools",
|
||||
"summary": "Display the invoiced and uninvoiced untaxed total in the sale order",
|
||||
# any module necessary for this one to work correctly
|
||||
"depends": [
|
||||
"account",
|
||||
"sale",
|
||||
],
|
||||
"qweb": [
|
||||
# "static/src/xml/*.xml",
|
||||
],
|
||||
"external_dependencies": {
|
||||
"python": [],
|
||||
},
|
||||
# always loaded
|
||||
"data": [
|
||||
"views/sale_order_view.xml",
|
||||
],
|
||||
# only loaded in demonstration mode
|
||||
"demo": [],
|
||||
"js": [],
|
||||
"css": [],
|
||||
"installable": True,
|
||||
# Install this module automatically if all dependency have been previously
|
||||
# and independently installed. Used for synergetic or glue modules.
|
||||
"auto_install": False,
|
||||
"application": False,
|
||||
}
|
1
sale_order_invoice_untaxed_amount/i18n/README
Normal file
1
sale_order_invoice_untaxed_amount/i18n/README
Normal file
@@ -0,0 +1 @@
|
||||
This directory should contain the *.po for Odoo translation.
|
56
sale_order_invoice_untaxed_amount/i18n/fr.po
Normal file
56
sale_order_invoice_untaxed_amount/i18n/fr.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * sale_order_invoice_untaxed_amount
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-12-02 08:32+0000\n"
|
||||
"PO-Revision-Date: 2022-12-02 08:32+0000\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_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nom affiché"
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__invoiced_untaxed_amount
|
||||
msgid "Invoiced Untaxed Amount"
|
||||
msgstr "Facturé HT"
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model_terms:ir.ui.view,arch_db:sale_order_invoice_untaxed_amount.view_order_tree_invoiced_untaxed_amount
|
||||
msgid "Invoiced Untaxed Total"
|
||||
msgstr "Facturé HT Total"
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Dernière modification le"
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model,name:sale_order_invoice_untaxed_amount.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr "Bon de commande"
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__uninvoiced_untaxed_amount
|
||||
msgid "Uninvoiced Untaxed Amount"
|
||||
msgstr "Non-facturé HT"
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model_terms:ir.ui.view,arch_db:sale_order_invoice_untaxed_amount.view_order_tree_invoiced_untaxed_amount
|
||||
msgid "Uninvoiced Untaxed Total"
|
||||
msgstr "Non-facturé HT Total"
|
@@ -0,0 +1,56 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * sale_order_invoice_untaxed_amount
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-12-02 08:33+0000\n"
|
||||
"PO-Revision-Date: 2022-12-02 08:33+0000\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_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__invoiced_untaxed_amount
|
||||
msgid "Invoiced Untaxed Amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model_terms:ir.ui.view,arch_db:sale_order_invoice_untaxed_amount.view_order_tree_invoiced_untaxed_amount
|
||||
msgid "Invoiced Untaxed Total"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model,name:sale_order_invoice_untaxed_amount.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model:ir.model.fields,field_description:sale_order_invoice_untaxed_amount.field_sale_order__uninvoiced_untaxed_amount
|
||||
msgid "Uninvoiced Untaxed Amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_order_invoice_untaxed_amount
|
||||
#: model_terms:ir.ui.view,arch_db:sale_order_invoice_untaxed_amount.view_order_tree_invoiced_untaxed_amount
|
||||
msgid "Uninvoiced Untaxed Total"
|
||||
msgstr ""
|
1
sale_order_invoice_untaxed_amount/models/__init__.py
Normal file
1
sale_order_invoice_untaxed_amount/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import sale_order
|
43
sale_order_invoice_untaxed_amount/models/sale_order.py
Normal file
43
sale_order_invoice_untaxed_amount/models/sale_order.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Copyright (C) 2021 ForgeFlow S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
|
||||
_inherit = "sale.order"
|
||||
|
||||
invoiced_untaxed_amount = fields.Monetary(
|
||||
string="Invoiced Untaxed Amount",
|
||||
compute="_compute_invoice_untaxed_amount",
|
||||
store=True,
|
||||
)
|
||||
|
||||
uninvoiced_untaxed_amount = fields.Monetary(
|
||||
string="Uninvoiced Untaxed Amount",
|
||||
compute="_compute_invoice_untaxed_amount",
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"state",
|
||||
"invoice_ids",
|
||||
"invoice_ids.amount_untaxed_signed",
|
||||
"amount_total",
|
||||
"invoice_ids.state",
|
||||
)
|
||||
def _compute_invoice_untaxed_amount(self):
|
||||
for rec in self:
|
||||
if rec.state != "cancel" and rec.invoice_ids:
|
||||
rec.invoiced_untaxed_amount = 0.0
|
||||
for invoice in rec.invoice_ids:
|
||||
if invoice.state != "cancel":
|
||||
rec.invoiced_untaxed_amount += invoice.amount_untaxed_signed
|
||||
rec.uninvoiced_untaxed_amount = max(0, rec.amount_untaxed - rec.invoiced_untaxed_amount)
|
||||
else:
|
||||
rec.invoiced_untaxed_amount = 0.0
|
||||
if rec.state in ["draft", "sent", "cancel"]:
|
||||
rec.uninvoiced_untaxed_amount = 0.0
|
||||
else:
|
||||
rec.uninvoiced_untaxed_amount = rec.amount_untaxed
|
1
sale_order_invoice_untaxed_amount/tests/__init__.py
Normal file
1
sale_order_invoice_untaxed_amount/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_sale_order_invoice_untaxed_amount
|
@@ -0,0 +1,117 @@
|
||||
# Copyright (C) 2021 ForgeFlow S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestSaleOrderInvoiceUntaxedAmount(common.SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# Partners
|
||||
cls.res_partner_1 = cls.env["res.partner"].create({"name": "Wood Corner"})
|
||||
cls.res_partner_address_1 = cls.env["res.partner"].create(
|
||||
{"name": "Willie Burke", "parent_id": cls.res_partner_1.id}
|
||||
)
|
||||
cls.res_partner_2 = cls.env["res.partner"].create({"name": "Partner 12"})
|
||||
|
||||
# Products
|
||||
cls.product_1 = cls.env["product.product"].create(
|
||||
{"name": "Desk Combination", "type": "product", "invoice_policy": "order"}
|
||||
)
|
||||
cls.product_2 = cls.env["product.product"].create(
|
||||
{"name": "Conference Chair", "type": "product", "invoice_policy": "order"}
|
||||
)
|
||||
cls.product_3 = cls.env["product.product"].create(
|
||||
{"name": "Repair Services", "type": "service", "invoice_policy": "order"}
|
||||
)
|
||||
|
||||
# Location
|
||||
cls.stock_warehouse = cls.env["stock.warehouse"].search(
|
||||
[("company_id", "=", cls.env.company.id)], limit=1
|
||||
)
|
||||
cls.stock_location_14 = cls.env["stock.location"].create(
|
||||
{"name": "Shelf 2", "location_id": cls.stock_warehouse.lot_stock_id.id}
|
||||
)
|
||||
# Replenish products
|
||||
cls.env["stock.quant"]._update_available_quantity(
|
||||
cls.product_1, cls.stock_location_14, 10
|
||||
)
|
||||
cls.env["stock.quant"]._update_available_quantity(
|
||||
cls.product_2, cls.stock_location_14, 10
|
||||
)
|
||||
# Sale Order
|
||||
cls.tax = cls.env["account.tax"].create(
|
||||
{"name": "Tax 15", "type_tax_use": "sale", "amount": 21}
|
||||
)
|
||||
cls.sale_order_1 = cls.env["sale.order"].create(
|
||||
{"partner_id": cls.res_partner_1.id}
|
||||
)
|
||||
cls.order_line_1 = cls.env["sale.order.line"].create(
|
||||
{
|
||||
"order_id": cls.sale_order_1.id,
|
||||
"product_id": cls.product_1.id,
|
||||
"product_uom": cls.product_1.uom_id.id,
|
||||
"product_uom_qty": 10.0,
|
||||
"price_unit": 10.0,
|
||||
"tax_id": cls.tax,
|
||||
}
|
||||
)
|
||||
cls.order_line_2 = cls.env["sale.order.line"].create(
|
||||
{
|
||||
"order_id": cls.sale_order_1.id,
|
||||
"product_id": cls.product_2.id,
|
||||
"product_uom": cls.product_2.uom_id.id,
|
||||
"product_uom_qty": 25.0,
|
||||
"price_unit": 4.0,
|
||||
"tax_id": cls.tax,
|
||||
}
|
||||
)
|
||||
cls.order_line_3 = cls.env["sale.order.line"].create(
|
||||
{
|
||||
"order_id": cls.sale_order_1.id,
|
||||
"product_id": cls.product_3.id,
|
||||
"product_uom": cls.product_3.uom_id.id,
|
||||
"product_uom_qty": 20.0,
|
||||
"price_unit": 5.0,
|
||||
"tax_id": cls.tax,
|
||||
}
|
||||
)
|
||||
|
||||
def test_sale_order_invoiced_amount(self):
|
||||
|
||||
self.assertEqual(
|
||||
self.sale_order_1.invoiced_amount,
|
||||
0.0,
|
||||
"Invoiced Amount should be 0.0",
|
||||
)
|
||||
context_payment = {
|
||||
"active_ids": [self.sale_order_1.id],
|
||||
"active_id": self.sale_order_1.id,
|
||||
}
|
||||
payment = (
|
||||
self.env["sale.advance.payment.inv"]
|
||||
.with_context(context_payment)
|
||||
.create({"advance_payment_method": "fixed", "fixed_amount": 100})
|
||||
)
|
||||
|
||||
payment.create_invoices()
|
||||
self.assertEqual(
|
||||
self.sale_order_1.invoiced_untaxed_amount,
|
||||
100.0,
|
||||
"Invoiced Untaxed Amount should be 100",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.sale_order_1.uninvoiced_untaxed_amount,
|
||||
200.0,
|
||||
"Uninvoiced Untaxed Amount should be 263",
|
||||
)
|
||||
|
||||
self.sale_order_1.action_confirm()
|
||||
self.sale_order_1._create_invoices(final=True)
|
||||
self.assertEqual(
|
||||
self.sale_order_1.invoiced_amount,
|
||||
300.0,
|
||||
"Invoiced Untaxed Amount should be calculated",
|
||||
)
|
29
sale_order_invoice_untaxed_amount/views/sale_order_view.xml
Normal file
29
sale_order_invoice_untaxed_amount/views/sale_order_view.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_order_form_invoiced_untaxed_amount" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.invoiced.untaxed.amount</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="amount_untaxed" position="after">
|
||||
<field name="invoiced_untaxed_amount" />
|
||||
<field name="uninvoiced_untaxed_amount" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_order_tree_invoiced_untaxed_amount" model="ir.ui.view">
|
||||
<field name="name">sale.order.tree.invoiced.untaxed.amount</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='amount_tax']" position="after">
|
||||
<field name="invoiced_untaxed_amount" sum="Invoiced Untaxed Total" optional="hide" />
|
||||
<field
|
||||
name="uninvoiced_untaxed_amount"
|
||||
sum="Uninvoiced Untaxed Total"
|
||||
optional="hide"
|
||||
/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
Reference in New Issue
Block a user