merge: resolve ignored pyc/log conflicts by keeping deletions

This commit is contained in:
2026-03-28 07:09:19 +07:00
2480 changed files with 768459 additions and 105 deletions
+20
View File
@@ -0,0 +1,20 @@
# GRT Addon Versioning
Gunakan pola `14.0.x.y.z` untuk addon custom GRT di Odoo 14.
- `14.0` mengikuti versi Odoo.
- `x` untuk rilis besar per modul jika ada perubahan fungsional besar atau milestone penting.
- `y` untuk fitur kecil atau penambahan perilaku yang tetap backward compatible.
- `z` untuk fix kecil, patch, atau penyesuaian teknis seperti CORS, domain, validasi, dan perbaikan bug.
Aturan praktis:
- Bugfix kecil: naikkan digit terakhir.
- Tambah endpoint, field, view, atau behavior baru yang kompatibel: naikkan digit ke-4 lalu reset digit terakhir jika perlu.
- Perubahan besar per modul boleh menaikkan digit ke-3.
Normalisasi yang sudah dilakukan:
- `grt_sales_business_category`: `14.0.1.0.12` setelah patch CORS.
- `grt_project_task`: `0.1` -> `14.0.0.1.0`.
- `grt_scada`: `7.2.1` -> `14.0.7.2.1` agar tetap membawa jejak versi lama dalam format Odoo-style.
+143
View File
@@ -0,0 +1,143 @@
===============================
Accounting with Operating Units
===============================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github
:target: https://github.com/OCA/operating-unit/tree/14.0/account_operating_unit
:alt: OCA/operating-unit
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/operating-unit-14-0/operating-unit-14-0-account_operating_unit
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/213/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows a company to manage the accounting based on Operating
Units (OU's).
* The financial reports (Trial Balance, P&L, Balance Sheet), allow to report
the balances of one or more OU's.
* If a company wishes to report Balance Sheet and P&L accounts based on
OU's, they should indicate at company level that the OU's are
self-balanced, and the corresponding Inter-Operating Unit clearing account.
The Chart of Accounts will always be balanced, for each Operating Unit.
* A company considering Operating Unit as applicable to report only profits
and losses will not need to set the OU's as self-balanced.
* The self-balancing of Operating Unit is ensured at the time of posting a
journal entry. In case that the journal involves posting of items in
separate Operating Units, new journal items will be created, using the
Inter-Operating Unit clearing account, to ensure that each OU is going to
be self-balanced for that journal entry.
* Adds the Operating Unit to the invoice. A user can choose what OU to
create the invoice for.
* Adds the Operating Unit to payments and payment methods. The operating
unit of a payment will be that of the payment method chosen.
* Implements security rules at OU level to invoices, payments and journal
items.
**Table of contents**
.. contents::
:local:
Configuration
=============
If your company is required to generate a balanced balance sheet by
Operating Unit you can specify at company level that Operating Units should
be self-balanced, and then indicate a self-balancing clearing account.
#. Create an account "Inter-OU Clearing". It is a balance sheet account.
#. Go to *Settings / Companies / Configuration* and Set the "Operating Units
are self-balanced" checkbox. Then set the "Inter-OU Clearing" account in "Inter-Operating Unit
clearing account" field.
#. Go to *Accounting / Configuration / Accounting / Journals* and define, for
each Payment Method, the Operating Unit that will be used in payments.
Usage
=====
* Add the Operating Unit to invoices.
* Report invoices by Operating Unit in *Accounting / Reporting*
*Business Intelligence / Invoices*
* Add the Default Operating Unit to account move. Then all move lines will
by default adopt this Operating Unit.
* Add Operating Units to the move lines. If they differ across lines of the same move, and the OU's are
self-balanced, then additional move lines will be created so as to make
the move self-balanced from OU perspective.
* In the menu *Accounting / Reporting / PDF Reports*, you can indicate the
Operating Units to report on, for the *Trial Balance*, *Balance Sheet*,
*Profit and Loss*, and *Financial Reports*.
Known issues / Roadmap
======================
* The *General Ledger*, *Aged Partner Balance* reports do not support the
filter by Operating Unit. Basically due to lack of proper hooks in the
standard methods used by these reports, to introduce the ability to filter
by Operating Unit.
* Trial Balance, P&L and Balance Sheet were removed from Odoo Community. Once
OCA Financial Reports are migrated to 13 we can add the Operating Unit to
those reports.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/operating-unit/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 <https://github.com/OCA/operating-unit/issues/new?body=module:%20account_operating_unit%0Aversion:%2014.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
* Serpent Consulting Services Pvt. Ltd.
* WilldooIT Pty Ltd
Contributors
~~~~~~~~~~~~
* ForgeFlow <contact@forgeflow.com>
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
* Aarón Henríquez <ahenriquez@forgeflow.com>
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
* WilldooIT Pty Ltd <info@willdooit.com>
* Michael Villamar <michael.villamar@willdooit.com>
* Jarsa Sistemas <info@jarsa.com.mx>
* Alan Ramos <alan.ramos@jarsa.com.mx>
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/operating-unit <https://github.com/OCA/operating-unit/tree/14.0/account_operating_unit>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+5
View File
@@ -0,0 +1,5 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models
from . import report
from . import wizards
+27
View File
@@ -0,0 +1,27 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Accounting with Operating Units",
"summary": "Introduces Operating Unit (OU) in invoices and "
"Accounting Entries with clearing account",
"version": "14.0.1.0.2",
"author": "ForgeFlow, "
"Serpent Consulting Services Pvt. Ltd.,"
"WilldooIT Pty Ltd,"
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/operating-unit",
"category": "Accounting & Finance",
"depends": ["account", "analytic_operating_unit","cash_management",],
"license": "LGPL-3",
"data": [
"security/account_security.xml",
"views/account_move_view.xml",
"views/account_journal_view.xml",
"views/company_view.xml",
"views/account_payment_view.xml",
"views/account_move_aa.xml",
"views/account_invoice_report_view.xml",
"views/account_move_account_inherit.xml",
],
}
@@ -0,0 +1,191 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_operating_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.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: account_operating_unit
#: model:ir.model.fields,help:account_operating_unit.field_res_company__ou_is_self_balanced
msgid ""
"Activate if your company is required to generate a balanced balance sheet "
"for each operating unit."
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_res_company
msgid "Companies"
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_journal.py:0
#, python-format
msgid ""
"Configuration error. If defined as self-balanced at company level, the "
"operating unit is mandatory in bank journal."
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/res_company.py:0
#, python-format
msgid ""
"Configuration error. Please provide an Inter-operating unit clearing "
"account."
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. The Company in the Move Line and in the Operating Unit "
"must be the same."
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. The Operating Unit in the Move Line and in the Move "
"must be the same."
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. The operating unit is mandatory for each line as the "
"operating unit has been defined as self-balanced at company level."
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. You need to define aninter-operating unit clearing "
"account in the company settings"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment_register__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__display_name
msgid "Display Name"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment_register__id
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__id
msgid "ID"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__inter_ou_clearing_account_id
msgid "Inter-operating unit clearing account"
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_invoice_report
msgid "Invoices Statistics"
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_journal
msgid "Journal"
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_move
msgid "Journal Entry"
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_move_line
msgid "Journal Item"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment_register____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company____last_update
msgid "Last Modified on"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_bank_statement_line__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment__operating_unit_id
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_invoice_filter
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_invoice_report_search
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_move_line_filter
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_payment_search
msgid "Operating Unit"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,help:account_operating_unit.field_account_journal__operating_unit_id
msgid ""
"Operating Unit that will be used in payments, when this journal is used."
msgstr ""
#. module: account_operating_unit
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_company_form
msgid "Operating Units"
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__ou_is_self_balanced
msgid "Operating Units are self-balanced"
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_payment
msgid "Payments"
msgstr ""
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_payment_register
msgid "Register Payment"
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid "The Company in the Move and in Operating Unit must be the same."
msgstr ""
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid "The OU in the Move and in Journal must be the same."
msgstr ""
#. module: account_operating_unit
#: model:ir.model.fields,help:account_operating_unit.field_account_bank_statement_line__operating_unit_id
#: model:ir.model.fields,help:account_operating_unit.field_account_move__operating_unit_id
msgid "This operating unit will be defaulted in the move lines."
msgstr ""
+211
View File
@@ -0,0 +1,211 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_operating_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-01-02 11:45+0000\n"
"Last-Translator: Francesco Foresti <francesco.foresti@ooops404.com>\n"
"Language-Team: none\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.14.1\n"
#. module: account_operating_unit
#: model:ir.model.fields,help:account_operating_unit.field_res_company__ou_is_self_balanced
msgid ""
"Activate if your company is required to generate a balanced balance sheet "
"for each operating unit."
msgstr ""
"Da attivare se la tua azienda è tenuta a generare un bilancio in pareggio "
"per ogni Unità Operativa."
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_res_company
msgid "Companies"
msgstr "Aziende"
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_journal.py:0
#, python-format
msgid ""
"Configuration error. If defined as self-balanced at company level, the "
"operating unit is mandatory in bank journal."
msgstr ""
"Errore di configurazione. Se definito come autobilanciata a livello "
"aziendale, l'unità operativa è obbligatoria nel Registro banca."
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/res_company.py:0
#, python-format
msgid ""
"Configuration error. Please provide an Inter-operating unit clearing "
"account."
msgstr ""
"Errore di configurazione. Per favore Fornisci un conto di compensazione tra "
"unità operative."
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. The Company in the Move Line and in the Operating Unit "
"must be the same."
msgstr ""
"Errore di configurazione. L'azienda nella riga di movimento e nell'unità "
"operativa deve essere la stessa."
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. The Operating Unit in the Move Line and in the Move "
"must be the same."
msgstr ""
"Errore di configurazione. L'Unità Operativa nella riga di movimento e e nel "
"movimento deve essere la stessa."
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. The operating unit is mandatory for each line as the "
"operating unit has been defined as self-balanced at company level."
msgstr ""
"Errore di configurazione. L'unità operativa è obbligatoria per ciascuna "
"linea in quanto l'unità operativa è stata definita autobilanciata a livello "
"aziendale."
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid ""
"Configuration error. You need to define aninter-operating unit clearing "
"account in the company settings"
msgstr ""
"Errore di configurazione. È necessario definire un conto di compensazione "
"tra unità operative nelle impostazioni dell'azienda"
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment_register__display_name
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment__id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment_register__id
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__id
msgid "ID"
msgstr "ID"
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__inter_ou_clearing_account_id
msgid "Inter-operating unit clearing account"
msgstr "Conto di compensazione tra unità operative"
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_invoice_report
msgid "Invoices Statistics"
msgstr "Statistiche Fatture"
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_journal
msgid "Journal"
msgstr "Registro"
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_move
msgid "Journal Entry"
msgstr "Registrazione contabile"
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_move_line
msgid "Journal Item"
msgstr "Movimento contabile"
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment_register____last_update
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_account_bank_statement_line__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_invoice_report__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_journal__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_move_line__operating_unit_id
#: model:ir.model.fields,field_description:account_operating_unit.field_account_payment__operating_unit_id
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_invoice_filter
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_invoice_report_search
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_move_line_filter
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_account_payment_search
msgid "Operating Unit"
msgstr "Unità Operativa"
#. module: account_operating_unit
#: model:ir.model.fields,help:account_operating_unit.field_account_journal__operating_unit_id
msgid ""
"Operating Unit that will be used in payments, when this journal is used."
msgstr ""
"L'Unità operativa che verrà utilizzata nei pagamenti, quando viene "
"utilizzato questo Registro."
#. module: account_operating_unit
#: model_terms:ir.ui.view,arch_db:account_operating_unit.view_company_form
msgid "Operating Units"
msgstr "Unità Operative"
#. module: account_operating_unit
#: model:ir.model.fields,field_description:account_operating_unit.field_res_company__ou_is_self_balanced
msgid "Operating Units are self-balanced"
msgstr "Le unità operative sono autobilanciate"
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_payment
msgid "Payments"
msgstr "Pagamenti"
#. module: account_operating_unit
#: model:ir.model,name:account_operating_unit.model_account_payment_register
msgid "Register Payment"
msgstr "Registrare Pagamento"
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid "The Company in the Move and in Operating Unit must be the same."
msgstr "L'azienda nei movimenti e nelle unità operativa deve essere la stessa."
#. module: account_operating_unit
#: code:addons/account_operating_unit/models/account_move.py:0
#: code:addons/account_operating_unit/models/account_move.py:0
#, python-format
msgid "The OU in the Move and in Journal must be the same."
msgstr "L'unità operativa nel movimento e nel Registro deve essere la stessa."
#. module: account_operating_unit
#: model:ir.model.fields,help:account_operating_unit.field_account_bank_statement_line__operating_unit_id
#: model:ir.model.fields,help:account_operating_unit.field_account_move__operating_unit_id
msgid "This operating unit will be defaulted in the move lines."
msgstr "Questa unità operativa sarà predefinita nelle righe di movimento."
@@ -0,0 +1,8 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import res_company
from . import account_journal
from . import account_move
from . import account_payment
from . import account_move_aa
from . import account_payment_aa
@@ -0,0 +1,34 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class AccountJournal(models.Model):
_inherit = "account.journal"
operating_unit_id = fields.Many2one(
comodel_name="operating.unit",
domain="[('user_ids', '=', uid)]",
help="Operating Unit that will be used in payments, "
"when this journal is used.",
)
@api.constrains("type")
def _check_ou(self):
for journal in self:
if (
journal.type in ("bank", "cash")
and journal.company_id.ou_is_self_balanced
and not journal.operating_unit_id
):
raise UserError(
_(
"Configuration error. If defined as "
"self-balanced at company level, the "
"operating unit is mandatory in bank "
"journal."
)
)
@@ -0,0 +1,257 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class AccountMoveLine(models.Model):
_inherit = "account.move.line"
operating_unit_id = fields.Many2one(
comodel_name="operating.unit", domain="[('user_ids', '=', uid)]"
)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get("move_id", False):
move = self.env["account.move"].browse(vals["move_id"])
if move.operating_unit_id:
vals["operating_unit_id"] = move.operating_unit_id.id
return super().create(vals_list)
@api.model
def _query_get(self, domain=None):
if domain is None:
domain = []
if self._context.get("operating_unit_ids", False):
domain.append(
("operating_unit_id", "in", self._context.get("operating_unit_ids"))
)
return super()._query_get(domain)
@api.constrains("operating_unit_id", "company_id")
def _check_company_operating_unit(self):
for rec in self:
if (
rec.company_id
and rec.operating_unit_id
and rec.company_id != rec.operating_unit_id.company_id
):
raise UserError(
_(
"Configuration error. The Company in the"
" Move Line and in the Operating Unit must "
"be the same."
)
)
@api.constrains("operating_unit_id", "move_id")
def _check_move_operating_unit(self):
for rec in self:
if (
rec.move_id
and rec.move_id.operating_unit_id
and rec.operating_unit_id
and rec.move_id.operating_unit_id != rec.operating_unit_id
):
raise UserError(
_(
"Configuration error. The Operating Unit in"
" the Move Line and in the Move must be the"
" same."
)
)
class AccountMove(models.Model):
_inherit = "account.move"
@api.model
def _default_operating_unit_id(self):
if (
self._context.get("default_move_type", False)
and self._context.get("default_move_type") != "entry"
):
return self.env["res.users"].operating_unit_default_get()
return False
operating_unit_id = fields.Many2one(
comodel_name="operating.unit",
default=_default_operating_unit_id,
domain="[('user_ids', '=', uid)]",
help="This operating unit will be defaulted in the move lines.",
readonly=True,
states={"draft": [("readonly", False)]},
)
@api.onchange("invoice_line_ids")
def _onchange_invoice_line_ids(self):
res = super()._onchange_invoice_line_ids()
if self.operating_unit_id:
for line in self.line_ids:
line.operating_unit_id = self.operating_unit_id
return res
@api.onchange("operating_unit_id")
def _onchange_operating_unit(self):
if self.operating_unit_id and (
not self.journal_id
or self.journal_id.operating_unit_id != self.operating_unit_id
):
journal = self.env["account.journal"].search(
[("type", "=", self.journal_id.type)]
)
jf = journal.filtered(
lambda aj: aj.operating_unit_id == self.operating_unit_id
)
if not jf:
self.journal_id = journal[0]
else:
self.journal_id = jf[0]
for line in self.line_ids:
line.operating_unit_id = self.operating_unit_id
@api.onchange("journal_id")
def _onchange_journal(self):
if (
self.journal_id
and self.journal_id.operating_unit_id
and self.journal_id.operating_unit_id != self.operating_unit_id
):
self.operating_unit_id = self.journal_id.operating_unit_id
for line in self.line_ids:
line.operating_unit_id = self.journal_id.operating_unit_id
def _prepare_inter_ou_balancing_move_line(self, move, ou_id, ou_balances):
if not move.company_id.inter_ou_clearing_account_id:
raise UserError(
_(
"Configuration error. You need to define an"
"inter-operating unit clearing account in the "
"company settings"
)
)
res = {
"name": "OU-Balancing",
"move_id": move.id,
"journal_id": move.journal_id.id,
"date": move.date,
"operating_unit_id": ou_id,
"partner_id": move.partner_id and move.partner_id.id or False,
"account_id": move.company_id.inter_ou_clearing_account_id.id,
}
if ou_balances[ou_id] < 0.0:
res["debit"] = abs(ou_balances[ou_id])
else:
res["credit"] = ou_balances[ou_id]
return res
def _check_ou_balance(self, move):
# Look for the balance of each OU
ou_balance = {}
for line in move.line_ids:
if line.operating_unit_id.id not in ou_balance:
ou_balance[line.operating_unit_id.id] = 0.0
ou_balance[line.operating_unit_id.id] += line.debit - line.credit
return ou_balance
def _post(self, soft=True):
ml_obj = self.env["account.move.line"]
for move in self:
if not move.company_id.ou_is_self_balanced:
continue
# If all move lines point to the same operating unit, there's no
# need to create a balancing move line
if len(move.line_ids.operating_unit_id) <= 1:
continue
# Create balancing entries for un-balanced OU's.
ou_balances = self._check_ou_balance(move)
amls = []
for ou_id in list(ou_balances.keys()):
# If the OU is already balanced, then do not continue
if move.company_id.currency_id.is_zero(ou_balances[ou_id]):
continue
# Create a balancing move line in the operating unit
# clearing account
line_data = self._prepare_inter_ou_balancing_move_line(
move, ou_id, ou_balances
)
if line_data:
amls.append(ml_obj.with_context(wip=True).create(line_data))
if amls:
move.with_context(wip=False).write(
{"line_ids": [(4, aml.id) for aml in amls]}
)
return super()._post(soft)
def _check_balanced(self):
if self.env.context.get("wip"):
return True
return super()._check_balanced()
@api.constrains("line_ids")
def _check_ou(self):
for move in self:
if not move.company_id.ou_is_self_balanced:
continue
for line in move.line_ids:
if not line.operating_unit_id:
raise UserError(
_(
"Configuration error. The operating unit is "
"mandatory for each line as the operating unit "
"has been defined as self-balanced at company "
"level."
)
)
@api.constrains("operating_unit_id", "journal_id")
def _check_journal_operating_unit(self):
for move in self:
if (
move.journal_id.operating_unit_id
and move.operating_unit_id
and move.operating_unit_id != move.journal_id.operating_unit_id
):
# Change journal_id if create move from other model. e.g., sale.order
if (
move._context.get("active_model")
and move._context.get("active_model") != "account.move"
):
move._onchange_operating_unit()
if (
move.journal_id.operating_unit_id
and move.operating_unit_id
and move.operating_unit_id != move.journal_id.operating_unit_id
):
raise UserError(
_("The OU in the Move and in Journal must be the same.")
)
else:
raise UserError(
_("The OU in the Move and in Journal must be the same.")
)
return True
@api.constrains("operating_unit_id", "company_id")
def _check_company_operating_unit(self):
for move in self:
if (
move.company_id
and move.operating_unit_id
and move.company_id != move.operating_unit_id.company_id
):
raise UserError(
_(
"The Company in the Move and in "
"Operating Unit must be the same."
)
)
return True
@@ -0,0 +1,64 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError
# class AccountMoveLine(models.Model):
# _inherit = "account.move.line"
#
# operating_unit_id = fields.Many2one(
# comodel_name="operating.unit", domain="[('user_ids', '=', uid)]"
# )
#
# @api.model_create_multi
# def create(self, vals_list):
# for vals in vals_list:
# if vals.get("move_id", False):
# move = self.env["account.move"].browse(vals["move_id"])
# if move.operating_unit_id:
# vals["operating_unit_id"] = move.operating_unit_id.id
# return super().create(vals_list)
class account_move_aa(models.Model):
_inherit = "account.move"
analytic_account_id = fields.Many2one(
comodel_name="account.analytic.account", string="Analytic Account"
)
@api.onchange("invoice_line_ids", "analytic_account_id")
def _onchange_invoice_line_ids(self):
res = super()._onchange_invoice_line_ids()
if self.analytic_account_id:
for line in self.line_ids:
line.analytic_account_id = self.analytic_account_id
return res
class account_move_account(models.Model):
_inherit = "account.move"
account_id = fields.Many2one(
comodel_name="account.account"
)
# @api.onchange("operating_unit_id")
# def _onchange_operating_unit(self):
# if self.operating_unit_id and (
# not self.journal_id
# or self.journal_id.operating_unit_id != self.operating_unit_id
# ):
# journal = self.env["account.journal"].search(
# [("type", "=", self.journal_id.type)]
# )
# jf = journal.filtered(
# lambda aj: aj.operating_unit_id == self.operating_unit_id
# )
# if not jf:
# self.journal_id = journal[0]
# else:
# self.journal_id = jf[0]
# for line in self.line_ids:
# line.operating_unit_id = self.operating_unit_id
@@ -0,0 +1,35 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
class AccountPayment(models.Model):
_inherit = "account.payment"
@api.depends("journal_id")
def _compute_operating_unit_id(self):
for payment in self:
if payment.journal_id:
payment.operating_unit_id = payment.journal_id.operating_unit_id
operating_unit_id = fields.Many2one(
comodel_name="operating.unit",
domain="[('user_ids', '=', uid)]",
compute="_compute_operating_unit_id",
store=True,
)
def _prepare_move_line_default_vals(self, write_off_line_vals=None):
res = super()._prepare_move_line_default_vals(write_off_line_vals)
for line in res:
line["operating_unit_id"] = self.operating_unit_id.id
invoices = self.env["account.move"].browse(self._context.get("active_ids"))
invoices_ou = invoices.operating_unit_id
if invoices and len(invoices_ou) == 1 and invoices_ou != self.operating_unit_id:
destination_account_id = self.destination_account_id.id
for line in res:
if line["account_id"] == destination_account_id:
line["operating_unit_id"] = invoices_ou.id
return res
@@ -0,0 +1,31 @@
from odoo import api, fields, models
class account_payment_aa(models.Model):
_inherit = "account.payment"
# @api.depends("journal_id")
# def _compute_operating_unit_id(self):
# for payment in self:
# if payment.journal_id:
# payment.operating_unit_id = payment.journal_id.operating_unit_id
#
# operating_unit_id = fields.Many2one(
# comodel_name="operating.unit",
# domain="[('user_ids', '=', uid)]",
# compute="_compute_operating_unit_id",
# store=True,
# )
def _prepare_move_line_default_aa_vals(self, write_off_line_vals=None):
res = super()._prepare_move_line_default_aa_vals(write_off_line_vals)
for line in res:
line["analytic_account_id"] = self.analytic_account_id.id
invoices = self.env["account.move"].browse(self._context.get("active_ids"))
invoices_ou = invoices.analytic_account_id
if invoices and len(invoices_ou) == 1 and invoices_ou != self.analytic_account_id:
destination_account_id = self.destination_account_id.id
for line in res:
if line["account_id"] == destination_account_id:
line["analytic_account_id"] = invoices_ou.id
return res
@@ -0,0 +1,34 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
from odoo.exceptions import UserError
from odoo.tools.translate import _
class ResCompany(models.Model):
_inherit = "res.company"
inter_ou_clearing_account_id = fields.Many2one(
comodel_name="account.account",
string="Inter-operating unit clearing account",
)
ou_is_self_balanced = fields.Boolean(
string="Operating Units are self-balanced",
help="Activate if your company is "
"required to generate a balanced"
" balance sheet for each "
"operating unit.",
)
@api.constrains("ou_is_self_balanced", "inter_ou_clearing_account_id")
def _inter_ou_clearing_acc_required(self):
for rec in self:
if rec.ou_is_self_balanced and not rec.inter_ou_clearing_account_id:
raise UserError(
_(
"Configuration error. Please provide an "
"Inter-operating unit clearing account."
)
)
@@ -0,0 +1,10 @@
If your company is required to generate a balanced balance sheet by
Operating Unit you can specify at company level that Operating Units should
be self-balanced, and then indicate a self-balancing clearing account.
#. Create an account "Inter-OU Clearing". It is a balance sheet account.
#. Go to *Settings / Companies / Configuration* and Set the "Operating Units
are self-balanced" checkbox. Then set the "Inter-OU Clearing" account in "Inter-Operating Unit
clearing account" field.
#. Go to *Accounting / Configuration / Accounting / Journals* and define, for
each Payment Method, the Operating Unit that will be used in payments.
@@ -0,0 +1,8 @@
* ForgeFlow <contact@forgeflow.com>
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
* Aarón Henríquez <ahenriquez@forgeflow.com>
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
* WilldooIT Pty Ltd <info@willdooit.com>
* Michael Villamar <michael.villamar@willdooit.com>
* Jarsa Sistemas <info@jarsa.com.mx>
* Alan Ramos <alan.ramos@jarsa.com.mx>
@@ -0,0 +1,22 @@
This module allows a company to manage the accounting based on Operating
Units (OU's).
* The financial reports (Trial Balance, P&L, Balance Sheet), allow to report
the balances of one or more OU's.
* If a company wishes to report Balance Sheet and P&L accounts based on
OU's, they should indicate at company level that the OU's are
self-balanced, and the corresponding Inter-Operating Unit clearing account.
The Chart of Accounts will always be balanced, for each Operating Unit.
* A company considering Operating Unit as applicable to report only profits
and losses will not need to set the OU's as self-balanced.
* The self-balancing of Operating Unit is ensured at the time of posting a
journal entry. In case that the journal involves posting of items in
separate Operating Units, new journal items will be created, using the
Inter-Operating Unit clearing account, to ensure that each OU is going to
be self-balanced for that journal entry.
* Adds the Operating Unit to the invoice. A user can choose what OU to
create the invoice for.
* Adds the Operating Unit to payments and payment methods. The operating
unit of a payment will be that of the payment method chosen.
* Implements security rules at OU level to invoices, payments and journal
items.
@@ -0,0 +1,7 @@
* The *General Ledger*, *Aged Partner Balance* reports do not support the
filter by Operating Unit. Basically due to lack of proper hooks in the
standard methods used by these reports, to introduce the ability to filter
by Operating Unit.
* Trial Balance, P&L and Balance Sheet were removed from Odoo Community. Once
OCA Financial Reports are migrated to 13 we can add the Operating Unit to
those reports.
+11
View File
@@ -0,0 +1,11 @@
* Add the Operating Unit to invoices.
* Report invoices by Operating Unit in *Accounting / Reporting*
*Business Intelligence / Invoices*
* Add the Default Operating Unit to account move. Then all move lines will
by default adopt this Operating Unit.
* Add Operating Units to the move lines. If they differ across lines of the same move, and the OU's are
self-balanced, then additional move lines will be created so as to make
the move self-balanced from OU perspective.
* In the menu *Accounting / Reporting / PDF Reports*, you can indicate the
Operating Units to report on, for the *Trial Balance*, *Balance Sheet*,
*Profit and Loss*, and *Financial Reports*.
@@ -0,0 +1,3 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import account_invoice_report
@@ -0,0 +1,29 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import fields, models
class AccountInvoiceReport(models.Model):
_inherit = "account.invoice.report"
operating_unit_id = fields.Many2one(
comodel_name="operating.unit",
string="Operating Unit",
)
def _select(self):
select_str = super()._select()
select_str += """
,line.operating_unit_id
"""
return select_str
def _group_by(self):
group_by_str = super()._group_by()
group_by_str += """
,line.operating_unit_id
"""
return group_by_str
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2019 ForgeFlow S.L.-->
<!--© 2019 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo noupdate="0">
<record id="ir_rule_account_journal_allowed_operating_units" model="ir.rule">
<field name="model_id" ref="account.model_account_journal" />
<field name="domain_force">
['|', ('operating_unit_id','=',False),
('operating_unit_id','in',user.operating_unit_ids.ids)]
</field>
<field name="name">Journals from allowed operating units</field>
<field name="global" eval="True" />
<field eval="0" name="perm_unlink" />
<field eval="0" name="perm_write" />
<field eval="1" name="perm_read" />
<field eval="0" name="perm_create" />
</record>
<record id="ir_rule_move_line_allowed_operating_units" model="ir.rule">
<field name="model_id" ref="account.model_account_move_line" />
<field name="domain_force">
['|', ('operating_unit_id','=',False), ('operating_unit_id','in',
user.operating_unit_ids.ids)]
</field>
<field name="name">Move lines from allowed operating units</field>
<field name="global" eval="True" />
<field eval="0" name="perm_unlink" />
<field eval="0" name="perm_write" />
<field eval="1" name="perm_read" />
<field eval="0" name="perm_create" />
</record>
<record id="ir_rule_move_allowed_operating_units" model="ir.rule">
<field name="model_id" ref="account.model_account_move" />
<field name="domain_force">
['|', ('operating_unit_id','=',False), ('operating_unit_id','in',
user.operating_unit_ids.ids)]
</field>
<field name="name">Moves from allowed operating units</field>
<field name="global" eval="True" />
<field eval="0" name="perm_unlink" />
<field eval="0" name="perm_write" />
<field eval="1" name="perm_read" />
<field eval="0" name="perm_create" />
</record>
<record id="ir_rule_account_payment_allowed_operating_units" model="ir.rule">
<field name="model_id" ref="account.model_account_payment" />
<field name="domain_force">
['|', ('operating_unit_id','=',False), ('operating_unit_id','in',
user.operating_unit_ids.ids)]
</field>
<field name="name">Payments from allowed operating units</field>
<field name="global" eval="True" />
<field eval="0" name="perm_unlink" />
<field eval="0" name="perm_write" />
<field eval="1" name="perm_read" />
<field eval="0" name="perm_create" />
</record>
<record id="ir_rule_invoice_report_allowed_operating_units" model="ir.rule">
<field name="model_id" ref="account.model_account_invoice_report" />
<field name="domain_force">
['|', ('operating_unit_id','=',False), ('operating_unit_id','in',
user.operating_unit_ids.ids)]
</field>
<field name="name">Invoice Report from allowed operating units</field>
<field name="global" eval="True" />
<field eval="0" name="perm_unlink" />
<field eval="0" name="perm_write" />
<field eval="1" name="perm_read" />
<field eval="0" name="perm_create" />
</record>
</odoo>
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

@@ -0,0 +1,495 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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 0.15.1: http://docutils.sourceforge.net/" />
<title>Accounting with Operating Units</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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: grey; } /* 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 {
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="accounting-with-operating-units">
<h1 class="title">Accounting with Operating Units</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/operating-unit/tree/14.0/account_operating_unit"><img alt="OCA/operating-unit" src="https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/operating-unit-14-0/operating-unit-14-0-account_operating_unit"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/213/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows a company to manage the accounting based on Operating
Units (OUs).</p>
<ul class="simple">
<li>The financial reports (Trial Balance, P&amp;L, Balance Sheet), allow to report
the balances of one or more OUs.</li>
<li>If a company wishes to report Balance Sheet and P&amp;L accounts based on
OUs, they should indicate at company level that the OUs are
self-balanced, and the corresponding Inter-Operating Unit clearing account.
The Chart of Accounts will always be balanced, for each Operating Unit.</li>
<li>A company considering Operating Unit as applicable to report only profits
and losses will not need to set the OUs as self-balanced.</li>
<li>The self-balancing of Operating Unit is ensured at the time of posting a
journal entry. In case that the journal involves posting of items in
separate Operating Units, new journal items will be created, using the
Inter-Operating Unit clearing account, to ensure that each OU is going to
be self-balanced for that journal entry.</li>
<li>Adds the Operating Unit to the invoice. A user can choose what OU to
create the invoice for.</li>
<li>Adds the Operating Unit to payments and payment methods. The operating
unit of a payment will be that of the payment method chosen.</li>
<li>Implements security rules at OU level to invoices, payments and journal
items.</li>
</ul>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id3">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id1">Configuration</a></h1>
<p>If your company is required to generate a balanced balance sheet by
Operating Unit you can specify at company level that Operating Units should
be self-balanced, and then indicate a self-balancing clearing account.</p>
<ol class="arabic simple">
<li>Create an account “Inter-OU Clearing”. It is a balance sheet account.</li>
<li>Go to <em>Settings / Companies / Configuration</em> and Set the “Operating Units
are self-balanced” checkbox. Then set the “Inter-OU Clearing” account in “Inter-Operating Unit
clearing account” field.</li>
<li>Go to <em>Accounting / Configuration / Accounting / Journals</em> and define, for
each Payment Method, the Operating Unit that will be used in payments.</li>
</ol>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
<ul class="simple">
<li>Add the Operating Unit to invoices.</li>
<li>Report invoices by Operating Unit in <em>Accounting / Reporting</em>
<em>Business Intelligence / Invoices</em></li>
<li>Add the Default Operating Unit to account move. Then all move lines will
by default adopt this Operating Unit.</li>
<li>Add Operating Units to the move lines. If they differ across lines of the same move, and the OUs are
self-balanced, then additional move lines will be created so as to make
the move self-balanced from OU perspective.</li>
<li>In the menu <em>Accounting / Reporting / PDF Reports</em>, you can indicate the
Operating Units to report on, for the <em>Trial Balance</em>, <em>Balance Sheet</em>,
<em>Profit and Loss</em>, and <em>Financial Reports</em>.</li>
</ul>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>The <em>General Ledger</em>, <em>Aged Partner Balance</em> reports do not support the
filter by Operating Unit. Basically due to lack of proper hooks in the
standard methods used by these reports, to introduce the ability to filter
by Operating Unit.</li>
<li>Trial Balance, P&amp;L and Balance Sheet were removed from Odoo Community. Once
OCA Financial Reports are migrated to 13 we can add the Operating Unit to
those reports.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/operating-unit/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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/operating-unit/issues/new?body=module:%20account_operating_unit%0Aversion:%2014.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="#id5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id6">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
<li>Serpent Consulting Services Pvt. Ltd.</li>
<li>WilldooIT Pty Ltd</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id7">Contributors</a></h2>
<ul class="simple">
<li>ForgeFlow &lt;<a class="reference external" href="mailto:contact&#64;forgeflow.com">contact&#64;forgeflow.com</a>&gt;</li>
<li>Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;forgeflow.com">jordi.ballester&#64;forgeflow.com</a>&gt;</li>
<li>Aarón Henríquez &lt;<a class="reference external" href="mailto:ahenriquez&#64;forgeflow.com">ahenriquez&#64;forgeflow.com</a>&gt;</li>
<li>Serpent Consulting Services Pvt. Ltd. &lt;<a class="reference external" href="mailto:support&#64;serpentcs.com">support&#64;serpentcs.com</a>&gt;</li>
<li>WilldooIT Pty Ltd &lt;<a class="reference external" href="mailto:info&#64;willdooit.com">info&#64;willdooit.com</a>&gt;</li>
<li>Michael Villamar &lt;<a class="reference external" href="mailto:michael.villamar&#64;willdooit.com">michael.villamar&#64;willdooit.com</a>&gt;</li>
<li>Jarsa Sistemas &lt;<a class="reference external" href="mailto:info&#64;jarsa.com.mx">info&#64;jarsa.com.mx</a>&gt;</li>
<li>Alan Ramos &lt;<a class="reference external" href="mailto:alan.ramos&#64;jarsa.com.mx">alan.ramos&#64;jarsa.com.mx</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id8">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/operating-unit/tree/14.0/account_operating_unit">OCA/operating-unit</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>
+7
View File
@@ -0,0 +1,7 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import test_account_operating_unit
from . import test_invoice_operating_unit
from . import test_cross_ou_journal_entry
from . import test_operating_unit_security
from . import test_payment_operating_unit
@@ -0,0 +1,186 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import odoo.tests
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
@odoo.tests.tagged("post_install", "-at_install")
class TestAccountOperatingUnit(AccountTestInvoicingCommon):
def setUp(self):
super().setUp()
self.res_users_model = self.env["res.users"]
self.aml_model = self.env["account.move.line"]
self.move_model = self.env["account.move"]
self.account_model = self.env["account.account"]
self.journal_model = self.env["account.journal"]
self.product_model = self.env["product.product"]
self.payment_model = self.env["account.payment"]
self.register_payments_model = self.env["account.payment.register"]
# company
self.company = self.env.user.company_id
self.grp_acc_manager = self.env.ref("account.group_account_manager")
# Main Operating Unit
self.ou1 = self.env.ref("operating_unit.main_operating_unit")
# B2B Operating Unit
self.b2b = self.env.ref("operating_unit.b2b_operating_unit")
# B2C Operating Unit
self.b2c = self.env.ref("operating_unit.b2c_operating_unit")
# Assign user to main company to allow to write OU
self.env.user.write(
{
"company_ids": [(4, self.env.ref("base.main_company").id)],
"operating_unit_ids": [
(4, self.b2b.id),
(4, self.b2c.id),
],
}
)
# Assign company to OU
(self.ou1 + self.b2b + self.b2c).write({"company_id": self.company.id})
# Partner
self.partner1 = self.env.ref("base.res_partner_1")
# Products
self.product1 = self.env.ref("product.product_product_7")
self.product2 = self.env.ref("product.product_product_9")
self.product3 = self.env.ref("product.product_product_11")
# Payment methods
self.payment_method_manual_in = self.env.ref(
"account.account_payment_method_manual_in"
)
# Create user1
self.user_id = self.res_users_model.with_context(
{"no_reset_password": True}
).create(
{
"name": "Test Account User",
"login": "user_1",
"password": "demo",
"email": "example@yourcompany.com",
"company_id": self.company.id,
"company_ids": [(4, self.company.id)],
"operating_unit_ids": [(4, self.b2b.id), (4, self.b2c.id)],
"groups_id": [(6, 0, [self.grp_acc_manager.id])],
}
)
# Create cash - test account
user_type = self.env.ref("account.data_account_type_current_assets")
self.current_asset_account_id = self.account_model.create(
{
"name": "Current asset - Test",
"code": "test_current_asset",
"user_type_id": user_type.id,
"company_id": self.company.id,
}
)
# Create Inter-OU Clearing - test account
user_type = self.env.ref("account.data_account_type_equity")
self.inter_ou_account_id = self.account_model.create(
{
"name": "Inter-OU Clearing",
"code": "test_inter_ou",
"user_type_id": user_type.id,
"company_id": self.company.id,
}
)
# Assign the Inter-OU Clearing account to the company
self.company.inter_ou_clearing_account_id = self.inter_ou_account_id.id
self.company.ou_is_self_balanced = True
# Create user2
self.user2_id = self.res_users_model.with_context(
{"no_reset_password": True}
).create(
{
"name": "Test Account User",
"login": "user_2",
"password": "demo",
"email": "example@yourcompany.com",
"company_id": self.company.id,
"company_ids": [(4, self.company.id)],
"operating_unit_ids": [(4, self.b2c.id)],
"groups_id": [(6, 0, [self.grp_acc_manager.id])],
}
)
# Create a cash account 1
user_type = self.env.ref("account.data_account_type_liquidity")
self.cash1_account_id = self.account_model.create(
{
"name": "Cash 1 - Test",
"code": "test_cash_1",
"user_type_id": user_type.id,
"company_id": self.company.id,
}
)
# Create a journal for cash account 1, associated to the main
# operating unit
self.cash_journal_ou1 = self.journal_model.create(
{
"name": "Cash Journal 1 - Test",
"code": "test_cash_1",
"type": "cash",
"company_id": self.company.id,
"default_account_id": self.cash1_account_id.id,
"operating_unit_id": self.ou1.id,
}
)
# Create a cash account 2
user_type = self.env.ref("account.data_account_type_liquidity")
self.cash2_account_id = self.account_model.create(
{
"name": "Cash 2 - Test",
"code": "test_cash_2",
"user_type_id": user_type.id,
"company_id": self.company.id,
}
)
# Create a journal for cash account 2, associated to the operating
# unit B2B
self.cash2_journal_b2b = self.journal_model.create(
{
"name": "Cash Journal 2 - Test",
"code": "test_cash_2",
"type": "cash",
"company_id": self.company.id,
"default_account_id": self.cash2_account_id.id,
"operating_unit_id": self.b2b.id,
}
)
def _prepare_invoice(self, operating_unit_id, name="Test Supplier Invoice"):
line_products = [
(self.product1, 1000),
(self.product2, 500),
(self.product3, 800),
]
# Prepare invoice lines
lines = []
acc_type = self.env.ref("account.data_account_type_expenses")
for product, qty in line_products:
line_values = {
"name": product.name,
"product_id": product.id,
"quantity": qty,
"price_unit": 50,
"account_id": self.env["account.account"]
.search([("user_type_id", "=", acc_type.id)], limit=1)
.id,
}
lines.append((0, 0, line_values))
inv_vals = {
"partner_id": self.partner1.id,
"operating_unit_id": operating_unit_id,
"name": name,
"move_type": "in_invoice",
"invoice_line_ids": lines,
}
return inv_vals
@@ -0,0 +1,99 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import odoo.tests
from . import test_account_operating_unit as test_ou
@odoo.tests.tagged("post_install", "-at_install")
class TestCrossOuJournalEntry(test_ou.TestAccountOperatingUnit):
def test_cross_ou_journal_entry(self):
"""Test balance of cross OU journal entries.
Test that when I create a manual journal entry with multiple
operating units, new cross-operating unit entries are created
automatically whent the journal entry is posted, ensuring that each
OU is self-balanced."""
# Create Journal Entries and check the balance of the account
# based on different operating units.
self.company.write(
{"inter_ou_clearing_account_id": self.inter_ou_account_id.id}
)
self.acc_move_model = self.env["account.move"]
self.journal_model = self.env["account.journal"]
# Create Journal Entries
journal_ids = self.journal_model.search(
[("code", "=", "MISC"), ("company_id", "=", self.company.id)], limit=1
)
# get default values of account move
move_vals = self.acc_move_model.default_get([])
lines = [
(
0,
0,
{
"name": "Test",
"account_id": self.current_asset_account_id.id,
"debit": 0,
"credit": 100,
"operating_unit_id": self.b2b.id,
},
),
(
0,
0,
{
"name": "Test",
"account_id": self.current_asset_account_id.id,
"debit": 100,
"credit": 0,
"operating_unit_id": self.b2c.id,
},
),
]
move_vals.update(
{"journal_id": journal_ids and journal_ids.id, "line_ids": lines}
)
move = self.acc_move_model.with_user(self.user_id.id).create(move_vals)
# Post journal entries
move.action_post()
# Check the balance of the account
self._check_balance(self.current_asset_account_id.id, acc_type="other")
clearing_account_id = self.company.inter_ou_clearing_account_id.id
self._check_balance(clearing_account_id, acc_type="clearing")
def _check_balance(self, account_id, acc_type="clearing"):
# Check balance for all operating units
domain = [("account_id", "=", account_id)]
balance = self._get_balance(domain)
self.assertEqual(balance, 0.0, "Balance is 0 for all Operating Units.")
# Check balance for operating B2B units
domain = [
("account_id", "=", account_id),
("operating_unit_id", "=", self.b2b.id),
]
balance = self._get_balance(domain)
if acc_type == "other":
self.assertEqual(balance, -100, "Balance is -100 for Operating Unit B2B.")
else:
self.assertEqual(balance, 100, "Balance is 100 for Operating Unit B2B.")
# Check balance for operating B2C units
domain = [
("account_id", "=", account_id),
("operating_unit_id", "=", self.b2c.id),
]
balance = self._get_balance(domain)
if acc_type == "other":
self.assertEqual(balance, 100.0, "Balance is 100 for Operating Unit B2C.")
else:
self.assertEqual(balance, -100.0, "Balance is -100 for Operating Unit B2C.")
def _get_balance(self, domain):
"""
Call read_group method and return the balance of particular account.
"""
aml_rec = self.aml_model.with_user(self.user_id.id).read_group(
domain, ["debit", "credit", "account_id"], ["account_id"]
)[0]
return aml_rec.get("debit", 0) - aml_rec.get("credit", 0)
@@ -0,0 +1,35 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import odoo.tests
from . import test_account_operating_unit as test_ou
@odoo.tests.tagged("post_install", "-at_install")
class TestInvoiceOperatingUnit(test_ou.TestAccountOperatingUnit):
def test_create_invoice_validate(self):
"""Create & Validate the invoice.
Test that when an invoice is created, the operating unit is
passed to the accounting journal items.
"""
# Create invoice
self.invoice = self.move_model.with_user(self.user_id.id).create(
self._prepare_invoice(self.b2b.id)
)
self.invoice.invoice_date = self.invoice.date
# Validate the invoice
self.invoice.with_user(self.user_id.id).action_post()
# Check Operating Units in journal entries
all_op_units = all(
move_line.operating_unit_id.id == self.b2b.id
for move_line in self.invoice.line_ids
)
# Assert if journal entries of the invoice
# have different operating units
self.assertNotEqual(
all_op_units,
False,
"Journal Entries have different Operating Units.",
)
@@ -0,0 +1,21 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import odoo.tests
from . import test_account_operating_unit as test_ou
@odoo.tests.tagged("post_install", "-at_install")
class TestOuSecurity(test_ou.TestAccountOperatingUnit):
def test_security(self):
"""Test Security of Account Operating Unit"""
# User 2 is only assigned to Operating Unit B2C, and cannot list
# Journal Entries from Operating Unit B2B.
move_ids = self.aml_model.with_user(self.user2_id.id).search(
[("operating_unit_id", "=", self.b2b.id)]
)
self.assertFalse(
move_ids, "user_2 should not have access to OU %s" % self.b2b.name
)
@@ -0,0 +1,109 @@
# © 2019 ForgeFlow S.L.
# © 2019 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import time
import odoo.tests
from . import test_account_operating_unit as test_ou
@odoo.tests.tagged("post_install", "-at_install")
class TestInvoiceOperatingUnit(test_ou.TestAccountOperatingUnit):
def test_payment_from_invoice(self):
"""Create and invoice and a subsquent payment, in another OU"""
# Create invoice for B2B operating unit
self.invoice = self.move_model.with_user(self.user_id.id).create(
self._prepare_invoice(self.b2b.id)
)
self.invoice.invoice_date = self.invoice.date
# Validate the invoice
self.invoice.with_user(self.user_id.id).action_post()
# Pay the invoice using a cash journal associated to the main company
ctx = {"active_model": "account.move", "active_ids": [self.invoice.id]}
register_payments = self.register_payments_model.with_context(ctx).create(
{
"payment_date": time.strftime("%Y") + "-07-15",
"journal_id": self.cash_journal_ou1.id,
"payment_method_id": self.payment_method_manual_in.id,
}
)
register_payments.action_create_payments()
payment = self.payment_model.search([], order="id desc", limit=1)
# Validate that inter OU balance move lines are created
self.assertEqual(len(payment.move_id.line_ids), 4)
self.assertAlmostEqual(payment.amount, 115000)
self.assertEqual(payment.state, "posted")
self.assertEqual(self.invoice.payment_state, "paid")
def test_payment_from_two_invoices(self):
"""Create two invoices of different OU and payment from a third OU"""
# Create invoices for B2B and B2C operating units
to_create = [
self._prepare_invoice(self.b2b.id, "SUPP/B2B/01"),
self._prepare_invoice(self.b2c.id, "SUPP/B2C/02"),
]
invoices = self.move_model.with_user(self.user_id.id).create(to_create)
for invoice in invoices:
invoice.invoice_date = invoice.date
# Validate the invoices
invoices.with_user(self.user_id.id).action_post()
# Pay the invoices using a cash journal associated to the main company
ctx = {"active_model": "account.move", "active_ids": invoices.ids}
register_payments = self.register_payments_model.with_context(ctx).create(
{
"payment_date": time.strftime("%Y") + "-07-15",
"journal_id": self.cash_journal_ou1.id,
"payment_method_id": self.payment_method_manual_in.id,
}
)
register_payments.action_create_payments()
payments = self.payment_model.search([], order="id desc", limit=2)
for payment in payments:
# Validate that inter OU balance move lines are created
self.assertEqual(len(payment.move_id.line_ids), 4)
self.assertAlmostEqual(payment.amount, 115000)
self.assertEqual(payment.state, "posted")
for invoice in invoices:
self.assertEqual(invoice.payment_state, "paid")
def test_payment_transfer(self):
"""Create a transfer payment with journals in different OU"""
payments = self.payment_model.create(
{
"payment_type": "outbound",
"amount": 115000,
"date": time.strftime("%Y") + "-07-15",
"journal_id": self.cash_journal_ou1.id,
"destination_account_id": self.company.transfer_account_id.id,
"payment_method_id": self.payment_method_manual_in.id,
"is_internal_transfer": True,
}
)
payments |= self.payment_model.create(
{
"payment_type": "inbound",
"amount": 115000,
"date": time.strftime("%Y") + "-07-15",
"journal_id": self.cash2_journal_b2b.id,
"destination_account_id": self.company.transfer_account_id.id,
"payment_method_id": self.payment_method_manual_in.id,
"is_internal_transfer": True,
}
)
payments.action_post()
self.assertEqual(len(payments.move_id.mapped("line_ids.operating_unit_id")), 2)
# Validate that every move has their correct OU
for move in payments.move_id:
ou_in_lines = move.line_ids.operating_unit_id
self.assertEqual(len(ou_in_lines), 1)
ou_in_journal = move.journal_id.operating_unit_id
self.assertEqual(ou_in_lines, ou_in_journal)
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2016-17 ForgeFlow S.L.-->
<!--© 2016 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<record id="view_account_invoice_report_search" model="ir.ui.view">
<field name="name">account.invoice.report.search</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_search" />
<field name="arch" type="xml">
<field name="invoice_date" position="after">
<field
name="operating_unit_id"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
<xpath expr="//filter[1]" position="after">
<filter
name='group_by_operating_unit'
string="Operating Unit"
context="{'group_by':'operating_unit_id'}"
groups="operating_unit.group_multi_operating_unit"
/>
</xpath>
</field>
</record>
</odoo>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2016-17 ForgeFlow S.L.-->
<!--© 2016 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<record id="view_account_journal_form" model="ir.ui.view">
<field name="name">account.journal.form</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form" />
<field name="arch" type="xml">
<field name="company_id" position="after">
<field
name="operating_unit_id"
options="{'no_create': True}"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
</field>
</record>
</odoo>
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2016-17 ForgeFlow S.L.-->
<!--© 2016 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<record id="view_move_aa_form" model="ir.ui.view">
<field name="name">account.move.aa.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath expr="//group[@id='header_right_group']" position="inside">
<field
name="analytic_account_id"
options="{'no_create': True, 'no_create_edit': True}" required="1"
/>
</xpath>
</field>
</record>
<record id="view_move_line_aa_form" model="ir.ui.view">
<field name="name">account.move.line.aa.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_line_ids']//tree//field[@name='analytic_account_id']" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
<attribute name="readonly">1</attribute>
</xpath>
</field>
</record>
<record id="view_move_line_aa_item" model="ir.ui.view">
<field name="name">account.move.line.aa.item</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='line_ids']//tree//field[@name='analytic_account_id']" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
</xpath>
</field>
</record>
<!-- <record id="view_account_move_attribute_form" model="ir.ui.view">-->
<!-- <field name="name">account.account.move.attribute.form</field>-->
<!-- <field name="model">account.move</field>-->
<!-- <field name="inherit_id" ref="account.view_move_form" />-->
<!-- <field name="arch" type="xml">-->
<!-- <xpath expr="//field[@name='partner_id']" position="attributes">-->
<!-- <attribute name="options">{'no_create': True, 'no_create_edit': True}</attribute>/>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
</odoo>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="view_move_line_account_item" model="ir.ui.view">
<field name="name">account.move.line.account.item</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='line_ids']//tree//field[@name='account_id']" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
</xpath>
</field>
</record>
</data>
</odoo>
@@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2016-17 ForgeFlow S.L.-->
<!--© 2016 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<record id="view_move_line_form" model="ir.ui.view">
<field name="name">account.move.line.form</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='account_id']" position="after">
<field
name="operating_unit_id"
options="{'no_create': True}"
groups="operating_unit.group_multi_operating_unit"
/>
</xpath>
</field>
</record>
<record id="view_move_line_tree" model="ir.ui.view">
<field name="name">account.move.line.tree</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_tree" />
<field name="arch" type="xml">
<xpath expr="//field[@name='account_id']" position="after">
<field
name="operating_unit_id"
options="{'no_create': True}"
optional="show"
groups="operating_unit.group_multi_operating_unit"
/>
</xpath>
</field>
</record>
<record id="view_account_move_line_filter" model="ir.ui.view">
<field name="name">Journal Items</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_account_move_line_filter" />
<field name="arch" type="xml">
<field name="account_id" position="after">
<field
name="operating_unit_id"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
<filter name="group_by_account" position="after">
<filter
string="Operating Unit"
name="operating_unit_grouped"
icon="terp-folder-green"
context="{'group_by':'operating_unit_id'}"
groups="operating_unit.group_multi_operating_unit"
/>
</filter>
</field>
</record>
<record id="view_move_form" model="ir.ui.view">
<field name="name">account.move.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath expr="//group[@id='header_right_group']" position="inside">
<field
name="operating_unit_id"
invisible = '1'
options="{'no_create': True}"
groups="operating_unit.group_multi_operating_unit"
/>
</xpath>
<field name="invoice_line_ids" position="attributes">
<attribute name="context">
{'default_move_type': context.get('default_move_type'),
'journal_id':
journal_id, 'default_partner_id': commercial_partner_id,
'default_currency_id': currency_id or company_currency_id,
'operating_unit_id': operating_unit_id}
</attribute>
</field>
<xpath
expr="//field[@name='invoice_line_ids']/tree/field[@name='analytic_account_id']"
position="attributes"
>
<attribute name="domain">
['|', ('company_id', '=', False), ('company_id', '=',
parent.company_id), '|', ('operating_unit_ids', '=',
context.get('operating_unit_id', False)), ('operating_unit_ids',
'=', False)]
</attribute>
</xpath>
<xpath
expr="//field[@name='invoice_line_ids']//form//field[@name='analytic_account_id']"
position="attributes"
>
<attribute name="domain">
['|', ('operating_unit_ids', '=', context.get('operating_unit_id',
False)), ('operating_unit_ids', '=', False)]
</attribute>
</xpath>
<field name="line_ids" position="attributes">
<attribute name="context">
{
'default_move_type': context.get('default_move_type'),
'line_ids': line_ids,
'journal_id': journal_id,
'default_partner_id': commercial_partner_id,
'default_currency_id': currency_id or company_currency_id,
'default_operating_unit_id': operating_unit_id}
</attribute>
</field>
<xpath
expr="//field[@name='line_ids']/tree//field[@name='account_id']"
position="after"
>
<field
name="operating_unit_id"
options="{'no_create': True}"
optional="show"
groups="operating_unit.group_multi_operating_unit"
/>
</xpath>
<xpath
expr="//field[@name='line_ids']/tree/field[@name='analytic_account_id']"
position="attributes"
>
<attribute name="domain">
['|', ('company_id', '=', parent.company_id), ('company_id', '=',
False), '|', ('operating_unit_ids', '=',
context.get('default_operating_unit_id', False)),
('operating_unit_ids', '=', False)]
</attribute>
</xpath>
<xpath
expr="//field[@name='line_ids']/form/group/field[@name='analytic_account_id']"
position="attributes"
>
<attribute name="domain">
['|', ('operating_unit_ids', '=',
context.get('default_operating_unit_id', False)),
('operating_unit_ids', '=', False)]
</attribute>
</xpath>
</field>
</record>
<record id="view_invoice_tree" model="ir.ui.view">
<field name="name">account.invoice.tree</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_invoice_tree" />
<field name="arch" type="xml">
<field name="company_id" position="before">
<field
name="operating_unit_id"
options="{'no_create': True}"
optional="show"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
</field>
</record>
<record id="view_account_invoice_filter" model="ir.ui.view">
<field name="name">account.invoice.select</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_invoice_filter" />
<field name="arch" type="xml">
<field name="invoice_user_id" position="after">
<field
name="operating_unit_id"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
<filter name="salesperson" position="after">
<filter
string="Operating Unit"
name="operating_unit_grouped"
icon="terp-folder-orange"
domain="[]"
groups="operating_unit.group_multi_operating_unit"
context="{'group_by':'operating_unit_id'}"
/>
</filter>
</field>
</record>
</odoo>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2016-17 ForgeFlow S.L.-->
<!--© 2016 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<record id="view_account_payment_tree" model="ir.ui.view">
<field name="name">account.payment.tree</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_tree" />
<field name="arch" type="xml">
<field name="journal_id" position="after">
<field
name="operating_unit_id"
options="{'no_create': True}"
optional="show"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
</field>
</record>
<record id="view_account_payment_search" model="ir.ui.view">
<field name="name">account.payment.search</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_search" />
<field name="arch" type="xml">
<field name="journal_id" position="after">
<field
name="operating_unit_id"
groups="operating_unit.group_multi_operating_unit"
/>
<filter
string="Operating Unit"
name="operating_unit_grouped"
domain="[]"
context="{'group_by': 'operating_unit_id'}"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
</field>
</record>
<!-- <record id="view_account_payment_form" model="ir.ui.view">-->
<!-- <field name="name">account.payment.form</field>-->
<!-- <field name="model">account.payment</field>-->
<!-- <field name="inherit_id" ref="account.view_account_payment_form" />-->
<!-- <field name="arch" type="xml">-->
<!-- <field name="journal_id" position="after">-->
<!-- <field-->
<!-- name="operating_unit_id"-->
<!-- options="{'no_create': True}"-->
<!-- groups="operating_unit.group_multi_operating_unit"-->
<!-- />-->
<!-- </field>-->
<!-- </field>-->
<!-- </record>-->
</odoo>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--© 2016-17 ForgeFlow S.L.-->
<!--© 2016 Serpent Consulting Services Pvt. Ltd.-->
<!--License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<!-- <record id="view_company_form" model="ir.ui.view">-->
<!-- <field name="name">res.company.form</field>-->
<!-- <field name="model">res.company</field>-->
<!-- <field name="inherit_id" ref="base.view_company_form" />-->
<!-- <field name="arch" type="xml">-->
<!-- <xpath expr="//notebook/page/group" position="after">-->
<!-- <group string="Operating Units">-->
<!-- <field name="ou_is_self_balanced" />-->
<!-- <field name="inter_ou_clearing_account_id" />-->
<!-- </group>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
</odoo>
@@ -0,0 +1,3 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import account_payment_register
@@ -0,0 +1,38 @@
# © 2020 Jarsa Sistemas, SA de CV
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import models
class AccountPaymentRegister(models.TransientModel):
_inherit = "account.payment.register"
def _create_payments(self):
payments = super()._create_payments()
if self.group_payment and len(payments) > 1:
return payments
for payment in payments:
to_reconcile = self.env["account.move.line"]
reconciled_moves = (
payment.reconciled_bill_ids + payment.reconciled_invoice_ids
)
if reconciled_moves.operating_unit_id != payment.operating_unit_id:
destination_account = payments.destination_account_id
to_reconcile |= payment.move_id.line_ids.filtered(
lambda l: l.account_id == destination_account
)
to_reconcile |= reconciled_moves.line_ids.filtered(
lambda l: l.account_id == destination_account
)
payment.action_draft()
line = payment.move_id.line_ids.filtered(
lambda l: l.account_id == destination_account
)
line.write(
{
"operating_unit_id": reconciled_moves.operating_unit_id.id,
}
)
payment.action_post()
to_reconcile.reconcile()
return payments
+2
View File
@@ -0,0 +1,2 @@
from . import models
from . import wizard
+54
View File
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#############################################################################
#
#
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': 'Asset Sell Or Dispose',
'category': 'Asset',
'version':'14.0',
'summary': "Selling or Disposing of Assets",
'author': 'APPSGATE FZC LLC',
'depends': ['account','base_accounting_kit'],
'description':"""
asset,
sell,
dispose,
asset management,
""",
'data': [
'security/ir.model.access.csv',
'views/asset_split.xml',
'views/account_view.xml',
'wizard/asset_dep_wizard.xml',
'wizard/asset_sell_view.xml'
],
'demo': [
],
'images':[
'static/src/img/main-screenshot.png'
],
'license': 'AGPL-3',
'price':'10',
'currency':'USD',
'application': True,
'installable': True,
'auto_install': False,
}
+3
View File
@@ -0,0 +1,3 @@
from . import asset_split
from . import account
from . import res_company
+109
View File
@@ -0,0 +1,109 @@
from odoo import api, fields, models
from odoo import tools
from odoo.exceptions import UserError
from odoo.tools import float_compare
from odoo.tools.misc import formatLang
from dateutil.relativedelta import relativedelta
class AccountMove(models.Model):
_inherit = 'account.move'
categ_asset_id = fields.Many2one('account.asset.category', string='Category')
asset_type = fields.Selection([('sale', 'Sale: Revenue Recognition'), ('purchase', 'Purchase: Asset'), ('expense', 'Deferred Expense')], index=True, readonly=False, states={'draft': [('readonly', False)]})
# remaining_value = fields.Monetary(string='Depreciable Value', copy=False)
# depreciated_value = fields.Monetary(string='Cumulative Depreciation', copy=False)
# def _reverse_moves(self, default_values_list=None, cancel=False):
# for move in self:
# # Report the value of this move to the next draft move or create a new one
# if move.asset_id:
# # Set back the amount in the asset as the depreciation is now void
# move.asset_id.value_residual += move.amount_total
# # Recompute the status of the asset for all depreciations posted after the reversed entry
# for later_posted in move.asset_id.depreciation_move_ids.filtered(lambda m: m.date >= move.date and m.state == 'posted'):
# later_posted.depreciated_value -= move.amount_total
# later_posted.remaining_value += move.amount_total
# first_draft = min(move.asset_id.depreciation_move_ids.filtered(lambda m: m.state == 'draft'), key=lambda m: m.date, default=None)
# if first_draft:
# # If there is a draft, simply move/add the depreciation amount here
# # The depreciated and remaining values don't need to change
# first_draft.amount_total += move.amount_total
# else:
# # If there was no raft move left, create one
# last_date = max(move.asset_id.depreciation_move_ids.mapped('date'))
# method_period = move.asset_id.method_period
# self.create(self._prepare_move_for_asset_depreciation({
# 'asset_id': move.asset_id,
# 'move_ref': _('Report of reversal for {name}').format(move.asset_id.name),
# 'amount': move.amount_total,
# 'date': last_date + (relativedelta(months=1) if method_period == "1" else relativedelta(years=1)),
# 'depreciated_value': move.amount_total + max(move.asset_id.depreciation_move_ids.mapped('depreciated_value')),
# 'remaining_value': 0,
# }))
# msg = _('Depreciation entry %s reversed (%s)') % (move.name, formatLang(self.env, move.amount_total, currency_obj=move.company_id.currency_id))
# move.asset_id.message_post(body=msg)
# # If an asset was created for this move, delete it when reversing the move
# for line in move.line_ids:
# if line.asset_id.state == 'draft' or all(state == 'draft' for state in line.asset_id.depreciation_move_ids.mapped('state')):
# line.asset_id.state = 'draft'
# line.asset_id.unlink()
# return super(AccountMove, self)._reverse_moves(default_values_list, cancel)
# @api.model
# def _prepare_move_for_asset_depreciation(self, vals):
# missing_fields = set(['asset_id', 'move_ref', 'amount', 'remaining_value', 'depreciated_value']) - set(vals)
# if missing_fields:
# raise UserError(_('Some fields are missing {}').format(', '.join(missing_fields)))
# asset = vals['asset_id']
# account_analytic_id = asset.account_analytic_id
# analytic_tag_ids = asset.analytic_tag_ids
# depreciation_date = vals.get('date', fields.Date.context_today(self))
# company_currency = asset.company_id.currency_id
# current_currency = asset.currency_id
# prec = company_currency.decimal_places
# amount = current_currency._convert(vals['amount'], company_currency, asset.company_id, depreciation_date)
# move_line_1 = {
# 'name': asset.name,
# 'account_id': asset.account_depreciation_id.id,
# 'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
# 'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
# 'analytic_account_id': account_analytic_id.id if asset.asset_type == 'sale' else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if asset.asset_type == 'sale' else False,
# 'currency_id': company_currency != current_currency and current_currency.id or False,
# 'amount_currency': company_currency != current_currency and - 1.0 * vals['amount_total'] or 0.0,
# }
# move_line_2 = {
# 'name': asset.name,
# 'account_id': asset.account_depreciation_expense_id.id,
# 'credit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
# 'debit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
# 'analytic_account_id': account_analytic_id.id if asset.asset_type in ('purchase', 'expense') else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if asset.asset_type in ('purchase', 'expense') else False,
# 'currency_id': company_currency != current_currency and current_currency.id or False,
# 'amount_currency': company_currency != current_currency and vals['amount_total'] or 0.0,
# }
# move_vals = {
# 'ref': vals['move_ref'],
# 'date': depreciation_date,
# 'journal_id': asset.journal_id.id,
# 'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
# 'auto_post': asset.state == 'open',
# 'asset_id': asset.id,
# 'remaining_value': vals['emaining_value'],
# 'depreciated_value': vals['depreciated_value'],
# 'amount_total': amount,
# 'name': '/',
# 'asset_value_change': vals.get('asset_value_change', False),
# 'type': 'entry',
# }
# return move_vals
# @api.model
# def create_asset_move(self, vals):
# move_vals = self._prepare_move_for_asset_depreciation(vals)
# return self.env['account.move'].create(move_vals)
+325
View File
@@ -0,0 +1,325 @@
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools import float_compare, float_is_zero
from math import copysign
from odoo.tools import float_compare
from odoo.tools.misc import formatLang
class AccountAssetAsset(models.Model):
_inherit = 'account.asset.asset'
sales_value = fields.Float(string='Sale Value')
children_ids = fields.One2many('account.asset.asset', 'parent_id', help="The children are the gains in value of this asset")
parent_id = fields.Many2one('account.asset.asset', help="An asset has a parent when it is the result of gaining value")
#depreciation_move_ids = fields.One2many('account.move', 'asset_id', string='Depreciation Lines', readonly=True, states={'draft': [('readonly', False)], 'open': [('readonly', False)], 'paused': [('readonly', False)]})
disposal_date = fields.Date(readonly=True, states={'draft': [('readonly', False)]},)
asset_type = fields.Selection([('sale', 'Sale: Revenue Recognition'), ('purchase', 'Purchase: Asset'), ('expense', 'Deferred Expense')], index=True, readonly=False, states={'draft': [('readonly', False)]})
account_analytic_id = fields.Many2one('account.analytic.account')
def action_set_to_close(self):
""" Returns an action opening the asset pause wizard."""
self.ensure_one()
# new_wizard = self.env['account.asset.sell'].create({
# 'asset_id': self.id,
# 'action':'sell',
# })
return {
'name': _('Sell Asset'),
'view_mode': 'form',
'res_model': 'account.asset.sell',
'type': 'ir.actions.act_window',
'target': 'new',
'context':{
'default_assets_id': self.id,
}
# 'res_id': new_wizard.id,
}
# def action_set_to_close(self):
# """ Returns an action opening the asset pause wizard."""
# self.ensure_one()
# new_wizard = self.env['account.asset.sell'].create({
# 'assets_id': self.id,
# })
# return {
# 'name': _('Sell Asset'),
# 'view_mode': 'form',
# 'res_model': 'account.asset.sell',
# 'type': 'ir.actions.act_window',
# 'target': 'new',
# 'res_id': new_wizard.id,
# }
def set_to_close(self, invoice_line_id, date=None):
#res = super(AccountAssetAsset, self).set_to_close()
print('---set_to_close---')
for rec in self:
rec.ensure_one()
disposal_date = date or fields.Date.today()
if invoice_line_id and rec.children_ids:
raise UserError("You cannot automate the journal entry for an asset that has had a gross increase. Please use 'Dispose' and modify the entries.")
move_ids = rec._get_disposal_moves([invoice_line_id], disposal_date)
rec.write({'state': 'close', 'disposal_date': disposal_date})
if move_ids:
# raise UserError("test2")
return rec._return_disposal_view(move_ids)
#return res
# def set_to_running(self):
# if self.depreciation_line_ids and not max(self.depreciation_line_ids, key=lambda m: m.move_id.date).asset_remaining_value == 0:
# self.env['asset.modify'].create({'asset_id': self.id, 'name': _('Reset to running')}).modify()
# self.write({'state': 'open', 'disposal_date': False})
def _return_disposal_view(self, move_ids):
name = _('Disposal Move')
view_mode = 'form'
if len(move_ids) > 1:
name = _('Disposal Moves')
view_mode = 'tree,form'
return {
'name': name,
'view_mode': view_mode,
'res_model': 'account.move',
'type': 'ir.actions.act_window',
'target': 'current',
'res_id': move_ids[0],
'domain': [('id', 'in', move_ids)]
}
def _get_disposal_moves(self, invoice_line_ids, disposal_date):
def get_line(asset, amount, account):
return (0, 0, {
'name': asset.name,
'account_id': account.id,
'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
# 'analytic_account_id': account_analytic_id.id if asset.asset_type == 'sale' else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if asset.asset_type == 'sale' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - 1.0 * asset.value_residual or 0.0,
})
move_ids = []
assert len(self) == len(invoice_line_ids)
for asset, invoice_line_id in zip(self, invoice_line_ids):
if disposal_date < max(asset.depreciation_line_ids.filtered(
lambda x: not x.move_id.reversal_move_id and x.move_id.state == 'posted').mapped('move_id.date') or [fields.Date.today()]): #.mapped('date')
if invoice_line_id:
raise UserError(
'There are depreciation posted after the invoice date (%s).\nPlease revert them or change the date of the invoice.' % disposal_date)
else:
raise UserError('There are depreciation posted in the future, please revert them.')
# Also dispose of the children
# This is not implemented for selling with an invoice.
if not invoice_line_id and asset.children_ids:
move_ids += asset.children_ids._get_disposal_moves(
[self.env['account.move.line']] * len(asset.children_ids), disposal_date)
# account_analytic_id = asset.account_analytic_id
# analytic_tag_ids = asset.analytic_tag_ids
company_currency = asset.company_id.currency_id
current_currency = asset.currency_id
prec = company_currency.decimal_places
unposted_depreciation_line_ids = asset.depreciation_line_ids.filtered(lambda x: not x.move_check)
if unposted_depreciation_line_ids:
old_values = {
'method_end': asset.method_end,
'method_number': asset.method_number,
}
# Remove all unposted depr. lines
commands = [(2, line_id.id, False) for line_id in unposted_depreciation_line_ids]
# Create a new depr. line with the residual amount and post it
asset_sequence = len(asset.depreciation_line_ids) - len(unposted_depreciation_line_ids) + 1
initial_amount = asset.value
initial_account = asset.category_id.account_asset_id
depreciated_amount = asset.value_residual - initial_amount
# copysign(
# sum(asset.depreciation_line_ids.filtered(lambda r: r.move_id.state == 'posted').mapped('amount')),
# -initial_amount)
depreciation_account = asset.category_id.account_depreciation_id
invoice_amount = copysign(invoice_line_id.price_subtotal, -initial_amount)
invoice_account = invoice_line_id.account_id
difference = -initial_amount - depreciated_amount - invoice_amount
difference_account = asset.company_id.gain_account_id if difference > 0 else asset.company_id.loss_account_id
line_datas = [(initial_amount,initial_account), (depreciated_amount, depreciation_account),#initial_account
(invoice_amount, invoice_account), (difference, difference_account)]
print("******************************************************************\n")
print(initial_amount)
print("\n")
print(initial_account)
print("\n")
print(depreciated_amount)
print("\n")
print(depreciation_account)
print("\n")
print(invoice_amount)
print("\n")
print(invoice_account)
print("\n")
print(difference)
print("\n")
print(difference_account)
print("\n\n\n")
if not invoice_line_id:
del line_datas[2]
# raise UserError(asset_sequence)
seq_name = asset.name + ': ' + (_('Disposal') if not invoice_line_id else _('Sale'))
vals = {
'asset_id': asset.id,
'amount': asset.value_residual ,
'name': seq_name,
'sequence': asset_sequence,
'remaining_value': 0.0,
'depreciated_value': 0.0,
'depreciation_date': disposal_date,
# 'journal_id': asset.category_id.journal_id.id,
# 'move_lines': ,
# 'move_id': [get_line(asset, amount, account) for amount, account in line_datas if account],
}
move_lines = [get_line(asset, amount, account) for amount, account in line_datas if account]
commands.append((0, 0, vals))
asset.write({'depreciation_line_ids': commands,'method_number': asset_sequence})
# raise UserError("test2")
tracked_fields = self.env['account.asset.asset'].fields_get(['method_number','method_end'])
changes, tracking_value_ids = asset._message_track(tracked_fields, old_values)
if changes:
asset.message_post(body=_('Asset sold or disposed. Accounting entry awaiting for validation.'),
tracking_value_ids=tracking_value_ids)
#move_ids += self.env['account.move'].search([('asset_id', '=', asset.id), ('state', '=', 'draft')]).ids
print("********************************************************************************************\n")
print(move_lines)
print("\n********************************************************************************************")
move_ids += asset.depreciation_line_ids[-1].create_move(post_move=False)
return move_ids
class AccountAssetDepreciationLine(models.Model):
_inherit = 'account.asset.depreciation.line'
def _prepare_move(self, line,move_lines=None):
category_id = line.asset_id.category_id
# account_analytic_id = line.asset_id.account_analytic_id
# analytic_tag_ids = line.asset_id.analytic_tag_ids
depreciation_date = self.env.context.get(
'depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
prec = company_currency.decimal_places
amount = current_currency._convert(
line.amount, company_currency, line.asset_id.company_id, depreciation_date)
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))#+ '/' +line.asset_id.asset_code
#asset_code_id = line.asset_id.asset_code + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
move_line_1 = {
'name': asset_name,
# 'asset_category_id': category_id.id,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'partner_id': line.asset_id.partner_id.id,
# 'analytic_account_id': account_analytic_id.id if category_id.type == 'sale' else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'sale' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0,
}
move_line_2 = {
'name': asset_name,
# 'asset_category_id': category_id.id,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'debit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'partner_id': line.asset_id.partner_id.id,
# 'analytic_account_id': account_analytic_id.id if category_id.type == 'purchase' else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'purchase' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and line.amount or 0.0,
}
# move_vals = {
# 'ref': line.asset_id.name + '/' + line.asset_id.asset_code,
# 'date': depreciation_date or False,
# 'journal_id': category_id.journal_id.id,
# 'categ_asset_id': category_id.id,
# 'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
# }
if move_lines:
move_vals = {
'ref': line.asset_id.code,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'categ_asset_id': category_id.id,
'line_ids': move_lines,
}
else:
move_vals = {
'ref': line.asset_id.code,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'categ_asset_id': category_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
return move_vals
def _prepare_move_grouped(self):
asset_id = self[0].asset_id
category_id = asset_id.category_id # we can suppose that all lines have the same category
# account_analytic_id = asset_id.account_analytic_id
# analytic_tag_ids = asset_id.analytic_tag_ids
depreciation_date = self.env.context.get('depreciation_date') or fields.Date.context_today(self)
amount = 0.0
for line in self:
# Sum amount of all depreciation lines
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
company = line.asset_id.company_id
amount += current_currency._convert(line.amount, company_currency, company, fields.Date.today())
name = category_id.name + _(' (grouped)')
move_line_1 = {
'name': name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0,
'credit': amount,
'journal_id': category_id.journal_id.id,
# 'analytic_account_id': account_analytic_id.id if category_id.type == 'sale' else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'sale' else False,
}
move_line_2 = {
'name': name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0,
'debit': amount,
'journal_id': category_id.journal_id.id,
# 'analytic_account_id': account_analytic_id.id if category_id.type == 'purchase' else False,
# 'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'purchase' else False,
}
move_vals = {
'ref': category_id.name,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'categ_asset_id': category_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
return move_vals
@@ -0,0 +1,19 @@
from odoo import api, fields, models, _
class ResCompany(models.Model):
_inherit = "res.company"
gain_account_id = fields.Many2one('account.account', domain="[('deprecated', '=', False), ('company_id', '=', id)]", help="Account used to write the journal item in case of gain while selling an asset")
loss_account_id = fields.Many2one('account.account', domain="[('deprecated', '=', False), ('company_id', '=', id)]", help="Account used to write the journal item in case of loss while selling an asset")
asset_income_account_id = fields.Many2one('account.account',string="Asset Income Account", domain="[('deprecated', '=', False), ('company_id', '=', id)]", help="Account used to write the journal item in case of loss while selling an asset")
class ProductTemplate(models.Model):
_inherit = 'product.template'
@api.onchange('is_asset')
def _onchange_set_asset_income_account(self):
for rec in self:
if rec.is_asset == True:
rec.property_account_income_id = self.env.company.asset_income_account_id.id
# else:
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_asset_sell,account.asset.sell,model_account_asset_sell,account.group_account_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_asset_sell account.asset.sell model_account_asset_sell account.group_account_user 1 1 1 1
Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,186 @@
<section class="oe_container lead bi_title_box" style="padding: 3% 0% 0% 15%;">
<div >
<div >
<h2 class="oe_slogan bi_title" style="color:#9a3997;">
<b> ASSET SELL OR DISPOSE </b>
</h2>
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
Asset disposal is the removal of a long-term asset from the companys accounting records. It is an important concept because capital
assets are essential to successful business operations. Moreover, proper accounting of the disposal of an asset is critical to maintaining
updated and clean accounting records. Similarly asset selling is also an important factor to maintain the assets effectively.
</h3>
</div>
</div>
</section>
<section class="oe_container" style="padding: 3% 0% 0% 15%;">
<div>
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;color:#9a3997; font-weight: 600;margin: 0px !important;">
Features
</h2>
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;">
<ul><li>Asset Selling</li></ul>
</h3>
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;">
<ul><li>Asset Disposal.</li></ul>
</h3>
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;">
<ul><li>Maintaining Asset Accounting Records.</li></ul>
</h3>
</div>
</section>
<section class="oe_container lead" style="padding: 3% 0% 0% 15%;">
<div>
<h2 class="oe_slogan" style="color: #49a3fe;font-size: 35px;font-style: italic;font-weight:bolder;"> How to use this module
</h2>
</div>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell1.png" alt="" style="width: 95%;"/>
</div>
<div>
Here we can see an invoice, for the product Laptop with asset category Computers.
The Price for this particular asset is 12000. Which means we had bought this asset for 12000.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell2.png" alt="" style="width: 95%;"/>
</div>
<div>
Now, under the accounting menu, in assets an asset for Laptop is created and in the gross value
the price is 14000. Which means we are planning to sell it at price 14000.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell3.png" alt="" style="width: 95%;"/>
</div>
<div>
From the depreciation lines, we can post manually , now since, first depreciation line is posted one journal
entry gets created. By clicking on sell or dispose we can choose option to sell or dispose the asset.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell4.png" alt="" style="width: 95%;"/>
</div>
<div>
Here, in the action we can choose sell and the related invoice for the particular asset. Now automatically the Gain Account
is shown, this is because the value in our invoice is 12000 and the gross value is 14000. Since, we are selling for more price
than purchased, it will be posted in the Gain account.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell5.png" alt="" style="width: 95%;"/>
</div>
<div>
After we click on sell, the journal entries is created and the difference amount between sell and
purchase value is recorded in the gain account.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell6.png" alt="" style="width: 95%;"/>
</div>
<div>
After posting the entries, it will change the state to close and 2 journal entries are generated, one which we posted manually
and automatically created entry after selling.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell7.png" alt="" style="width: 95%;"/>
</div>
<div>
Now in the second case if we provide the Gross Value as 10000 which less than the purchase price.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell3.png" alt="" style="width: 95%;"/>
</div>
<div>
From the depreciation lines, we can post manually , now since, first depreciation line is posted one journal
entry gets created. By clicking on sell or dispose we can choose option to sell or dispose the asset.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell7.1.png" alt="" style="width: 95%;"/>
</div>
<div>
Here, it will go to the Loss Account and the difference will be recorded in the Loss Account.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell8.png" alt="" style="width: 95%;"/>
</div>
<div>
Apart, from selling we can also dispose the asset which is no longer required. From action you
can select dispose to dispose the asset.
</div>
</h3>
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;">
<div class="oe_row oe_spaced">
<img src="assetsell9.png" alt="" style="width: 95%;"/>
</div>
<div>
After selecting dispose , the amount will be recorded in the loss account automatically.
</div>
</h3>
</section>
<div style="padding-top:20px;">
<hr style="width: 100%;height: 4px;background: #2C0091;margin:0px 0px; ">
<hr style="width: 100%;height: 4px;background: #148963;margin:0px 0px; ">
<section class="oe_container" style="background-repeat:no-repeat; background-size:100%;padding: 2% 0% 6% 0%;">
<div class="oe_slogan text-center" style="margin-top:10px !important;margin-bottom: 0px;">
<div style="color:#269900;">
<h3 style="color:#2C0091;font-size:25px;">If You Need Any Help Please Feel Free To Contact US</h3><br/>
<h3 style="color:#2C0091;font-size:23px;"><i class="fa fa-envelope"></i> Email us <a href="mailto:info@apps-gate.net">info@apps-gate.net</a></h3><br/>
</div>
<br>
</div>
</section>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="view_invoice_asset_category">
<field name="name">account.move.supplier.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='ref']" position="after">
<field string="Asset Category" name="categ_asset_id" invisible="1"/>
</xpath>
<xpath expr="//field[@name='categ_asset_id']" position="after">
<field string="Asset Type" name="asset_type" invisible="1"/>
</xpath>
</field>
</record>
<record id="view_res_company_form_inher_gain" model="ir.ui.view">
<field name="name">res.company.form.inherit.gain</field>
<field name="model">res.company</field>
<field name="priority">2</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='email']" position="after">
<field name="gain_account_id" string="Asset Gain Account"/>
<field name="loss_account_id" string="Asset Loss Account"/>
<field name="asset_income_account_id" string="Asset Income Account"/>
</xpath>
</field>
</record>
</odoo>
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record model="ir.ui.view" id="view_account_asset_asset_form_inherit">
<field name="name">account.asset.asset.form.inherit</field>
<field name="model">account.asset.asset</field>
<field name="inherit_id" ref="base_accounting_kit.view_account_asset_asset_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet/group/group[2]/field[@name='invoice_id']" position="after">
<field name="sales_value" invisible="1" options="{'no_create': True}"/>
</xpath>
<xpath expr="//button[@name='set_to_close']" position="replace">
<button name="action_set_to_close" states="open" string="Sell or Dispose" type="object" class="oe_highlight"/>
</xpath>
<xpath expr="//field[@name='date']" position="after">
<field name="disposal_date" invisible="1"/>
</xpath>
<xpath expr="//field[@name='disposal_date']" position="after">
<field name="asset_type" invisible="1"/>
</xpath>
<!-- <xpath expr="//button[@name='action_set_to_close']" position="after">
<button name="set_to_running" string="Set to Running" type="object" attrs="{'invisible': [('state', '!=', 'close')]}"/>
</xpath>-->
</field>
</record>
<!-- <record model="ir.actions.act_window" id="om_account_asset.action_account_asset_asset_form">-->
<!-- <field name="name">Assets</field>-->
<!-- <field name="res_model">account.asset.asset</field>-->
<!-- <field name="view_mode">tree,kanban,form</field>-->
<!-- <field name="view_id" ref="om_account_asset.view_account_asset_asset_purchase_tree"/>-->
<!-- <field name="domain">[('category_id.type', '=', 'purchase'), ('parent_id', '=', False)]</field>-->
<!-- </record>-->
</data>
</odoo>
+2
View File
@@ -0,0 +1,2 @@
from . import assest_dep_wizard
from . import asset_sell
@@ -0,0 +1,16 @@
from odoo import api, fields, models, _
class AssetDepreciationConfirmationWizard(models.TransientModel):
_inherit = "asset.depreciation.confirmation.wizard"
_description = "asset.depreciation.confirmation.wizard"
category_id = fields.Many2one('account.asset.category', string='Category')
def asset_compute(self):
res = super(AssetDepreciationConfirmationWizard, self).asset_compute()
domain_filter = []
if self.category_id:
domain_filter.append(('category_id', '=', self.category_id.id))
res['domain'] = str(domain_filter)
return res
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_asset_depreciation_confirmation_wizard_inherit" model="ir.ui.view">
<field name="name">asset.depreciation.confirmation.wizard.inherit</field>
<field name="model">asset.depreciation.confirmation.wizard</field>
<field name="inherit_id" ref="base_accounting_kit.view_asset_depreciation_confirmation_wizard"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='date']" position="after">
<field name="category_id"/>
</xpath>
</field>
</record>
</odoo>
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class AssetSell(models.TransientModel):
_name = 'account.asset.sell'
_description = 'Sell Asset'
assets_id = fields.Many2one('account.asset.asset', required=True)
company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
action = fields.Selection([('sell', 'Sell'), ('dispose', 'Dispose')], required=True, default='sell')
invoice_id = fields.Many2one('account.move', string="Customer Invoice", help="The disposal invoice is needed in order to generate the closing journal entry.", domain="[('move_type', '=', 'out_invoice'), ('state', '=', 'posted')]")
invoice_line_id = fields.Many2one('account.move.line', help="There are multiple lines that could be the related to this asset", domain="[('move_id', '=', invoice_id), ('exclude_from_invoice_tab', '=', False)]")
select_invoice_line_id = fields.Boolean(compute="_compute_select_invoice_line_id")
gain_account_id = fields.Many2one('account.account', domain="[('deprecated', '=', False), ('company_id', '=', company_id)]", related='company_id.gain_account_id', help="Account used to write the journal item in case of gain", readonly=False)
loss_account_id = fields.Many2one('account.account', domain="[('deprecated', '=', False), ('company_id', '=', company_id)]", related='company_id.loss_account_id', help="Account used to write the journal item in case of loss", readonly=False)
gain_or_loss = fields.Selection([('gain', 'Gain'), ('loss', 'Loss'), ('no', 'No')], compute='_compute_gain_or_loss', help="Technical field to know is there was a gain or a loss in the selling of the asset")
@api.depends('invoice_id', 'action')
def _compute_select_invoice_line_id(self):
for record in self:
record.select_invoice_line_id = record.action == 'sell' and len(record.invoice_id.invoice_line_ids) > 1
@api.onchange('action')
def _onchange_action(self):
if self.action == 'sell' and self.assets_id.children_ids:
raise UserError("You cannot automate the journal entry for an asset that has had a gross increase. Please use 'Dispose' and modify the entries.")
@api.depends('assets_id', 'invoice_id', 'invoice_line_id')
def _compute_gain_or_loss(self):
print('---loss/gain---')
for record in self:
line = record.invoice_line_id or len(record.invoice_id.invoice_line_ids) == 1 and record.invoice_id.invoice_line_ids or self.env['account.move.line']
if record.assets_id.value_residual < abs(line.balance):
record.gain_or_loss = 'gain'
elif record.assets_id.value_residual > abs(line.balance):
record.gain_or_loss = 'loss'
else:
record.gain_or_loss = 'no'
def do_action(self):
self.ensure_one()
invoice_line = self.env['account.move.line'] if self.action == 'dispose' else self.invoice_line_id or self.invoice_id.invoice_line_ids
return self.assets_id.set_to_close(invoice_line_id=invoice_line, date=invoice_line.move_id.invoice_date)
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="asset_sell_form">
<field name="name">wizard.asset.sell.form</field>
<field name="model">account.asset.sell</field>
<field name="arch" type="xml">
<form string="Sell Asset">
<field name="select_invoice_line_id" invisible="1"/>
<field name="gain_or_loss" invisible="1"/>
<field name="company_id" invisible="1"/>
<group>
<group>
<field name="action"/>
<field name="invoice_id" options="{'no_create': True}" attrs="{'invisible': [('action', '!=', 'sell')], 'required': [('action', '=', 'sell')]}"/>
<field name="invoice_line_id" options="{'no_create': True}" attrs="{'invisible': [('select_invoice_line_id', '=', False)], 'required': [('select_invoice_line_id', '=', True)]}"/>
</group>
<group>
<field name="gain_account_id" attrs="{'invisible': [('gain_or_loss', '!=', 'gain')], 'required': [('gain_or_loss', '=', 'gain')]}"/>
<field name="loss_account_id" attrs="{'invisible': [('gain_or_loss', '!=', 'loss')], 'required': [('gain_or_loss', '=', 'loss')]}"/>
</group>
</group>
<footer>
<button name="do_action" string="Sell" type="object" class="btn-primary" attrs="{'invisible': [('action', '!=', 'sell')]}"/>
<button name="do_action" string="Dispose" type="object" class="btn-primary" attrs="{'invisible': [('action', '!=', 'dispose')]}"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
+86
View File
@@ -0,0 +1,86 @@
=======================
Analytic Operating Unit
=======================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github
:target: https://github.com/OCA/operating-unit/tree/14.0/analytic_operating_unit
:alt: OCA/operating-unit
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/operating-unit-14-0/operating-unit-14-0-analytic_operating_unit
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/213/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows users to introduce into the analytic accounts the allowed
operating units. Only a user with permissions to operate on the operating
units indicated in an analytic account will have the rights to use it.
**Table of contents**
.. contents::
:local:
Usage
=====
* Go to 'Accounting / Configuration / Analytic Accounting / Analytic
Accounts' and add the accepted Operating Units to each analytic account.
Analytic accounts with no Operating Unit assigned to them will be accessible
by all users with access to analytic accounts.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/operating-unit/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 <https://github.com/OCA/operating-unit/issues/new?body=module:%20analytic_operating_unit%0Aversion:%2014.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
~~~~~~~~~~~~
* Jordi Ballester Alomar <jordi.ballester@eficent.com>
* Sudhir Arya <sudhir@erpharbor.com>
* Alan Ramos <alan.ramos@jarsa.com.mx>
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/operating-unit <https://github.com/OCA/operating-unit/tree/14.0/analytic_operating_unit>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+2
View File
@@ -0,0 +1,2 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models
+16
View File
@@ -0,0 +1,16 @@
# Copyright 2016-17 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Analytic Operating Unit",
"version": "14.0.1.0.0",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"license": "LGPL-3",
"website": "https://github.com/OCA/operating-unit",
"category": "Sales",
"depends": ["analytic", "operating_unit"],
"data": [
"security/analytic_account_security.xml",
"views/analytic_account_view.xml",
],
"installable": True,
}
@@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * analytic_operating_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.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: analytic_operating_unit
#: model:ir.model,name:analytic_operating_unit.model_account_analytic_account
msgid "Analytic Account"
msgstr ""
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__display_name
msgid "Display Name"
msgstr ""
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__id
msgid "ID"
msgstr ""
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account____last_update
msgid "Last Modified on"
msgstr ""
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__operating_unit_ids
msgid "Operating Units"
msgstr ""
+27
View File
@@ -0,0 +1,27 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * analytic_operating_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2020-02-15 14:13+0000\n"
"Last-Translator: Jesús Alan Ramos Rodríguez <alan.ramos@jarsa.com.mx>\n"
"Language-Team: none\n"
"Language: es_MX\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 3.10\n"
#. module: analytic_operating_unit
#: model:ir.model,name:analytic_operating_unit.model_account_analytic_account
msgid "Analytic Account"
msgstr "Cuenta Analítica"
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__operating_unit_ids
msgid "Operating Units"
msgstr "Unidades Operativas"
+42
View File
@@ -0,0 +1,42 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * analytic_operating_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-01-02 11:44+0000\n"
"Last-Translator: Francesco Foresti <francesco.foresti@ooops404.com>\n"
"Language-Team: none\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.14.1\n"
#. module: analytic_operating_unit
#: model:ir.model,name:analytic_operating_unit.model_account_analytic_account
msgid "Analytic Account"
msgstr "Conto Analitico"
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__display_name
msgid "Display Name"
msgstr "Nome da visualizzare"
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__id
msgid "ID"
msgstr "ID"
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: analytic_operating_unit
#: model:ir.model.fields,field_description:analytic_operating_unit.field_account_analytic_account__operating_unit_ids
msgid "Operating Units"
msgstr "Unità operative"
@@ -0,0 +1,2 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import account_analytic_account
@@ -0,0 +1,17 @@
# Copyright 2016-17 ForgeFlow S.L.
# Copyright 2016-17 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import fields, models
class AccountAnalyticAccount(models.Model):
_inherit = "account.analytic.account"
operating_unit_ids = fields.Many2many(
comodel_name="operating.unit",
string="Operating Units",
relation="analytic_account_operating_unit_rel",
domain="[('user_ids', '=', uid)]",
column1="analytic_account_id",
column2="operating_unit_id",
)
@@ -0,0 +1,12 @@
# from odoo import api, fields, models
#
#
# class analytic_user(models.Model):
#
# _inherit = "res.users"
#
# analytic_ids = fields.Many2many(
# comodel_name="account.analytic.account",
# string="Analytic Account",
# relation="analytic_account_res_users_rel",
# )
@@ -0,0 +1,3 @@
* Jordi Ballester Alomar <jordi.ballester@eficent.com>
* Sudhir Arya <sudhir@erpharbor.com>
* Alan Ramos <alan.ramos@jarsa.com.mx>
@@ -0,0 +1,3 @@
This module allows users to introduce into the analytic accounts the allowed
operating units. Only a user with permissions to operate on the operating
units indicated in an analytic account will have the rights to use it.
+5
View File
@@ -0,0 +1,5 @@
* Go to 'Accounting / Configuration / Analytic Accounting / Analytic
Accounts' and add the accepted Operating Units to each analytic account.
Analytic accounts with no Operating Unit assigned to them will be accessible
by all users with access to analytic accounts.
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2016-17 ForgeFlow S.L.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) -->
<odoo>
<record id="ir_rule_analytic_account_allowed_operating_units" model="ir.rule">
<field name="model_id" ref="analytic.model_account_analytic_account" />
<field name="domain_force">
['|',('operating_unit_ids','=',False),('operating_unit_ids','in',[g.id for g
in user.operating_unit_ids])]
</field>
<field name="name">Analytic Accounts from allowed operating units</field>
<field name="global" eval="True" />
<field eval="0" name="perm_unlink" />
<field eval="0" name="perm_write" />
<field eval="1" name="perm_read" />
<field eval="0" name="perm_create" />
</record>
</odoo>
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

@@ -0,0 +1,433 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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 0.15.1: http://docutils.sourceforge.net/" />
<title>Analytic Operating Unit</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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: grey; } /* 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 {
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="analytic-operating-unit">
<h1 class="title">Analytic Operating Unit</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/operating-unit/tree/14.0/analytic_operating_unit"><img alt="OCA/operating-unit" src="https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/operating-unit-14-0/operating-unit-14-0-analytic_operating_unit"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/213/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows users to introduce into the analytic accounts the allowed
operating units. Only a user with permissions to operate on the operating
units indicated in an analytic account will have the rights to use it.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<ul class="simple">
<li>Go to Accounting / Configuration / Analytic Accounting / Analytic
Accounts and add the accepted Operating Units to each analytic account.</li>
</ul>
<p>Analytic accounts with no Operating Unit assigned to them will be accessible
by all users with access to analytic accounts.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/operating-unit/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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/operating-unit/issues/new?body=module:%20analytic_operating_unit%0Aversion:%2014.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="#id3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple">
<li>Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;eficent.com">jordi.ballester&#64;eficent.com</a>&gt;</li>
<li>Sudhir Arya &lt;<a class="reference external" href="mailto:sudhir&#64;erpharbor.com">sudhir&#64;erpharbor.com</a>&gt;</li>
<li>Alan Ramos &lt;<a class="reference external" href="mailto:alan.ramos&#64;jarsa.com.mx">alan.ramos&#64;jarsa.com.mx</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id6">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/operating-unit/tree/14.0/analytic_operating_unit">OCA/operating-unit</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>
@@ -0,0 +1,19 @@
<?xml version="1.0" ?>
<!-- Copyright 2016-17 ForgeFlow S.L.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl) -->
<odoo>
<record id="view_account_analytic_account_form" model="ir.ui.view">
<field name="name">analytic.analytic.account.form</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_form" />
<field name="arch" type="xml">
<field name="company_id" position="before">
<field
name="operating_unit_ids"
widget="many2many_tags"
groups="operating_unit.group_multi_operating_unit"
/>
</field>
</field>
</record>
</odoo>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- <record id="view_res_users_form" models="ir.ui.view">-->
<!-- <field name="name">res.users.form</field>-->
<!-- <field name="models">res.users</field>-->
<!-- <field name="inherit_id" ref="base.view_users_form" />-->
<!-- <field name="arch" type="xml">-->
<!-- <xpath expr="//page[@name='access_rights']/group[1]" position="after">-->
<!-- <group string="Analytic Account">-->
<!-- <field-->
<!-- name="analytic_ids"-->
<!-- widget="many2many_tags"-->
<!-- domain="[('id','in',analytic_ids)]"-->
<!-- />-->
<!-- </group>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
</odoo>
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
+17
View File
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
{
"name": "Analytic Account On Register Payment",
"version": "1.01",
"author": "Ifoel Arbeis - 08156814955",
"license": "",
"category": "Account",
"website": "",
'depends': ['account','base_accounting_kit'],
"data": [
'views/payment_view.xml',
'views/account_asset_asset.xml'
],
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import controllers
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from odoo import http
# class AsaAnalyticPayment(http.Controller):
# @http.route('/asa_analytic_payment/asa_analytic_payment/', auth='public')
# def index(self, **kw):
# return "Hello, world"
# @http.route('/asa_analytic_payment/asa_analytic_payment/objects/', auth='public')
# def list(self, **kw):
# return http.request.render('asa_analytic_payment.listing', {
# 'root': '/asa_analytic_payment/asa_analytic_payment',
# 'objects': http.request.env['asa_analytic_payment.asa_analytic_payment'].search([]),
# })
# @http.route('/asa_analytic_payment/asa_analytic_payment/objects/<model("asa_analytic_payment.asa_analytic_payment"):obj>/', auth='public')
# def object(self, obj, **kw):
# return http.request.render('asa_analytic_payment.object', {
# 'object': obj
# })
+30
View File
@@ -0,0 +1,30 @@
<odoo>
<data>
<!-- -->
<!-- <record id="object0" model="asa_analytic_payment.asa_analytic_payment"> -->
<!-- <field name="name">Object 0</field> -->
<!-- <field name="value">0</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object1" model="asa_analytic_payment.asa_analytic_payment"> -->
<!-- <field name="name">Object 1</field> -->
<!-- <field name="value">10</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object2" model="asa_analytic_payment.asa_analytic_payment"> -->
<!-- <field name="name">Object 2</field> -->
<!-- <field name="value">20</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object3" model="asa_analytic_payment.asa_analytic_payment"> -->
<!-- <field name="name">Object 3</field> -->
<!-- <field name="value">30</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object4" model="asa_analytic_payment.asa_analytic_payment"> -->
<!-- <field name="name">Object 4</field> -->
<!-- <field name="value">40</field> -->
<!-- </record> -->
<!-- -->
</data>
</odoo>
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import payment
from . import analytic_account_asset
@@ -0,0 +1,211 @@
# Copyright 2020 Jesus Ramoneda <jesus.ramoneda@qubiq.es>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo.tools import float_compare, float_is_zero
from odoo.exceptions import UserError
class AnalyticAccountAsset(models.Model):
_inherit = "account.asset.asset"
account_analytic_id = fields.Many2one(
comodel_name='account.analytic.account')
analytic_id = fields.Many2one(
comodel_name='account.analytic.account')
mutasi_asset_id = fields.Many2one('account.asset.asset',string="Mutasi Asset")
asset_count = fields.Integer(compute='_asset_count', string='Asset Count')
def _asset_count(self):
for rec in self:
asset_ids = self.env['account.asset.asset'].search([('mutasi_asset_id', '=', rec.id)])
rec.asset_count = len(asset_ids)
def action_view_asset(self):
action = self.env.ref('base_accounting_kit.action_account_asset_asset_form').read()[0]
action['context'] = {}
action['domain'] = [('mutasi_asset_id', '=', self.id)]
return action
@api.onchange('category_id')
def onchange_category_id(self):
res = super(AnalyticAccountAsset, self).onchange_category_id()
self.account_analytic_id = self.category_id.account_analytic_id
return res
def create_mutasi_asset(self):
for rec in self :
if not rec.mutasi_asset_id :
comulative = 0
val = 0
for line in rec.depreciation_line_ids :
if line.move_check == True :
comulative += line.amount
val += 1
vals = {
'name' : rec.name +'-'+'Mutasi',
'category_id' : rec.category_id.id,
'code' : rec.code,
'company_id' : rec.company_id.id,
'value' : rec.value,
'salvage_value' : rec.salvage_value + comulative,
'value_residual' : rec.value_residual,
'mutasi_asset_id' : rec.id,
'method' : rec.method,
'method_time' : rec.method_time,
'prorata' : rec.prorata,
'method_number' : rec.method_number - val,
'method_period' : rec.method_period,
}
asset = self.env['account.asset.asset'].create(vals)
rec.write({'state': 'close'})
# for line in rec.depreciation_line_ids:
# if line.move_check == False :
# line_vals = {
# 'asset_id' : asset.id,
# 'name' : line.name,
# 'sequence' : line.sequence,
# 'depreciated_value' : line.depreciated_value,
# 'amount' : line.amount,
# 'remaining_value' : line.remaining_value,
# 'depreciation_date' : line.depreciation_date,
# }
# self.env['account.asset.depreciation.line'].create(line_vals)
else :
raise UserError(_("You can't create mutasi asset for this asset because mutasi asset is created."))
class AccountAssetLine(models.Model):
_inherit = "account.asset.depreciation.line"
def _set_analytic_account(self):
def get_move_line(asset_line):
return 1 if asset_line.asset_id.category_id.type == "sale" else 0
for rec in self.filtered(
lambda x: x.move_id and x.asset_id and
x.asset_id.account_analytic_id):
i = get_move_line(rec)
rec.move_id.line_ids[i].analytic_account_id =\
rec.asset_id.account_analytic_id
# def write(self, values):
# res = super(AccountAssetLine, self).write(values)
# if values.get('move_id'):
# self._set_analytic_account()
# return res
def create_move(self, post_move=True):
created_moves = self.env['account.move']
prec = self.env['decimal.precision'].precision_get('Account')
if self.mapped('move_id'):
raise UserError(_(
'This depreciation is already linked to a journal entry! Please post or delete it.'))
for line in self:
category_id = line.asset_id.category_id
depreciation_date = self.env.context.get(
'depreciation_date') or line.depreciation_date or fields.Date.context_today(
self)
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
amount = current_currency.with_context(
date=depreciation_date).compute(line.amount, company_currency)
asset_name = line.asset_id.name + ' (%s/%s)' % (
line.sequence, len(line.asset_id.depreciation_line_ids))
partner = self.env['res.partner']._find_accounting_partner(
line.asset_id.partner_id)
move_line_1 = {
'name': asset_name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0 if float_compare(amount, 0.0,
precision_digits=prec) > 0 else -amount,
'credit': amount if float_compare(amount, 0.0,
precision_digits=prec) > 0 else 0.0,
'journal_id': category_id.journal_id.id,
'partner_id': partner.id,
'analytic_account_id': line.asset_id.account_analytic_id.id,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0,
}
move_line_2 = {
'name': asset_name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0 if float_compare(amount, 0.0,
precision_digits=prec) > 0 else -amount,
'debit': amount if float_compare(amount, 0.0,
precision_digits=prec) > 0 else 0.0,
'journal_id': category_id.journal_id.id,
'partner_id': partner.id,
'analytic_account_id': line.asset_id.account_analytic_id.id,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and line.amount or 0.0,
}
move_vals = {
'ref': line.asset_id.code,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
move = self.env['account.move'].create(move_vals)
line.write({'move_id': move.id, 'move_check': True})
created_moves |= move
if post_move and created_moves:
created_moves.filtered(lambda m: any(
m.asset_depreciation_ids.mapped(
'asset_id.category_id.open_asset'))).post()
return [x.id for x in created_moves]
def create_grouped_move(self, post_move=True):
if not self.exists():
return []
created_moves = self.env['account.move']
category_id = self[
0].asset_id.category_id # we can suppose that all lines have the same category
depreciation_date = self.env.context.get(
'depreciation_date') or fields.Date.context_today(self)
amount = 0.0
for line in self:
# Sum amount of all depreciation lines
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
amount += current_currency.compute(line.amount, company_currency)
name = category_id.name + _(' (grouped)')
move_line_1 = {
'name': name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0,
'credit': amount,
'journal_id': category_id.journal_id.id,
'analytic_account_id': line.asset_id.account_analytic_id.id,
}
move_line_2 = {
'name': name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0,
'debit': amount,
'journal_id': category_id.journal_id.id,
'analytic_account_id': line.asset_id.account_analytic_id.id,
}
move_vals = {
'ref': category_id.name,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
move = self.env['account.move'].create(move_vals)
self.write({'move_id': move.id, 'move_check': True})
created_moves |= move
if post_move and created_moves:
self.post_lines_and_close_asset()
created_moves.post()
return [x.id for x in created_moves]
+169
View File
@@ -0,0 +1,169 @@
from odoo import models, fields, api
class AccountPayment(models.Model):
_inherit = "account.payment"
account_analytic_id = fields.Many2one('account.analytic.account',string='Analytic Account')
effective_date = fields.Date(string='Efective Date')
bank_reference = fields.Char(string='Bank Reference')
cheque_reference = fields.Char(string='Cheque Reference')
def _prepare_move_line_default_vals(self, write_off_line_vals=None):
''' Prepare the dictionary to create the default account.move.lines for the current payment.
:param write_off_line_vals: Optional dictionary to create a write-off account.move.line easily containing:
* amount: The amount to be added to the counterpart amount.
* name: The label to set on the line.
* account_id: The account on which create the write-off.
:return: A list of python dictionary to be passed to the account.move.line's 'create' method.
'''
self.ensure_one()
write_off_line_vals = write_off_line_vals or {}
if not self.journal_id.payment_debit_account_id or not self.journal_id.payment_credit_account_id:
raise UserError(_(
"You can't create a new payment without an outstanding payments/receipts account set on the %s journal.",
self.journal_id.display_name))
# Compute amounts.
write_off_amount_currency = write_off_line_vals.get('amount', 0.0)
if self.payment_type == 'inbound':
# Receive money.
liquidity_amount_currency = self.amount
elif self.payment_type == 'outbound':
# Send money.
liquidity_amount_currency = -self.amount
write_off_amount_currency *= -1
else:
liquidity_amount_currency = write_off_amount_currency = 0.0
write_off_balance = self.currency_id._convert(
write_off_amount_currency,
self.company_id.currency_id,
self.company_id,
self.date,
)
liquidity_balance = self.currency_id._convert(
liquidity_amount_currency,
self.company_id.currency_id,
self.company_id,
self.date,
)
counterpart_amount_currency = -liquidity_amount_currency - write_off_amount_currency
counterpart_balance = -liquidity_balance - write_off_balance
currency_id = self.currency_id.id
if self.is_internal_transfer:
if self.payment_type == 'inbound':
liquidity_line_name = _('Transfer to %s', self.journal_id.name)
else: # payment.payment_type == 'outbound':
liquidity_line_name = _('Transfer from %s', self.journal_id.name)
else:
liquidity_line_name = self.payment_reference
# Compute a default label to set on the journal items.
payment_display_name = self._prepare_payment_display_name()
default_line_name = self.env['account.move.line']._get_default_line_name(
_("Internal Transfer") if self.is_internal_transfer else payment_display_name['%s-%s' % (self.payment_type, self.partner_type)],
self.amount,
self.currency_id,
self.date,
partner=self.partner_id,
)
line_vals_list = [
# Liquidity line.
{
'name': liquidity_line_name or default_line_name,
'date_maturity': self.date,
'amount_currency': liquidity_amount_currency,
'currency_id': currency_id,
'debit': liquidity_balance if liquidity_balance > 0.0 else 0.0,
'credit': -liquidity_balance if liquidity_balance < 0.0 else 0.0,
'partner_id': self.partner_id.id,
'analytic_account_id': self.account_analytic_id.id,
'account_id': self.journal_id.payment_credit_account_id.id if liquidity_balance < 0.0 else self.journal_id.payment_debit_account_id.id,
},
# Receivable / Payable.
{
'name': self.payment_reference or default_line_name,
'date_maturity': self.date,
'amount_currency': counterpart_amount_currency,
'currency_id': currency_id,
'debit': counterpart_balance if counterpart_balance > 0.0 else 0.0,
'credit': -counterpart_balance if counterpart_balance < 0.0 else 0.0,
'partner_id': self.partner_id.id,
'account_id': self.destination_account_id.id,
'analytic_account_id': self.account_analytic_id.id,
},
]
if not self.currency_id.is_zero(write_off_amount_currency):
# Write-off line.
line_vals_list.append({
'name': write_off_line_vals.get('name') or default_line_name,
'amount_currency': write_off_amount_currency,
'currency_id': currency_id,
'debit': write_off_balance if write_off_balance > 0.0 else 0.0,
'credit': -write_off_balance if write_off_balance < 0.0 else 0.0,
'partner_id': self.partner_id.id,
'account_id': write_off_line_vals.get('account_id'),
})
return line_vals_list
class AccountRegisterPayment(models.TransientModel):
_inherit = "account.payment.register"
account_analytic_id = fields.Many2one('account.analytic.account',
string='Analytic Account')
@api.model
def default_get(self, fields_list):
# OVERRIDE
res = super().default_get(fields_list)
move_ids = self._context.get('active_ids', [])
if not move_ids or len(move_ids) != 1:
return res
move = self.env['account.move'].browse(move_ids)
res.update(account_analytic_id=move.analytic_account_id.id)
return res
def _create_payment_vals_from_wizard(self):
payment_vals = {
'date': self.payment_date,
'amount': self.amount,
'payment_type': self.payment_type,
'partner_type': self.partner_type,
'ref': self.communication,
'journal_id': self.journal_id.id,
'currency_id': self.currency_id.id,
'partner_id': self.partner_id.id,
'partner_bank_id': self.partner_bank_id.id,
'payment_method_id': self.payment_method_id.id,
'destination_account_id': self.line_ids[0].account_id.id,
'account_analytic_id': self.account_analytic_id.id,
}
if not self.currency_id.is_zero(self.payment_difference) and self.payment_difference_handling == 'reconcile':
payment_vals['write_off_line_vals'] = {
'name': self.writeoff_label,
'amount': self.payment_difference,
'account_id': self.writeoff_account_id.id,
}
return payment_vals
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_asa_analytic_payment_asa_analytic_payment,asa_analytic_payment.asa_analytic_payment,model_asa_analytic_payment_asa_analytic_payment,,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_asa_analytic_payment_asa_analytic_payment asa_analytic_payment.asa_analytic_payment model_asa_analytic_payment_asa_analytic_payment 1 0 0 0
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 Jesus Ramoneda <jesus.ramoneda@qubiq.es>
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="account_asset_asset_form" model="ir.ui.view">
<field name="name">account.asset.asset.form</field>
<field name="model">account.asset.asset</field>
<field name="inherit_id" ref="base_accounting_kit.view_account_asset_asset_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='open_entries']" position="before">
<button type="object" name="action_view_asset" class="oe_stat_button" icon="fa-pencil-square-o" attrs="{'invisible': [('asset_count', '=', 0)]}">
<field name="asset_count" widget="statinfo" string="Mutasi Asset"/>
</button>
</xpath>
<xpath expr="//field[@name='date']" position="after">
<field name="account_analytic_id"
attrs="{'readonly': [('state', '!=', 'draft')]}"
/>
<field name="mutasi_asset_id" readonly="1"/>
</xpath>
<xpath expr="//button[@name='validate']" position="after">
<button name="create_mutasi_asset" string="Create Mutasi" attrs="{'invisible': [('asset_count', '=', 1)]}" type="object"/>
</xpath>
</field>
</record>
</odoo>
@@ -0,0 +1,27 @@
<odoo>
<data>
<record model="ir.ui.view" id="inherit_payment_analytic">
<field name="name">Inherit Payment Analytic</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<field name="journal_id" position="after">
<field name="account_analytic_id"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="inherit_register_payment_analytic">
<field name="name">Inherit Register Payment Analytic</field>
<field name="model">account.payment.register</field>
<field name="inherit_id" ref="account.view_account_payment_register_form"/>
<field name="arch" type="xml">
<field name="journal_id" position="after">
<field name="account_analytic_id"/>
</field>
</field>
</record>
</data>
</odoo>
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
+16
View File
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
{
"name": "Menu Anglo Saxon Accounting",
"version": "1.01",
"author": "Ifoel Arbeis - 08156814955",
"license": "",
"category": "Account",
"website": "",
'depends': ['account'],
"data": [
'views/views.xml',
],
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import controllers
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# from odoo import http
# class AsaAngloSaxonMenu(http.Controller):
# @http.route('/asa_anglo_saxon_menu/asa_anglo_saxon_menu/', auth='public')
# def index(self, **kw):
# return "Hello, world"
# @http.route('/asa_anglo_saxon_menu/asa_anglo_saxon_menu/objects/', auth='public')
# def list(self, **kw):
# return http.request.render('asa_anglo_saxon_menu.listing', {
# 'root': '/asa_anglo_saxon_menu/asa_anglo_saxon_menu',
# 'objects': http.request.env['asa_anglo_saxon_menu.asa_anglo_saxon_menu'].search([]),
# })
# @http.route('/asa_anglo_saxon_menu/asa_anglo_saxon_menu/objects/<model("asa_anglo_saxon_menu.asa_anglo_saxon_menu"):obj>/', auth='public')
# def object(self, obj, **kw):
# return http.request.render('asa_anglo_saxon_menu.object', {
# 'object': obj
# })
+30
View File
@@ -0,0 +1,30 @@
<odoo>
<data>
<!--
<record id="object0" model="asa_anglo_saxon_menu.asa_anglo_saxon_menu">
<field name="name">Object 0</field>
<field name="value">0</field>
</record>
<record id="object1" model="asa_anglo_saxon_menu.asa_anglo_saxon_menu">
<field name="name">Object 1</field>
<field name="value">10</field>
</record>
<record id="object2" model="asa_anglo_saxon_menu.asa_anglo_saxon_menu">
<field name="name">Object 2</field>
<field name="value">20</field>
</record>
<record id="object3" model="asa_anglo_saxon_menu.asa_anglo_saxon_menu">
<field name="name">Object 3</field>
<field name="value">30</field>
</record>
<record id="object4" model="asa_anglo_saxon_menu.asa_anglo_saxon_menu">
<field name="name">Object 4</field>
<field name="value">40</field>
</record>
-->
</data>
</odoo>
+3
View File
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import models

Some files were not shown because too many files have changed in this diff Show More