Move all OCA HR modules from oca-technical to dedicated oca-hr submodule

Reorganized 67 HR-related modules for better structure:
- Moved all odoo-bringout-oca-hr-* packages from packages/oca-technical/
- Now organized in dedicated packages/oca-hr/ submodule
- Includes attendance, expense, holiday, employee, and contract modules
- Maintains all module functionality while improving project organization

This creates a cleaner separation between general technical modules
and HR-specific functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ernad Husremovic 2025-08-30 17:11:28 +02:00
parent f672249949
commit dfcda4100c
2456 changed files with 120722 additions and 0 deletions

View file

@ -0,0 +1,45 @@
# Hr Personal Equipment Stock
Odoo addon: hr_personal_equipment_stock
## Installation
```bash
pip install odoo-bringout-oca-hr-hr_personal_equipment_stock
```
## Dependencies
This addon depends on:
- hr_personal_equipment_request
- stock
## Manifest Information
- **Name**: Hr Personal Equipment Stock
- **Version**: 16.0.1.0.0
- **Category**: N/A
- **License**: AGPL-3
- **Installable**: False
## Source
Based on [OCA/hr](https://github.com/OCA/hr) branch 16.0, addon `hr_personal_equipment_stock`.
## 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
- 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 Hr_personal_equipment_stock Module - hr_personal_equipment_stock
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 hr_personal_equipment_stock. 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,6 @@
# Dependencies
This addon depends on:
- [hr_personal_equipment_request](https://github.com/bringout/oca-technical)
- [stock](https://github.com/bringout/oca-ocb-warehouse/tree/0ee5ffef60413a71dceb350918ad3fb572ec1875/odoo-bringout-oca-ocb-stock)

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 hr_personal_equipment_stock or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-hr-hr_personal_equipment_stock"
# or
uv pip install odoo-bringout-oca-hr-hr_personal_equipment_stock"
```

View file

@ -0,0 +1,18 @@
# Models
Detected core models and extensions in hr_personal_equipment_stock.
```mermaid
classDiagram
class hr_personal_equipment
class hr_personal_equipment_request
class procurement_group
class stock_location
class stock_move
class stock_picking
class stock_rule
```
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: hr_personal_equipment_stock. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon hr_personal_equipment_stock
- License: LGPL-3

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,85 @@
===========================
Hr Personal Equipment Stock
===========================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:fc5b579fad57f746f95989e01349e102d240d01825132f2a8b935a5b2499ccfb
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fhr-lightgray.png?logo=github
:target: https://github.com/OCA/hr/tree/16.0/hr_personal_equipment_stock
:alt: OCA/hr
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/hr-16-0/hr-16-0-hr_personal_equipment_stock
: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/hr&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module integrates stock with hr_personal_equipment_request module.
When the equipment request is accepted, a stock request is generated and a "stock.move" is created for each request line.
If the "stock.move" is marked as done, the corresponding allocations are marked as valid if the quantity_delivered is equal to the requested quantity.
In case a service is added to the equipment request, it will skip the procurement method. Instead, it has to be validated from the corresponding allocation.
In case a backorder is generated and cancelled afterwards, if qty_delivered is not null, the allocation is marked as valid. If not, it is marked as cancelled.
**Table of contents**
.. contents::
:local:
Installation
============
This module is auto installed if the modules "hr_personal_equipment_request" and "stock" are installed.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/hr/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/hr/issues/new?body=module:%20hr_personal_equipment_stock%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
~~~~~~~
* Creu Blanca
Contributors
~~~~~~~~~~~~
* Alba Riera <alba.riera@creublanca.es>
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/hr <https://github.com/OCA/hr/tree/16.0/hr_personal_equipment_stock>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

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

View file

@ -0,0 +1,22 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Hr Personal Equipment Stock",
"summary": """
This addon allows to integrate hr_personal_equipment_request with stock""",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Creu Blanca,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/hr",
"depends": ["hr_personal_equipment_request", "stock"],
"data": [
"views/stock_location.xml",
"views/stock_move.xml",
"views/procurement_group.xml",
"views/hr_personal_equipment.xml",
"views/hr_personal_equipment_request.xml",
"views/stock_picking.xml",
],
"auto_install": True,
}

View file

@ -0,0 +1,112 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_personal_equipment_stock
#
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: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment
msgid "Adds personal equipment information and allocation"
msgstr "Dodaje informacije o osobnoj opremi i dodjeli"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__qty_delivered
msgid "Delivered Quantity"
msgstr "Isporučena količina"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_move__personal_equipment_id
msgid "Employee Personal Equipment"
msgstr "Osobna oprema zaposlenika"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_procurement_group__equipment_request_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_picking__equipment_request_id
msgid "Equipment Request"
msgstr "Zahtjev za opremu"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_location
msgid "Inventory Locations"
msgstr "Lokacije inventure"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_location__is_personal_equipment_location
msgid "Is personal equipment location?"
msgstr "Je li lokacija osobne opreme?"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__location_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__location_id
msgid "Location"
msgstr "Lokacija"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid ""
"Moves created through this stock request will be put in this procurement "
"group. If none is given, the moves generated by procurement rules will be "
"grouped into one big picking."
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_ids
msgid "Picking"
msgstr "Skladišnice"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_count
msgid "Picking Count"
msgstr "Broj prikupljanja"
#. module: hr_personal_equipment_stock
#: model_terms:ir.ui.view,arch_db:hr_personal_equipment_stock.hr_personal_equipment_request_form_view_picking
msgid "Pickings"
msgstr "Skladišnice"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_procurement_group
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid "Procurement Group"
msgstr "Grupa naručivanja"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__skip_procurement
msgid "Skip Procurement"
msgstr "Preskoči nabavku"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_move
msgid "Stock Move"
msgstr "Skladišno kretanje"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__move_ids
msgid "Stock Moves"
msgstr "Kretanje zaliha"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_rule
msgid "Stock Rule"
msgstr "Skladišno pravilo"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment_request
msgid "This model allows to create a personal equipment request"
msgstr "Ovaj model omogućava kreiranje zahtjeva za osobnu opremu"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_picking
msgid "Transfer"
msgstr "Prijenos"

View file

@ -0,0 +1,128 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_personal_equipment_stock
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-02-18 21:33+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: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment
msgid "Adds personal equipment information and allocation"
msgstr "Agrega información y destribución de equipo personal"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__qty_delivered
msgid "Delivered Quantity"
msgstr "Cantidad Entregada"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_move__personal_equipment_id
msgid "Employee Personal Equipment"
msgstr "Equipamiento Personal de Empleado"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_procurement_group__equipment_request_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_picking__equipment_request_id
msgid "Equipment Request"
msgstr "Solicitud de equipamiento"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_location
msgid "Inventory Locations"
msgstr "Ubicaciones de inventario"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_location__is_personal_equipment_location
msgid "Is personal equipment location?"
msgstr "Es una ubicación de equipamiento personal?"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__location_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__location_id
msgid "Location"
msgstr "Ubicación"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid ""
"Moves created through this stock request will be put in this procurement "
"group. If none is given, the moves generated by procurement rules will be "
"grouped into one big picking."
msgstr ""
"Los movimientos creados a través de esta solicitud de existencias se "
"colocarán en este grupo de compras. Si no se proporciona ninguno, los "
"movimientos generados por las reglas de adquisición se agruparán en una gran "
"selección."
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_ids
msgid "Picking"
msgstr "Transferencia"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_count
msgid "Picking Count"
msgstr "Cuenta de transferencias"
#. module: hr_personal_equipment_stock
#: model_terms:ir.ui.view,arch_db:hr_personal_equipment_stock.hr_personal_equipment_request_form_view_picking
msgid "Pickings"
msgstr "Transferencias"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_procurement_group
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid "Procurement Group"
msgstr "Grupo de Adquisiciones"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__skip_procurement
msgid "Skip Procurement"
msgstr "Saltar Adquisiciones"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_move
msgid "Stock Move"
msgstr "Movimiento de stock"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__move_ids
msgid "Stock Moves"
msgstr "Movimientos de existencias"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_rule
msgid "Stock Rule"
msgstr "Regla de existencias"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment_request
msgid "This model allows to create a personal equipment request"
msgstr "Este modelo permite crear solicitudes de equipamiento personal"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_picking
msgid "Transfer"
msgstr "Transferencia"
#~ msgid "Display Name"
#~ msgstr "Mostrar Nombre"
#~ msgid "ID"
#~ msgstr "ID"
#~ msgid "Last Modified on"
#~ msgstr "Última Modificación el"

View file

@ -0,0 +1,113 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_personal_equipment_stock
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: es_PA\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"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment
msgid "Adds personal equipment information and allocation"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__qty_delivered
msgid "Delivered Quantity"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_move__personal_equipment_id
msgid "Employee Personal Equipment"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_procurement_group__equipment_request_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_picking__equipment_request_id
msgid "Equipment Request"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_location
msgid "Inventory Locations"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_location__is_personal_equipment_location
msgid "Is personal equipment location?"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__location_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__location_id
msgid "Location"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid ""
"Moves created through this stock request will be put in this procurement "
"group. If none is given, the moves generated by procurement rules will be "
"grouped into one big picking."
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_ids
msgid "Picking"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_count
msgid "Picking Count"
msgstr ""
#. module: hr_personal_equipment_stock
#: model_terms:ir.ui.view,arch_db:hr_personal_equipment_stock.hr_personal_equipment_request_form_view_picking
msgid "Pickings"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_procurement_group
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid "Procurement Group"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__skip_procurement
msgid "Skip Procurement"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_move
msgid "Stock Move"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__move_ids
msgid "Stock Moves"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_rule
msgid "Stock Rule"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment_request
msgid "This model allows to create a personal equipment request"
msgstr ""
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_picking
msgid "Transfer"
msgstr ""

View file

@ -0,0 +1,129 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_personal_equipment_stock
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-06-01 13:10+0000\n"
"Last-Translator: Sergio Zanchetta <primes2h@gmail.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.17\n"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment
msgid "Adds personal equipment information and allocation"
msgstr "Aggiunge informazioni e assegnazione su attrezzatura individuale"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__qty_delivered
msgid "Delivered Quantity"
msgstr "Quantità consegnata"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_move__personal_equipment_id
msgid "Employee Personal Equipment"
msgstr "Attrezzatura individuale dipendente"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_procurement_group__equipment_request_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_picking__equipment_request_id
msgid "Equipment Request"
msgstr "Richiesta attrezzatura"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_location
msgid "Inventory Locations"
msgstr "Ubicazioni di inventario"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_stock_location__is_personal_equipment_location
msgid "Is personal equipment location?"
msgstr "È una ubicazione per attrezzatura individuale?"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__location_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__location_id
msgid "Location"
msgstr "Ubicazione"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,help:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid ""
"Moves created through this stock request will be put in this procurement "
"group. If none is given, the moves generated by procurement rules will be "
"grouped into one big picking."
msgstr ""
"I movimenti creati tramite questa richiesta di magazzino verranno inseriti "
"in questo gruppo di approvvigionamento. Se non ne viene fornito nessuno, i "
"movimenti generati dalle regole di approvvigionamento verranno raggruppati "
"in un unico grande prelievo."
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_ids
msgid "Picking"
msgstr "Prelievo"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__picking_count
msgid "Picking Count"
msgstr "Conteggio prelievi"
#. module: hr_personal_equipment_stock
#: model_terms:ir.ui.view,arch_db:hr_personal_equipment_stock.hr_personal_equipment_request_form_view_picking
msgid "Pickings"
msgstr "Prelievi"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_procurement_group
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__procurement_group_id
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment_request__procurement_group_id
msgid "Procurement Group"
msgstr "Gruppo di approvvigionamento"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__skip_procurement
msgid "Skip Procurement"
msgstr "Ignora approvvigionamento"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_move
msgid "Stock Move"
msgstr "Movimento di magazzino"
#. module: hr_personal_equipment_stock
#: model:ir.model.fields,field_description:hr_personal_equipment_stock.field_hr_personal_equipment__move_ids
msgid "Stock Moves"
msgstr "Movimenti di magazzino"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_rule
msgid "Stock Rule"
msgstr "Regola di giacenza"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_hr_personal_equipment_request
msgid "This model allows to create a personal equipment request"
msgstr ""
"Questo modello permette di creare una richiesta attrezzatura individuale"
#. module: hr_personal_equipment_stock
#: model:ir.model,name:hr_personal_equipment_stock.model_stock_picking
msgid "Transfer"
msgstr "Trasferimento"
#~ msgid "Display Name"
#~ msgstr "Nome visualizzato"
#~ msgid "ID"
#~ msgstr "ID"
#~ msgid "Last Modified on"
#~ msgstr "Ultima modifica il"

View file

@ -0,0 +1,7 @@
from . import hr_personal_equipment_request
from . import hr_personal_equipment
from . import procurement_group
from . import stock_picking
from . import stock_move
from . import stock_rule
from . import stock_location

View file

@ -0,0 +1,122 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.exceptions import UserError
class HrPersonalEquipment(models.Model):
_inherit = "hr.personal.equipment"
location_id = fields.Many2one(related="equipment_request_id.location_id")
procurement_group_id = fields.Many2one(
"procurement.group",
"Procurement Group",
readonly=True,
help="Moves created through this stock request will be put in this "
"procurement group. If none is given, the moves generated by "
"procurement rules will be grouped into one big picking.",
related="equipment_request_id.procurement_group_id",
)
qty_delivered = fields.Float(
"Delivered Quantity",
copy=False,
compute="_compute_qty_delivered",
compute_sudo=True,
store=True,
)
move_ids = fields.One2many(
"stock.move", "personal_equipment_id", string="Stock Moves"
)
skip_procurement = fields.Boolean(compute="_compute_skip_procurement")
@api.depends("state", "product_id", "product_id.type")
def _compute_skip_procurement(self):
for record in self:
record.skip_procurement = record._skip_procurement()
@api.depends(
"move_ids.state",
"move_ids.scrapped",
"move_ids.product_uom_qty",
"move_ids.product_uom",
)
def _compute_qty_delivered(self):
for line in self:
qty = 0.0
for move in line.move_ids.filtered(
lambda r: r.state == "done" and line.product_id == r.product_id
):
qty += move.product_uom._compute_quantity(
move.product_uom_qty, line.product_uom_id
)
line.qty_delivered = qty
def _skip_procurement(self):
return self.product_id.type not in ("consu", "product")
def _prepare_procurement_values(self, group_id=False):
"""Prepare specific key for moves or other components that
will be created from a procurement rule
coming from a stock request. This method could be override
in order to add other custom key that could be used in
move/po creation.
"""
return {
"group_id": group_id or self.procurement_group_id.id or False,
"partner_id": self.employee_id.user_id.partner_id.id,
"personal_equipment_id": self.id,
}
def _get_company(self):
return self.employee_id.company_id or self.env.company
def _action_launch_procurement_rule(self):
"""
Launch procurement group run method with required/custom
fields generated by a
equipment request. procurement group will launch '_run_move',
'_run_buy' or '_run_manufacture'
depending on the stock request product rule.
"""
errors = []
for allocation in self:
if allocation.skip_procurement:
continue
values = allocation._prepare_procurement_values(
group_id=allocation.procurement_group_id
)
try:
# We launch with sudo because potentially we could create
# objects that the user is not authorized to create, such
# as PO.
procurement = self.env["procurement.group"].Procurement(
allocation.product_id,
allocation.quantity,
allocation.product_uom_id,
allocation.location_id,
allocation.equipment_request_id.name,
allocation.equipment_request_id.name,
allocation._get_company(),
values,
)
self.env["procurement.group"].sudo().run([procurement])
except UserError as error:
errors.append(error.args[0])
if errors:
raise UserError("\n".join(errors))
return True
def _accept_request(self):
res = super()._accept_request()
self._action_launch_procurement_rule()
return res
def _validate_allocation_vals(self):
res = super()._validate_allocation_vals()
if self.skip_procurement:
res["qty_delivered"] = self.quantity
return res

View file

@ -0,0 +1,56 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class HrPersonalEquipmentRequest(models.Model):
_inherit = "hr.personal.equipment.request"
location_id = fields.Many2one(
"stock.location",
ondelete="cascade",
required=True,
domain=[("is_personal_equipment_location", "=", True)],
)
procurement_group_id = fields.Many2one(
"procurement.group",
"Procurement Group",
help="Moves created through this stock request will be put in this "
"procurement group. If none is given, the moves generated by "
"procurement rules will be grouped into one big picking.",
copy=False,
)
picking_ids = fields.One2many("stock.picking", inverse_name="equipment_request_id")
picking_count = fields.Integer(compute="_compute_picking_count")
@api.depends("picking_ids")
def _compute_picking_count(self):
for rec in self:
rec.picking_count = len(rec.picking_ids)
def _get_procurement_group(self):
if self.procurement_group_id:
return self.procurement_group_id.id
return (
self.env["procurement.group"].create(self._get_procurement_group_vals()).id
)
def _get_procurement_group_vals(self):
return {
"move_type": "direct",
"equipment_request_id": self.id,
"partner_id": self.employee_id.user_id.partner_id.id,
}
def _accept_request_vals(self):
result = super()._accept_request_vals()
result["procurement_group_id"] = self._get_procurement_group()
return result
def action_view_pickings(self):
self.ensure_one()
action = self.env.ref("stock.action_picking_tree_all").sudo().read()[0]
action["domain"] = [("equipment_request_id", "=", self.id)]
return action

View file

@ -0,0 +1,11 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ProcurementGroup(models.Model):
_inherit = "procurement.group"
equipment_request_id = fields.Many2one("hr.personal.equipment.request")

View file

@ -0,0 +1,15 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class StockLocation(models.Model):
_inherit = "stock.location"
is_personal_equipment_location = fields.Boolean(
string="Is personal equipment location?"
)
# This field is used for filter purpose in the
# hr.personal.equipment.request location field

View file

@ -0,0 +1,34 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class StockMove(models.Model):
_inherit = "stock.move"
personal_equipment_id = fields.Many2one(
"hr.personal.equipment", "Employee Personal Equipment"
)
@api.model
def _prepare_merge_moves_distinct_fields(self):
distinct_fields = super()._prepare_merge_moves_distinct_fields()
distinct_fields.append("personal_equipment_id")
return distinct_fields
@api.model
def _prepare_merge_move_sort_method(self, move):
move.ensure_one()
keys_sorted = super()._prepare_merge_move_sort_method(move)
keys_sorted.append(move.personal_equipment_id.id)
return keys_sorted
def _action_cancel(self):
res = super()._action_cancel()
for rec in self.sudo():
if not rec.personal_equipment_id.qty_delivered:
rec.personal_equipment_id.update({"state": "cancelled"})
else:
rec.personal_equipment_id.update({"state": "valid"})
return res

View file

@ -0,0 +1,33 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class StockPicking(models.Model):
_inherit = "stock.picking"
equipment_request_id = fields.Many2one(
related="group_id.equipment_request_id", store=True
)
def _action_done(self):
res = super()._action_done()
if self.equipment_request_id:
for move in self.move_ids_without_package:
if move.state == "done":
request_lines = self.equipment_request_id.sudo().line_ids.filtered(
lambda x: x.product_id == move.product_id
)
for line in request_lines:
qty_initial = line.product_uom_id._compute_quantity(
line.quantity, line.product_uom_id
)
qty_done = line.product_uom_id._compute_quantity(
line.qty_delivered, line.product_uom_id
)
if qty_done:
if qty_initial <= qty_done:
line.validate_allocation()
return res

View file

@ -0,0 +1,33 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class StockRule(models.Model):
_inherit = "stock.rule"
def _get_stock_move_values(
self,
product_id,
product_qty,
product_uom,
location_id,
name,
origin,
company_id,
values,
):
result = super()._get_stock_move_values(
product_id,
product_qty,
product_uom,
location_id,
name,
origin,
company_id,
values,
)
if values.get("personal_equipment_id"):
result["personal_equipment_id"] = values.get("personal_equipment_id")
return result

View file

@ -0,0 +1 @@
* Alba Riera <alba.riera@creublanca.es>

View file

@ -0,0 +1,5 @@
This module integrates stock with hr_personal_equipment_request module.
When the equipment request is accepted, a stock request is generated and a "stock.move" is created for each request line.
If the "stock.move" is marked as done, the corresponding allocations are marked as valid if the quantity_delivered is equal to the requested quantity.
In case a service is added to the equipment request, it will skip the procurement method. Instead, it has to be validated from the corresponding allocation.
In case a backorder is generated and cancelled afterwards, if qty_delivered is not null, the allocation is marked as valid. If not, it is marked as cancelled.

View file

@ -0,0 +1 @@
This module is auto installed if the modules "hr_personal_equipment_request" and "stock" are installed.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,432 @@
<!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>Hr Personal Equipment Stock</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="hr-personal-equipment-stock">
<h1 class="title">Hr Personal Equipment Stock</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:fc5b579fad57f746f95989e01349e102d240d01825132f2a8b935a5b2499ccfb
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/hr/tree/16.0/hr_personal_equipment_stock"><img alt="OCA/hr" src="https://img.shields.io/badge/github-OCA%2Fhr-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/hr-16-0/hr-16-0-hr_personal_equipment_stock"><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/hr&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 integrates stock with hr_personal_equipment_request module.
When the equipment request is accepted, a stock request is generated and a “stock.move” is created for each request line.
If the “stock.move” is marked as done, the corresponding allocations are marked as valid if the quantity_delivered is equal to the requested quantity.
In case a service is added to the equipment request, it will skip the procurement method. Instead, it has to be validated from the corresponding allocation.
In case a backorder is generated and cancelled afterwards, if qty_delivered is not null, the allocation is marked as valid. If not, it is marked as cancelled.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#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="installation">
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>This module is auto installed if the modules “hr_personal_equipment_request” and “stock” are installed.</p>
</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/hr/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/hr/issues/new?body=module:%20hr_personal_equipment_stock%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>Creu Blanca</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Alba Riera &lt;<a class="reference external" href="mailto:alba.riera&#64;creublanca.es">alba.riera&#64;creublanca.es</a>&gt;</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/hr/tree/16.0/hr_personal_equipment_stock">OCA/hr</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View file

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

View file

@ -0,0 +1,213 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.exceptions import UserError
from odoo.tests import TransactionCase
class TestHRPersonalEquipment(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.warehouse = cls.env.ref("stock.warehouse0")
cls.company = cls.env.ref("base.main_company")
cls.ressuply_loc = cls.env["stock.location"].create(
{
"name": "Warehouse Test",
"location_id": cls.warehouse.view_location_id.id,
}
)
cls.location_employee = cls.env["stock.location"].create(
{
"name": "Employee Personal Equipment Virtual Location",
"location_id": cls.warehouse.view_location_id.id,
"usage": "transit",
"is_personal_equipment_location": True,
}
)
cls.route = cls.env["stock.route"].create(
{
"name": "Employee Personal Equipment Route",
"product_categ_selectable": False,
"product_selectable": True,
"company_id": cls.company.id,
"sequence": 10,
}
)
cls.env["stock.rule"].create(
{
"name": "Employee Personal Equipment Rule",
"route_id": cls.route.id,
"location_src_id": cls.ressuply_loc.id,
"location_dest_id": cls.location_employee.id,
"action": "pull",
"picking_type_id": cls.warehouse.int_type_id.id,
"procure_method": "make_to_stock",
"warehouse_id": cls.warehouse.id,
"company_id": cls.company.id,
"propagate_cancel": False,
}
)
cls.user = (
cls.env["res.users"]
.sudo()
.create(
{
"name": "Test User",
"login": "user@test.com",
"email": "user@test.com",
"groups_id": [
(4, cls.env.ref("base.group_user").id),
(4, cls.env.ref("hr.group_hr_user").id),
(4, cls.env.ref("stock.group_stock_manager").id),
],
}
)
)
cls.employee = cls.env["hr.employee"].create(
{"name": "Employee Test", "user_id": cls.user.id}
)
cls.product_personal_equipment_1 = cls.env["product.template"].create(
{
"name": "Product Test Personal Equipment",
"is_personal_equipment": True,
"route_ids": [(6, 0, cls.route.ids)],
"qty_available": 100,
"type": "product",
"uom_id": cls.env.ref("uom.product_uom_unit").id,
}
)
cls.product_personal_equipment_2 = cls.env["product.template"].create(
{
"name": "Service Test Personal Equipment 2",
"is_personal_equipment": True,
"type": "service",
"uom_id": cls.env.ref("uom.product_uom_unit").id,
}
)
lines = [
{
"name": "Personal Equipment 1",
"product_id": cls.product_personal_equipment_1.product_variant_id.id,
"quantity": 3,
"product_uom_id": cls.env.ref("uom.product_uom_unit").id,
},
{
"name": "Personal Equipment 2",
"product_id": cls.product_personal_equipment_2.product_variant_id.id,
"quantity": 2,
"product_uom_id": cls.env.ref("uom.product_uom_unit").id,
},
]
cls.personal_equipment_request = (
cls.env["hr.personal.equipment.request"]
.with_user(cls.user.id)
.create(
{
"name": "Personal Equipment Request Test",
"line_ids": [(0, 0, line) for line in lines],
"location_id": cls.location_employee.id,
}
)
)
# hr.personal.equipment.request
def test_get_procurement_group_without_group_set(self):
self.assertEqual(self.personal_equipment_request.state, "draft")
self.assertFalse(self.personal_equipment_request.procurement_group_id)
self.assertFalse(
self.personal_equipment_request.line_ids[0].procurement_group_id
)
self.personal_equipment_request.accept_request()
self.assertEqual(self.personal_equipment_request.state, "accepted")
self.assertTrue(self.personal_equipment_request.procurement_group_id)
self.assertTrue(
self.personal_equipment_request.line_ids[0].procurement_group_id
)
def test_get_procurement_group_with_group_set(self):
self.assertEqual(self.personal_equipment_request.state, "draft")
procurement_group_id = self.env["procurement.group"].create(
{"move_type": "direct"}
)
self.personal_equipment_request.procurement_group_id = procurement_group_id.id
self.assertTrue(self.personal_equipment_request.procurement_group_id)
self.assertTrue(
self.personal_equipment_request.line_ids[0].procurement_group_id
)
self.personal_equipment_request.accept_request()
self.assertEqual(self.personal_equipment_request.state, "accepted")
self.assertTrue(self.personal_equipment_request.procurement_group_id)
self.assertTrue(
self.personal_equipment_request.line_ids[0].procurement_group_id
)
self.assertEqual(
self.personal_equipment_request.procurement_group_id.id,
procurement_group_id.id,
)
def test_compute_picking_count(self):
self.assertEqual(self.personal_equipment_request.picking_count, 0)
self.personal_equipment_request.accept_request()
self.assertEqual(self.personal_equipment_request.picking_count, 1)
# hr.personal.equipment
def test_skip_procurement(self):
self.personal_equipment_request.line_ids[0]._compute_skip_procurement()
self.assertFalse(self.personal_equipment_request.line_ids[0].skip_procurement)
self.personal_equipment_request.line_ids[1]._compute_skip_procurement()
self.assertTrue(self.personal_equipment_request.line_ids[1].skip_procurement)
def test_compute_qty_delivered(self):
self.personal_equipment_request.accept_request()
allocation = self.personal_equipment_request.line_ids[0]
move = allocation.move_ids[0]
move.quantity_done = allocation.quantity
picking = self.personal_equipment_request.picking_ids[0]
picking._action_done()
self.assertEqual(allocation.qty_delivered, allocation.quantity)
self.assertEqual(allocation.state, "valid")
def test_quantity_delivered_skip_procurement(self):
allocation = self.personal_equipment_request.line_ids[1]
self.personal_equipment_request.accept_request()
allocation.validate_allocation()
self.assertEqual(allocation.qty_delivered, allocation.quantity)
def test_action_launch_procurement_rule_raise_error(self):
allocation = self.personal_equipment_request.line_ids[0]
allocation.location_id = None
with self.assertRaises(UserError):
self.personal_equipment_request.accept_request()
# stock.move
def test_action_cancel_with_qty_delivered(self):
allocation = self.personal_equipment_request.line_ids[0]
self.personal_equipment_request.accept_request()
self.assertEqual(allocation.state, "accepted")
picking = self.personal_equipment_request.picking_ids[0]
picking.action_cancel()
self.assertEqual(allocation.qty_delivered, 0)
self.assertEqual(allocation.state, "cancelled")
def test_action_cancel_without_qty_delivered(self):
allocation = self.personal_equipment_request.line_ids[0]
self.personal_equipment_request.accept_request()
self.assertEqual(allocation.state, "accepted")
move = allocation.move_ids[0]
move.quantity_done = allocation.quantity - 1
picking = self.personal_equipment_request.picking_ids[0]
picking._action_done()
back_order = self.personal_equipment_request.picking_ids[1]
back_order.action_cancel()
self.assertEqual(allocation.qty_delivered, allocation.quantity - 1)
self.assertEqual(allocation.state, "valid")
def test_action_view_pickings(self):
action = self.personal_equipment_request.action_view_pickings()
self.assertEqual(action["name"], "Transfers")

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2021 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="hr_personal_equipment_form_view">
<field
name="name"
>hr.personal.equipment.form (in hr_personal_equipment_stock)</field>
<field name="model">hr.personal.equipment</field>
<field
name="inherit_id"
ref="hr_personal_equipment_request.hr_personal_equipment_form_view"
/>
<field name="arch" type="xml">
<button name="validate_allocation" position="attributes">
<attribute
name="attrs"
>{'invisible': ['|', ('skip_procurement', '=', False), ('state', '!=', 'accepted')]}</attribute>
</button>
<field name="equipment_request_id" position='after'>
<field name="location_id" />
<field name="procurement_group_id" invisible="1" />
<field name="skip_procurement" />
</field>
<field name="quantity" position="before">
<field name="qty_delivered" />
</field>
<field name="quantity" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record model="ir.ui.view" id="hr_personal_equipment_tree_view">
<field
name="name"
>hr.personal.equipment.tree (in hr_personal_equipment_stock)</field>
<field name="model">hr.personal.equipment</field>
<field
name="inherit_id"
ref="hr_personal_equipment_request.hr_personal_equipment_tree_view"
/>
<field name="arch" type="xml">
<field name="quantity" position="before">
<field name="qty_delivered" />
</field>
<field name="quantity" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2021 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="hr_personal_equipment_request_form_view">
<field
name="name"
>hr.personal.equipment.request.form (in hr_personal_equipment_stock)</field>
<field name="model">hr.personal.equipment.request</field>
<field
name="inherit_id"
ref="hr_personal_equipment_request.hr_personal_equipment_request_form_view"
/>
<field name="arch" type="xml">
<xpath expr="//field[@name='employee_id']" position="after">
<field
name="location_id"
attrs="{'readonly': [('state', '!=', 'draft')]}"
/>
<field
name="procurement_group_id"
invisible="1"
attrs="{'readonly': [('state', '!=', 'draft')]}"
/>
</xpath>
<xpath expr="//tree/field[@name='state']" position="before">
<field name="qty_delivered" />
<field name="location_id" invisible="1" />
<field name="procurement_group_id" invisible="1" />
</xpath>
</field>
</record>
<record model="ir.ui.view" id="hr_personal_equipment_request_form_view_picking">
<field
name="name"
>hr.personal.equipment.request.form (in hr_personal_equipment_stock)</field>
<field name="model">hr.personal.equipment.request</field>
<field
name="inherit_id"
ref="hr_personal_equipment_request.hr_personal_equipment_request_form_view"
/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button
type="object"
name="action_view_pickings"
class="oe_stat_button"
icon="fa-truck"
attrs="{'invisible': [('picking_count','&lt;','1')]}"
groups="stock.group_stock_user"
>
<field name="picking_count" widget="statinfo" string="Pickings" />
</button>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="hr_personal_equipment_request_tree_view">
<field
name="name"
>hr.personal.equipment.request.tree (in hr_personal_equipment_stock)</field>
<field name="model">hr.personal.equipment.request</field>
<field
name="inherit_id"
ref="hr_personal_equipment_request.hr_personal_equipment_request_tree_view"
/>
<field name="arch" type="xml">
<xpath expr="//field[@name='employee_id']" position="after">
<field name="location_id" />
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2021 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="procurement_group_form_view">
<field
name="name"
>procurement.group.form (in hr_personal_equipment_stock)</field>
<field name="model">procurement.group</field>
<field name="inherit_id" ref="stock.procurement_group_form_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='move_type']" position="after">
<field name="equipment_request_id" groups="stock.group_stock_user" />
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2021 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="stock_location_form_view">
<field name="name">stock.location.form (in hr_personal_equipment_stock)</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_form" />
<field name="arch" type="xml">
<field name="return_location" position="after">
<field name="is_personal_equipment_location" />
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2021 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="stock_move_form_view">
<field name="name">stock.move.form (in hr_personal_equipment_stock)</field>
<field name="model">stock.move</field>
<field name="inherit_id" ref="stock.view_move_form" />
<field name="arch" type="xml">
<field name="reference" position="after">
<field name="personal_equipment_id" groups="stock.group_stock_user" />
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2021 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="view_picking_form">
<field name="name">stock.picking.form(in hr_personal_equipment_stock)</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form" />
<field name="arch" type="xml">
<xpath
expr="//page[@name='extra']//group//field[@name='company_id']"
position="after"
>
<field name="equipment_request_id" groups="hr.group_hr_user" />
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,44 @@
[project]
name = "odoo-bringout-oca-hr-hr_personal_equipment_stock"
version = "16.0.0"
description = "Hr Personal Equipment Stock -
This addon allows to integrate hr_personal_equipment_request with stock"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-hr-hr_personal_equipment_request>=16.0.0",
"odoo-bringout-oca-ocb-stock>=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 = ["hr_personal_equipment_stock"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]