Initial commit: OCA Workflow Process packages (456 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:00 +02:00
commit d366e42934
18799 changed files with 1284507 additions and 0 deletions

View file

@ -0,0 +1,46 @@
# Purchase Merge
Odoo addon: purchase_merge
## Installation
```bash
pip install odoo-bringout-oca-purchase-workflow-purchase_merge
```
## Dependencies
This addon depends on:
- purchase_order_approved
## Manifest Information
- **Name**: Purchase Merge
- **Version**: 16.0.1.0.3
- **Category**: Purchase
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/purchase-workflow](https://github.com/OCA/purchase-workflow) branch 16.0, addon `purchase_merge`.
## License
This package maintains the original AGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-purchase-workflow-purchase_merge"
# or
uv pip install odoo-bringout-oca-purchase-workflow-purchase_merge"
```

View file

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

View file

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

View file

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

View file

@ -0,0 +1,34 @@
# Security
Access control and security definitions in purchase_merge.
## Access Control Lists (ACLs)
Model access permissions defined in:
- **[ir.model.access.csv](../purchase_merge/security/ir.model.access.csv)**
- 1 model access rules
## Record Rules
Row-level security rules defined in:
```mermaid
graph TB
subgraph "Security Layers"
A[Users] --> B[Groups]
B --> C[Access Control Lists]
C --> D[Models]
B --> E[Record Rules]
E --> F[Individual Records]
end
```
Security files overview:
- **[ir.model.access.csv](../purchase_merge/security/ir.model.access.csv)**
- Model access permissions (CRUD rights)
Notes
- Access Control Lists define which groups can access which models
- Record Rules provide row-level security (filter records by user/group)
- Security groups organize users and define permission sets
- All security is enforced at the ORM level by Odoo

View file

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

View file

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

View file

@ -0,0 +1,8 @@
# Wizards
Transient models exposed as UI wizards in purchase_merge.
```mermaid
classDiagram
class MergePurchaseAutomatic
```

View file

@ -0,0 +1,103 @@
==============
Purchase Merge
==============
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:6593929c5934f76931f4345622c11a823589930923e026b3759d7257649c7d99
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/purchase-workflow/tree/16.0/purchase_merge
:alt: OCA/purchase-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/purchase-workflow-16-0/purchase-workflow-16-0-purchase_merge
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds a wizard to merge purchase order.
A wizard that can be called from tree view of purchase orders.
If merge criteria are validate:
All lines of all PO are "transferred" to the first one and some information like 'origin' and 'partner_ref' are concatenated.
We post a message on the chatter to indicate when the merge operation occurs and what were the PO concerned.
The empty PO are "canceled"
Merge criteria:
* PO are from the same supplier
* PO are in state 'draft'
* PO have the same
#. currency
#. picking type
#. incoterms
#. payment terms
#. fiscal position
**Table of contents**
.. contents::
:local:
Usage
=====
To use this module, you need to:
#. Merge purchase order with required criteria
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/purchase-workflow/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/purchase-workflow/issues/new?body=module:%20purchase_merge%0Aversion:%2016.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
~~~~~~~
* Camptocamp
Contributors
~~~~~~~~~~~~
* `Camptocamp <https://www.camptocamp.com>`_:
* Thomas Nowicki <thomas.nowicki@camptocamp.com>
* Bojan Anchev <bojan.anchev@camptocamp.com>
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/purchase-workflow <https://github.com/OCA/purchase-workflow/tree/16.0/purchase_merge>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

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

View file

@ -0,0 +1,18 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Purchase Merge",
"summary": "Wizard to merge purchase with required conditions",
"version": "16.0.1.0.3",
"author": "Camptocamp, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/purchase-workflow",
"license": "AGPL-3",
"category": "Purchase",
"depends": ["purchase_order_approved"],
"data": [
"security/ir.model.access.csv",
"wizard/purchase_merge_views.xml",
],
"external_dependencies": {"python": ["openupgradelib"]},
"installable": True,
}

View file

@ -0,0 +1,146 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_merge
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.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: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Automatic Merge Wizard"
msgstr "Čarobnjak automatskog spajanja"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Cancel"
msgstr "Otkaži"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_uid
msgid "Created by"
msgstr "Kreirao"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_date
msgid "Created on"
msgstr "Kreirano"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__dst_purchase_id
msgid "Destination"
msgstr "Odredište"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__display_name
msgid "Display Name"
msgstr "Prikazani naziv"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__id
msgid "ID"
msgstr "ID"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard____last_update
msgid "Last Modified on"
msgstr "Zadnje mijenjano"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_uid
msgid "Last Updated by"
msgstr "Zadnji ažurirao"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_date
msgid "Last Updated on"
msgstr "Zadnje ažurirano"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Merge Purchase"
msgstr "Merge Nabavni"
#. module: purchase_merge
#: model:ir.actions.act_window,name:purchase_merge.action_purchase_merge
msgid "Merge Selected Purchase"
msgstr "Merge Selected Nabavni"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__purchase_ids
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Purchase"
msgstr "Nabavke"
#. module: purchase_merge
#: model:ir.model,name:purchase_merge.model_purchase_merge_automatic_wizard
msgid "Purchase Merge Automatic Wizard"
msgstr "Nabavni Merge Automatic Čarobnjak"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Selected purchase will be merged together."
msgstr "Selected purchase will be merged together."
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "This purchase order lines have been merged %(way)s : %(po_names)s"
msgstr "This purchase order lines have been merged %(way)s : %(po_names)s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders that aren't in draft state like: {}"
msgstr "You can't merge purchase orders that aren't in draft state like: {}"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different currencies: %s"
msgstr "You can't merge purchase orders with different currencies: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different fiscal positions: %s"
msgstr "You can't merge purchase orders with different fiscal positions: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different incoterms: %s"
msgstr "You can't merge purchase orders with different incoterms: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different payment terms: %s"
msgstr "You can't merge purchase orders with different payment terms: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different picking types: %s"
msgstr "You can't merge purchase orders with different picking types: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different suppliers: %s"
msgstr "You can't merge purchase orders with different suppliers: %s"

View file

@ -0,0 +1,161 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_merge
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-10-09 09:10+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Automatic Merge Wizard"
msgstr "Asistente de fusión automática"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Cancel"
msgstr "Cancelar"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_date
msgid "Created on"
msgstr "Creado el"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__dst_purchase_id
msgid "Destination"
msgstr "Destino"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__display_name
msgid "Display Name"
msgstr "Nombre para Mostrar"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__id
msgid "ID"
msgstr "ID (identificación)"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard____last_update
msgid "Last Modified on"
msgstr "modificado por última vez el"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_uid
msgid "Last Updated by"
msgstr "actualizado por última vez por"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_date
msgid "Last Updated on"
msgstr "actualizado por última vez el"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Merge Purchase"
msgstr "Fusionar compra"
#. module: purchase_merge
#: model:ir.actions.act_window,name:purchase_merge.action_purchase_merge
msgid "Merge Selected Purchase"
msgstr "Fusionar compra seleccionada"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__purchase_ids
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Purchase"
msgstr "Compra"
#. module: purchase_merge
#: model:ir.model,name:purchase_merge.model_purchase_merge_automatic_wizard
msgid "Purchase Merge Automatic Wizard"
msgstr ""
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Selected purchase will be merged together."
msgstr "La compra seleccionada se fusionará."
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "This purchase order lines have been merged %(way)s : %(po_names)s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders that aren't in draft state like: {}"
msgstr ""
"No se pueden fusionar pedidos que no estén en estado de borrador como: {}"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different currencies: %s"
msgstr "No se pueden fusionar pedidos con divisas diferentes: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different fiscal positions: %s"
msgstr "No se pueden fusionar pedidos con diferentes posiciones fiscales: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different incoterms: %s"
msgstr "No se pueden fusionar pedidos con diferentes incotérminos: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different payment terms: %s"
msgstr "No se pueden fusionar pedidos con diferentes condiciones de pago: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different picking types: %s"
msgstr "No se pueden fusionar pedidos con diferentes tipos de recogida: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different suppliers: %s"
msgstr "No se pueden fusionar pedidos con diferentes proveedores: %s"
#, python-format
#~ msgid "This purchase order lines have been merged {way} : {po_names}"
#~ msgstr "Estas líneas de pedido han sido fusionadas {way} : {po_names}"
#~ msgid "purchase.merge.automatic.wizard"
#~ msgstr "asistente.de.fusión.automática.de.compras"
#, python-format
#~ msgid "This purchase order lines have been merged {} : {}"
#~ msgstr "Estas líneas de pedido se han fusionado {} : {}"

View file

@ -0,0 +1,159 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_merge
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-08-12 09:58+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\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 5.6.2\n"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Automatic Merge Wizard"
msgstr "Procedura guidata unione automatica"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Cancel"
msgstr "Annulla"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_date
msgid "Created on"
msgstr "Creato il"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__dst_purchase_id
msgid "Destination"
msgstr "Destinazione"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__id
msgid "ID"
msgstr "ID"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Merge Purchase"
msgstr "Unisci acquisto"
#. module: purchase_merge
#: model:ir.actions.act_window,name:purchase_merge.action_purchase_merge
msgid "Merge Selected Purchase"
msgstr "Unisci acquisto selezionato"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__purchase_ids
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Purchase"
msgstr "Acquisto"
#. module: purchase_merge
#: model:ir.model,name:purchase_merge.model_purchase_merge_automatic_wizard
msgid "Purchase Merge Automatic Wizard"
msgstr "Procedura guidata unione automatica acquisti"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Selected purchase will be merged together."
msgstr "Gli acquisti selezionati verranno uniti."
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "This purchase order lines have been merged %(way)s : %(po_names)s"
msgstr "Queste righe ordine di acquisto sono state unite %(way)s : %(po_names)s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders that aren't in draft state like: {}"
msgstr ""
"Non si pososno unire ordini di acquisto che non sono in stato bozza come : {}"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different currencies: %s"
msgstr "Non si possono unire ordini di acquisto con valute diverse: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different fiscal positions: %s"
msgstr ""
"Non si possono unire ordini di acquisto con posizioni fiscali diverse: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different incoterms: %s"
msgstr "Non si possono unire ordini di acquisto con Incoterm diversi: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different payment terms: %s"
msgstr ""
"Non si possono unire ordini di acquisto con termini di pagamento diversi: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different picking types: %s"
msgstr "Non si possono unire ordini di acquisto con tipi prelievo diversi: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different suppliers: %s"
msgstr "Non si possono unire ordini di acquisto con fornitori diversi: %s"
#, python-format
#~ msgid "This purchase order lines have been merged {way} : {po_names}"
#~ msgstr "Queste righe ordine di vendita sono state unite {way} : {po_names}"
#~ msgid "purchase.merge.automatic.wizard"
#~ msgstr "purchase.merge.automatic.wizard"

View file

@ -0,0 +1,164 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_merge
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-03 16:06+0000\n"
"Last-Translator: Rodrigo Sottomaior Macedo "
"<sottomaiormacedotec@sottomaiormacedo.tech>\n"
"Language-Team: none\n"
"Language: pt_BR\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 5.6.2\n"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Automatic Merge Wizard"
msgstr "Assistente de Mesclagem Automática"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Cancel"
msgstr "Cancelar"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_uid
msgid "Created by"
msgstr "Criado por"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_date
msgid "Created on"
msgstr "Criado em"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__dst_purchase_id
msgid "Destination"
msgstr "Destino"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__display_name
msgid "Display Name"
msgstr "Nome Exibição"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__id
msgid "ID"
msgstr "ID"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard____last_update
msgid "Last Modified on"
msgstr "Última Modificação em"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_uid
msgid "Last Updated by"
msgstr "Última Atualização por"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_date
msgid "Last Updated on"
msgstr "Última Atualização em"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Merge Purchase"
msgstr "Mesclar Compra"
#. module: purchase_merge
#: model:ir.actions.act_window,name:purchase_merge.action_purchase_merge
msgid "Merge Selected Purchase"
msgstr "Mesclar Compras Selecionadas"
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__purchase_ids
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Purchase"
msgstr "Compra"
#. module: purchase_merge
#: model:ir.model,name:purchase_merge.model_purchase_merge_automatic_wizard
msgid "Purchase Merge Automatic Wizard"
msgstr "Assistente automático de fusão de compras"
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Selected purchase will be merged together."
msgstr "A compra selecionada será mesclada."
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "This purchase order lines have been merged %(way)s : %(po_names)s"
msgstr "Essas linhas de ordem de compra foram mescladas %(way)s : %(po_names)s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders that aren't in draft state like: {}"
msgstr ""
"Não é possível mesclar pedidos de compra que não estejam no estado de "
"rascunho, como: {}"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different currencies: %s"
msgstr "Você não pode mesclar pedidos de compra com moedas diferentes: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different fiscal positions: %s"
msgstr ""
"Você não pode mesclar pedidos de compra com posições fiscais diferentes: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different incoterms: %s"
msgstr "Você não pode mesclar pedidos de compra com Incoterms diferentes: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different payment terms: %s"
msgstr ""
"Você não pode mesclar pedidos de compra com condições de pagamento "
"diferentes: %s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different picking types: %s"
msgstr ""
"Não é possível mesclar pedidos de compra com tipos de separação diferentes: "
"%s"
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different suppliers: %s"
msgstr "Você não pode mesclar pedidos de compra de fornecedores diferentes: %s"
#, python-format
#~ msgid "This purchase order lines have been merged {way} : {po_names}"
#~ msgstr "Estas linhas da ordem de compra foram mescladas {way}: {po_names}"
#~ msgid "purchase.merge.automatic.wizard"
#~ msgstr "assistente.de.fusão.automática.de.compras"

View file

@ -0,0 +1,146 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_merge
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.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: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Automatic Merge Wizard"
msgstr ""
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Cancel"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_uid
msgid "Created by"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__create_date
msgid "Created on"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__dst_purchase_id
msgid "Destination"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__display_name
msgid "Display Name"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__id
msgid "ID"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard____last_update
msgid "Last Modified on"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_uid
msgid "Last Updated by"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__write_date
msgid "Last Updated on"
msgstr ""
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Merge Purchase"
msgstr ""
#. module: purchase_merge
#: model:ir.actions.act_window,name:purchase_merge.action_purchase_merge
msgid "Merge Selected Purchase"
msgstr ""
#. module: purchase_merge
#: model:ir.model.fields,field_description:purchase_merge.field_purchase_merge_automatic_wizard__purchase_ids
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Purchase"
msgstr ""
#. module: purchase_merge
#: model:ir.model,name:purchase_merge.model_purchase_merge_automatic_wizard
msgid "Purchase Merge Automatic Wizard"
msgstr ""
#. module: purchase_merge
#: model_terms:ir.ui.view,arch_db:purchase_merge.purchase_merge_automatic_wizard_form
msgid "Selected purchase will be merged together."
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "This purchase order lines have been merged %(way)s : %(po_names)s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders that aren't in draft state like: {}"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different currencies: %s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different fiscal positions: %s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different incoterms: %s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different payment terms: %s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different picking types: %s"
msgstr ""
#. module: purchase_merge
#. odoo-python
#: code:addons/purchase_merge/wizard/purchase_merge.py:0
#, python-format
msgid "You can't merge purchase orders with different suppliers: %s"
msgstr ""

View file

@ -0,0 +1,4 @@
* `Camptocamp <https://www.camptocamp.com>`_:
* Thomas Nowicki <thomas.nowicki@camptocamp.com>
* Bojan Anchev <bojan.anchev@camptocamp.com>

View file

@ -0,0 +1,18 @@
This module adds a wizard to merge purchase order.
A wizard that can be called from tree view of purchase orders.
If merge criteria are validate:
All lines of all PO are "transferred" to the first one and some information like 'origin' and 'partner_ref' are concatenated.
We post a message on the chatter to indicate when the merge operation occurs and what were the PO concerned.
The empty PO are "canceled"
Merge criteria:
* PO are from the same supplier
* PO are in state 'draft'
* PO have the same
#. currency
#. picking type
#. incoterms
#. payment terms
#. fiscal position

View file

@ -0,0 +1,3 @@
To use this module, you need to:
#. Merge purchase order with required criteria

View file

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_purchase_merge_automatic_wizard_user,access_purchase_merge_automatic_wizard_user,model_purchase_merge_automatic_wizard,purchase.group_purchase_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_purchase_merge_automatic_wizard_user access_purchase_merge_automatic_wizard_user model_purchase_merge_automatic_wizard purchase.group_purchase_user 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,449 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Purchase Merge</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="purchase-merge">
<h1 class="title">Purchase Merge</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:6593929c5934f76931f4345622c11a823589930923e026b3759d7257649c7d99
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/purchase-workflow/tree/16.0/purchase_merge"><img alt="OCA/purchase-workflow" src="https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/purchase-workflow-16-0/purchase-workflow-16-0-purchase_merge"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module adds a wizard to merge purchase order.</p>
<p>A wizard that can be called from tree view of purchase orders.
If merge criteria are validate:
All lines of all PO are “transferred” to the first one and some information like origin and partner_ref are concatenated.
We post a message on the chatter to indicate when the merge operation occurs and what were the PO concerned.
The empty PO are “canceled”</p>
<p>Merge criteria:
* PO are from the same supplier
* PO are in state draft
* PO have the same
#. currency
#. picking type
#. incoterms
#. payment terms
#. fiscal position</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="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>To use this module, you need to:</p>
<ol class="arabic simple">
<li>Merge purchase order with required criteria</li>
</ol>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/purchase-workflow/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/purchase-workflow/issues/new?body=module:%20purchase_merge%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://www.camptocamp.com">Camptocamp</a>:<ul>
<li>Thomas Nowicki &lt;<a class="reference external" href="mailto:thomas.nowicki&#64;camptocamp.com">thomas.nowicki&#64;camptocamp.com</a>&gt;</li>
<li>Bojan Anchev &lt;<a class="reference external" href="mailto:bojan.anchev&#64;camptocamp.com">bojan.anchev&#64;camptocamp.com</a>&gt;</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">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/purchase-workflow/tree/16.0/purchase_merge">OCA/purchase-workflow</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,4 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_purchase_merge

View file

@ -0,0 +1,308 @@
from odoo.exceptions import UserError
from odoo.tests import common
class TestPurchaseMerge(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestPurchaseMerge, cls).setUpClass()
cls.PurchaseMerge = cls.env["purchase.merge.automatic.wizard"]
cls.product_1 = cls.env["product.product"].create({"name": "Product 1"})
cls.product_2 = cls.env["product.product"].create({"name": "Product 2"})
cls.partner = cls.env["res.partner"].create({"name": "Partner"})
cls.partner_2 = cls.env["res.partner"].create({"name": "Partner 2"})
cls.PurchaseOrder = cls.env["purchase.order"]
cls.purchase_order_1 = cls.PurchaseOrder.create(
{
"partner_id": cls.partner.id,
"order_line": [
(0, 0, {"product_id": cls.product_1.id, "price_unit": 10})
],
}
)
cls.purchase_order_2 = cls.PurchaseOrder.create(
{
"partner_id": cls.partner.id,
"order_line": [
(0, 0, {"product_id": cls.product_2.id, "price_unit": 10})
],
}
)
cls.purchase_order_eur = cls.PurchaseOrder.create(
{
"partner_id": cls.partner.id,
"currency_id": cls.env.ref("base.EUR").id,
"order_line": [
(0, 0, {"product_id": cls.product_2.id, "price_unit": 10})
],
}
)
cls.purchase_order_usd = cls.PurchaseOrder.create(
{
"partner_id": cls.partner.id,
"currency_id": cls.env.ref("base.USD").id,
"order_line": [
(0, 0, {"product_id": cls.product_2.id, "price_unit": 10})
],
}
)
cls.fiscal_position_1 = cls.env["account.fiscal.position"].create(
{"name": "Fiscal Position 1"}
)
cls.fiscal_position_2 = cls.env["account.fiscal.position"].create(
{"name": "Fiscal Position 2"}
)
cls.incoterm_1 = cls.env["account.incoterms"].create(
{"name": "Incoterm 1", "code": "INC1"}
)
cls.incoterm_2 = cls.env["account.incoterms"].create(
{"name": "Incoterm 2", "code": "INC2"}
)
def test_count_purchase_order_lines(self):
self.purchase_merge_1 = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [self.purchase_order_1.id, self.purchase_order_2.id])
],
"dst_purchase_id": self.purchase_order_2.id,
}
)
self.purchase_merge_1.action_merge()
self.purchase_order_line_1 = len(self.purchase_order_2.order_line)
self.assertEqual(self.purchase_order_line_1, 2)
def test_purchase_ids(self):
self.purchase_merge_2 = self.PurchaseMerge.create(
{
"dst_purchase_id": self.purchase_order_2.id,
}
)
self.assertEqual(self.purchase_merge_2.action_merge(), False)
def test_default_purchase_ids(self):
context = {
"active_ids": [self.purchase_order_1.id, self.purchase_order_2.id],
"active_model": self.PurchaseOrder._name,
}
self.purchase_merge_3 = self.PurchaseMerge.with_context(**context).create({})
self.assertEqual(len(self.purchase_merge_3.dst_purchase_id), 1)
self.assertEqual(len(self.purchase_merge_3.purchase_ids), 2)
def test_purchase_order_states(self):
self.purchase_order_3 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
self.purchase_order_3.write({"state": "sent"})
self.purchase_merge_4 = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [self.purchase_order_1.id, self.purchase_order_3.id])
],
"dst_purchase_id": self.purchase_order_3.id,
}
)
with self.assertRaisesRegex(
UserError,
r"You can't merge purchase orders that aren't in draft state like: .+",
):
self.purchase_merge_4._check_state(self.purchase_merge_4.purchase_ids)
def test_purchase_order_currency(self):
purchase_order_dst = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_dst.write({"state": "sent"})
purchase_merge_4 = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [self.purchase_order_eur.id, self.purchase_order_usd.id])
],
"dst_purchase_id": purchase_order_dst.id,
}
)
with self.assertRaisesRegex(
UserError,
r"You can't merge purchase orders with different currencies: .+",
):
purchase_merge_4._check_all_values(purchase_merge_4.purchase_ids)
def test_purchase_order_fiscal_position(self):
purchase_order_fp_1 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
"fiscal_position_id": self.fiscal_position_1.id,
}
)
purchase_order_fp_2 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
"fiscal_position_id": self.fiscal_position_2.id,
}
)
purchase_order_dst = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_dst.write({"state": "sent"})
purchase_merge = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [purchase_order_fp_1.id, purchase_order_fp_2.id])
],
"dst_purchase_id": purchase_order_dst.id,
}
)
with self.assertRaisesRegex(
UserError,
r"You can't merge purchase orders with different fiscal positions: .+",
):
purchase_merge._check_all_values(purchase_merge.purchase_ids)
def test_purchase_order_incoterms(self):
purchase_order_inc_1 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
"incoterm_id": self.incoterm_1.id,
}
)
purchase_order_inc_2 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
"incoterm_id": self.incoterm_2.id,
}
)
purchase_order_dst = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_dst.write({"state": "sent"})
purchase_merge = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [purchase_order_inc_1.id, purchase_order_inc_2.id])
],
"dst_purchase_id": purchase_order_dst.id,
}
)
with self.assertRaisesRegex(
UserError,
r"You can't merge purchase orders with different incoterms: .+",
):
purchase_merge._check_all_values(purchase_merge.purchase_ids)
def test_purchase_order_payment_terms(self):
purchase_order_pt_1 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
"payment_term_id": self.env.ref(
"account.account_payment_term_end_following_month"
).id,
}
)
purchase_order_pt_2 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
"payment_term_id": self.env.ref(
"account.account_payment_term_15days"
).id,
}
)
purchase_order_dst = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_dst.write({"state": "sent"})
purchase_merge = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [purchase_order_pt_1.id, purchase_order_pt_2.id])
],
"dst_purchase_id": purchase_order_dst.id,
}
)
with self.assertRaisesRegex(
UserError,
r"You can't merge purchase orders with different payment terms: .+",
):
purchase_merge._check_all_values(purchase_merge.purchase_ids)
def test_purchase_order_partners(self):
purchase_order_partner1 = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_partner2 = self.env["purchase.order"].create(
{
"partner_id": self.partner_2.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_dst = self.env["purchase.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
(0, 0, {"product_id": self.product_2.id, "price_unit": 10})
],
}
)
purchase_order_dst.write({"state": "sent"})
purchase_merge = self.PurchaseMerge.create(
{
"purchase_ids": [
(6, 0, [purchase_order_partner1.id, purchase_order_partner2.id])
],
"dst_purchase_id": purchase_order_dst.id,
}
)
with self.assertRaisesRegex(
UserError,
r"You can't merge purchase orders with different suppliers: .+",
):
purchase_merge._check_all_values(purchase_merge.purchase_ids)

View file

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

View file

@ -0,0 +1,230 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openupgradelib import openupgrade_merge_records
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class MergePurchaseAutomatic(models.TransientModel):
"""
The idea behind this wizard is to create a list of potential purchases
to merge. We use two objects, the first one is the wizard for
the end-user. And the second will contain the purchase list to merge.
"""
_name = "purchase.merge.automatic.wizard"
_description = "Purchase Merge Automatic Wizard"
purchase_ids = fields.Many2many(
comodel_name="purchase.order",
)
dst_purchase_id = fields.Many2one(
comodel_name="purchase.order",
string="Destination",
)
@api.model
def default_get(self, fields_list):
res = super(MergePurchaseAutomatic, self).default_get(fields_list)
active_ids = self.env.context.get("active_ids")
purchase_orders = self.purchase_ids.browse(active_ids)
self._check_all_values(purchase_orders)
if (
self.env.context.get("active_model") == "purchase.order"
and len(active_ids) >= 1
):
res["purchase_ids"] = [(6, 0, active_ids)]
res["dst_purchase_id"] = self._get_ordered_purchase(active_ids)[-1].id
return res
# ----------------------------------------
# Check method
# ----------------------------------------
def _check_all_values(self, purchase_orders):
"""Contain all check method"""
self._check_state(purchase_orders)
self._check_content(purchase_orders)
def _check_state(self, purchase_orders):
non_draft_po = purchase_orders.filtered(lambda p: p.state != "draft")
if non_draft_po:
po_names = non_draft_po.mapped("name")
raise ValidationError(
_(
"You can't merge purchase orders that aren't in draft state like: {}"
).format(po_names)
)
def _check_content(self, purchase_orders):
error_messages = []
currencies = purchase_orders.currency_id
if len(currencies) > 1:
error_messages.append(
_(
"You can't merge purchase orders with different currencies: %s",
", ".join(currencies.mapped("name")),
)
)
picking_types = purchase_orders.picking_type_id
if len(picking_types) > 1:
error_messages.append(
_(
"You can't merge purchase orders with different picking types: %s",
", ".join(picking_types.mapped("name")),
)
)
incoterms = purchase_orders.incoterm_id
if len(incoterms) > 1:
error_messages.append(
_(
"You can't merge purchase orders with different incoterms: %s",
", ".join(incoterms.mapped("name")),
)
)
payment_terms = purchase_orders.payment_term_id
if len(payment_terms) > 1:
error_messages.append(
_(
"You can't merge purchase orders with different payment terms: %s",
", ".join(payment_terms.mapped("name")),
)
)
fiscal_positions = purchase_orders.fiscal_position_id
if len(fiscal_positions) > 1:
error_messages.append(
_(
"You can't merge purchase orders with different fiscal positions: %s",
", ".join(fiscal_positions.mapped("name")),
)
)
suppliers = purchase_orders.partner_id
if len(suppliers) > 1:
error_messages.append(
_(
"You can't merge purchase orders with different suppliers: %s",
", ".join(suppliers.mapped("name")),
)
)
if error_messages:
raise ValidationError("\n".join(error_messages))
# ----------------------------------------
# Update method
# ----------------------------------------
@api.model
def _update_values(self, src_purchase, dst_purchase):
"""Update values of dst_purchase with the ones from the src_purchase.
:param src_purchase : recordset of source purchase.order
:param dst_purchase : record of destination purchase.order
"""
# merge all order lines + set origin and partner_ref
dst_purchase.write(self._get_update_values(src_purchase, dst_purchase))
for po in src_purchase:
self._add_message("to", [dst_purchase.name], po)
po_names = src_purchase.mapped("name")
self._add_message("from", po_names, dst_purchase)
@api.model
def _get_update_values(self, src_purchase, dst_purchase):
"""Generate values of dst_purchase with the ones from the src_purchase.
:param src_purchase : recordset of source purchase.order
:param dst_purchase : record of destination purchase.order
"""
# initialize destination origin and partner_ref
origin = {dst_purchase.origin or ""}
origin.update({x.origin for x in src_purchase if x.origin})
partner_ref = {dst_purchase.partner_ref or ""}
partner_ref.update({x.partner_ref for x in src_purchase if x.partner_ref})
# Generate destination origin and partner_ref
src_order_line = src_purchase.mapped("order_line")
return {
"order_line": [(4, line, 0) for line in src_order_line.ids],
"origin": ", ".join(origin),
"partner_ref": ", ".join(partner_ref),
}
def _add_message(self, way, po_name, po):
"""Send a message post with to advise the po about the merge.
:param way : choice between 'from' or 'to'
:param po_name : list of purchase order name to add in the body
:param po_name : the po where the message will be posted
"""
subject = "Merge purchase order"
body = _(
"This purchase order lines have been merged %(way)s : %(po_names)s",
way=way,
po_names=" ,".join(po_name),
)
po.message_post(body=body, subject=subject, content_subtype="plaintext")
def _merge(self, purchases, dst_purchase=None):
"""private implementation of merge purchase
:param purchases : ids of purchase to merge
:param dst_purchase : record of destination purchase.order
"""
if len(purchases) < 2:
return
record_ids = purchases - dst_purchase
openupgrade_merge_records.merge_records(
env=self.env,
model_name=self._name,
record_ids=record_ids.ids,
target_record_id=dst_purchase.id,
)
self._check_all_values(purchases)
# remove dst_purchase from purchases to merge
if dst_purchase and dst_purchase in purchases:
src_purchase = purchases - dst_purchase
else:
dst_purchase = self.purchase_ids[-1]
src_purchase = self.purchase_ids[:-1]
# call sub methods to do the merge
self._update_values(src_purchase, dst_purchase)
# cancel source purchase, since they are merged
src_purchase.button_cancel()
# ----------------------------------------
# Helpers
# ----------------------------------------
@api.model
def _get_ordered_purchase(self, purchase_ids):
"""Helper returns a `purchase.order` recordset ordered by create_date
:param purchase_ids : list of purchase ids to sort
"""
return (
self.env["purchase.order"]
.browse(purchase_ids)
.sorted(
key=lambda p: (p.create_date or ""),
reverse=True,
)
)
# ----------------------------------------
# Actions
# ----------------------------------------
def action_merge(self):
"""Merge Quotation button. Merge the selected purchases."""
if not self.purchase_ids:
return False
self._merge(self.purchase_ids, self.dst_purchase_id)
return True

View file

@ -0,0 +1,58 @@
<odoo>
<record id="purchase_merge_automatic_wizard_form" model="ir.ui.view">
<field name='name'>purchase.merge.automatic.wizard.form</field>
<field name='model'>purchase.merge.automatic.wizard</field>
<field name='arch' type='xml'>
<form string='Automatic Merge Wizard'>
<sheet>
<group col="1">
<p class="oe_grey">
Selected purchase will be merged together.
</p>
<group col="2">
<field
name="dst_purchase_id"
domain="[('id', 'in', purchase_ids or False)]"
/>
</group>
<field name="purchase_ids" nolabel="1" string="Purchase">
<tree>
<field name="name" />
<field name="date_order" />
<field name="date_planned" />
<field name="amount_total" />
<field name="state" />
<field name="invoice_status" />
</tree>
</field>
</group>
</sheet>
<footer>
<button
name='action_merge'
string='Merge Purchase'
class='oe_highlight'
type='object'
/>
<button
special="cancel"
string="Cancel"
type="object"
class="btn btn-default oe_inline"
/>
</footer>
</form>
</field>
</record>
<record id="action_purchase_merge" model="ir.actions.act_window">
<field name="name">Merge Selected Purchase</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">purchase.merge.automatic.wizard</field>
<field name="view_mode">form</field>
<field name="binding_model_id" ref="purchase.model_purchase_order" />
<field name="target">new</field>
</record>
</odoo>

View file

@ -0,0 +1,42 @@
[project]
name = "odoo-bringout-oca-purchase-workflow-purchase_merge"
version = "16.0.0"
description = "Purchase Merge - Wizard to merge purchase with required conditions"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-purchase-workflow-purchase_order_approved>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["purchase_merge"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]