diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..c1b867e --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,198 @@ +import { defineConfig } from "eslint/config"; +import globals from "globals"; + +export default defineConfig([{ + languageOptions: { + globals: { + ...globals.browser, + _: "readonly", + $: "readonly", + fuzzy: "readonly", + jQuery: "readonly", + moment: "readonly", + odoo: "readonly", + openerp: "readonly", + owl: "readonly", + luxon: "readonly", + }, + + ecmaVersion: 2019, + sourceType: "script", + }, + + rules: { + "accessor-pairs": "warn", + "array-callback-return": "warn", + "callback-return": "warn", + + "capitalized-comments": ["warn", "always", { + ignoreConsecutiveComments: true, + ignoreInlineComments: true, + }], + + complexity: ["warn", 15], + "constructor-super": "warn", + "dot-notation": "warn", + eqeqeq: "warn", + "global-require": "warn", + "handle-callback-err": "warn", + "id-blacklist": "warn", + "id-match": "warn", + "init-declarations": "error", + "max-depth": "warn", + "max-nested-callbacks": "warn", + "max-statements-per-line": "warn", + "no-alert": "warn", + "no-array-constructor": "warn", + "no-caller": "warn", + "no-case-declarations": "warn", + "no-class-assign": "warn", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-condition": "warn", + "no-control-regex": "warn", + "no-debugger": "error", + "no-delete-var": "warn", + "no-div-regex": "warn", + "no-dupe-args": "error", + "no-dupe-class-members": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-duplicate-imports": "error", + "no-else-return": "warn", + "no-empty-character-class": "warn", + "no-empty-function": "error", + "no-empty-pattern": "error", + "no-empty": "warn", + "no-eq-null": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "warn", + "no-extra-bind": "warn", + "no-extra-boolean-cast": "warn", + "no-extra-label": "warn", + "no-fallthrough": "warn", + "no-func-assign": "error", + "no-global-assign": "error", + + "no-implicit-coercion": ["warn", { + allow: ["~"], + }], + + "no-implicit-globals": "warn", + "no-implied-eval": "warn", + "no-inline-comments": "warn", + "no-inner-declarations": "warn", + "no-invalid-regexp": "warn", + "no-irregular-whitespace": "warn", + "no-iterator": "warn", + "no-label-var": "warn", + "no-labels": "warn", + "no-lone-blocks": "warn", + "no-lonely-if": "error", + "no-mixed-requires": "error", + "no-multi-str": "warn", + "no-native-reassign": "error", + "no-negated-condition": "warn", + "no-negated-in-lhs": "error", + "no-new-func": "warn", + "no-new-object": "warn", + "no-new-require": "warn", + "no-new-symbol": "warn", + "no-new-wrappers": "warn", + "no-new": "warn", + "no-obj-calls": "warn", + "no-octal-escape": "warn", + "no-octal": "warn", + "no-param-reassign": "warn", + "no-path-concat": "warn", + "no-process-env": "warn", + "no-process-exit": "warn", + "no-proto": "warn", + "no-prototype-builtins": "warn", + "no-redeclare": "warn", + "no-regex-spaces": "warn", + "no-restricted-globals": "warn", + "no-restricted-imports": "warn", + "no-restricted-modules": "warn", + "no-restricted-syntax": "warn", + "no-return-assign": "error", + "no-script-url": "warn", + "no-self-assign": "warn", + "no-self-compare": "warn", + "no-sequences": "warn", + "no-shadow-restricted-names": "warn", + "no-shadow": "warn", + "no-sparse-arrays": "warn", + "no-sync": "warn", + "no-this-before-super": "warn", + "no-throw-literal": "warn", + "no-undef-init": "warn", + "no-undef": "error", + "no-unmodified-loop-condition": "warn", + "no-unneeded-ternary": "error", + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unused-expressions": "error", + "no-unused-labels": "error", + "no-unused-vars": "error", + "no-use-before-define": "error", + "no-useless-call": "warn", + "no-useless-computed-key": "warn", + "no-useless-concat": "warn", + "no-useless-constructor": "warn", + "no-useless-escape": "warn", + "no-useless-rename": "warn", + "no-void": "warn", + "no-with": "warn", + "operator-assignment": ["error", "always"], + "prefer-const": "warn", + radix: "warn", + "require-yield": "warn", + "sort-imports": "warn", + "spaced-comment": ["error", "always"], + strict: ["error", "function"], + "use-isnan": "error", + + "valid-jsdoc": ["warn", { + prefer: { + arg: "param", + argument: "param", + augments: "extends", + constructor: "class", + exception: "throws", + func: "function", + method: "function", + prop: "property", + return: "returns", + virtual: "abstract", + yield: "yields", + }, + + preferType: { + array: "Array", + bool: "Boolean", + boolean: "Boolean", + number: "Number", + object: "Object", + str: "String", + string: "String", + }, + + requireParamDescription: false, + requireReturn: false, + requireReturnDescription: false, + requireReturnType: false, + }], + + "valid-typeof": "warn", + yoda: "warn", + }, +}, { + files: ["**/*.esm.js"], + + languageOptions: { + ecmaVersion: 5, + sourceType: "module", + }, +}]); diff --git a/itm/README.rst b/itm/README.rst new file mode 100644 index 0000000..e789184 --- /dev/null +++ b/itm/README.rst @@ -0,0 +1,87 @@ +============================ +IT Infrastructure Management +============================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0a7bb63fc33573b9c41dbb6cea29083cb6c798db09aa2ac3d89fb0cb675fb47a + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-trevi--software%2Ftrevi--misc-lightgray.png?logo=github + :target: https://github.com/trevi-software/trevi-misc/tree/18.0/itm + :alt: trevi-software/trevi-misc + +|badge1| |badge2| |badge3| + +This module is used to record information about a site's IT +infrastructure. You can record information about equipment, software, +backups, networks and access credentials. + +**Table of contents** + +.. contents:: + :local: + +Known issues / Roadmap +====================== + +- Manually set (or install) the python library 'cryptography' to version + 36.0.2. Because of Odoo Python requirements this module will **NOT** + work with versions of cryptography greater than 36.0.2. It will also + **NOT** work with the version in the Odoo requirements.txt file + (currently 3.4.8). +- The password for encrypting and decrypting credentials is stored in + Odoo as a system parameter. An attacker who has the + 'Administration/Settings' priviledge or has access to the Odoo + database itself can easily decrypt a credential's password field. +- To Do: store the encryption password in Odoo's configuration file + instead of a system parameter in the database + +Changelog +========= + +16.0.2.0.0 (2022-11-01) +----------------------- + +- [IMP] Use the new Odoo javascript framework OWL + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* TREVI Software +* Leandro Ezequiel Baldi + +Other credits +------------- + +- Leandro Ezequiel Baldi +- Altela Eleviansyah Pramardhika + +Maintainers +----------- + +This module is part of the `trevi-software/trevi-misc `_ project on GitHub. + +You are welcome to contribute. diff --git a/itm/__init__.py b/itm/__init__.py new file mode 100644 index 0000000..efc629a --- /dev/null +++ b/itm/__init__.py @@ -0,0 +1,7 @@ +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +# flake8: noqa +from . import models +from . import wizard diff --git a/itm/__manifest__.py b/itm/__manifest__.py new file mode 100644 index 0000000..c457f91 --- /dev/null +++ b/itm/__manifest__.py @@ -0,0 +1,69 @@ +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "IT Infrastructure Management", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "category": "IT Infrastructure Management", + "summary": """IT Assets, Credentials, Backups, Applications.""", + "author": """TREVI Software, + Leandro Ezequiel Baldi""", + "website": "https://github.com/trevi-software", + "images": [ + "static/src/img/main_screenshot.png", + "static/src/img/default_image_equipment.png", + ], + "depends": ["mail", "product", "web"], + "data": [ + "security/it_security.xml", + "security/ir.model.access.csv", + "data/migration.xml", + "data/application_license_data.xml", + "data/equipment_brand_data.xml", + "data/equipment_db_engine_data.xml", + "data/equipment_function.xml", + "data/equipment_mapping_data.xml", + "data/equipment_component_data.xml", + "data/equipment_component_cpu_data.xml", + "data/equipment_component_net_data.xml", + "data/equipment_component_ram_data.xml", + "data/equipment_component_storage_data.xml", + "data/equipment_type_data.xml", + "wizard/create_credential_view.xml", + "views/it_menu_view.xml", + "views/equipment_view.xml", + "views/equipment_worklog_view.xml", + "views/equipment_network_view.xml", + "views/equipment_partition_view.xml", + "views/equipment_component_view.xml", + "views/component_view.xml", + "views/access_view.xml", + "views/partner_view.xml", + "views/backup_view.xml", + "views/equipment_function_view.xml", + "views/equipment_mapping_view.xml", + "views/equipment_type_view.xml", + "views/application_view.xml", + "views/application_license_view.xml", + "views/brand_view.xml", + "views/site_view.xml", + "views/service_ad_view.xml", + "views/service_dhcp_view.xml", + "views/service_wireless_view.xml", + ], + "demo": [], + "test": [], + "assets": { + "web.assets_backend": [ + "/itm/static/src/js/itm_password_char_field.esm.js", + "/itm/static/src/js/itm_password_char_field.xml", + ], + }, + "external_dependencies": { + "python": ["cryptography"], + }, + "installable": True, + "application": True, +} diff --git a/itm/data/application_license_data.xml b/itm/data/application_license_data.xml new file mode 100644 index 0000000..b2a40a6 --- /dev/null +++ b/itm/data/application_license_data.xml @@ -0,0 +1,228 @@ + + + + + + + Academic Free License (AFL) + + + + AGPLv1 / Affero General Public License (version 1) + + + + AGPLv2 / Affero General Public License (version 2) + + + + Apache License + + + + Apple Public Source License (APSL) + + + + Artistic License 2.0 + + + + Berkeley Database License + + + + Boost Software License + + + + BDL / BSD Documentation License + + + + BSD license (original version) + + + + BSD 2-clause license + + + + CeCILL + + + + Common Public License + + + + Common Development and Distribution License (CDDL) + + + + Cryptix General License + + + + Eclipse Distribution License + + + + Eclipse Public License (EPL) + + + + EUPL - European Union Public License + + + + Free Solaris Binary License + + + + Free For non commercial Use + + + + AGPLv3 / GNU Affero General Public License (version 3) + + + + GPL / GNU General Public License + + + + GPLv3 / GNU General Public License v3 + + + + GNU LGPL / GNU Lesser General Public License + + + + IBM Public License + + + + Intel Open Source License + + + + ISC license + + + + LaTeX Project Public License (LPPL) + + + + License of Python + + + + MIT license + + + + Microsoft Reference License + + + + Microsoft Public License + + + + Microsoft Reciprocal License + + + + Microsoft's Shared Source + + + + Microsoft Windows' EULA + + + + Mozilla Public License (MPL) Version 1.1 + + + + Mozilla Public License (MPL) version 2.0 + + + + Netscape Public License (NPL) + + + + Open Software License + + + + OpenSSL license + + + + PHP License + + + + Public Domain + + + + Q Public License (QPL) + + + + Sun Industry Standards Source License (SISSL) + + + + Sun Public License + + + + W3C Software Notice and License + + + + WTFPL + + + + X11 license + + + + XFree86 1.1 License + + + + zlib/libpng license + + + + Zope Public License + + + diff --git a/itm/data/equipment_brand_data.xml b/itm/data/equipment_brand_data.xml new file mode 100644 index 0000000..84056aa --- /dev/null +++ b/itm/data/equipment_brand_data.xml @@ -0,0 +1,36 @@ + + + + + Dell + + + + + + HP + + + + + + Cisco + + + + + D-Link + + + + + TP-Link + + + + + Ubiquiti + + + + diff --git a/itm/data/equipment_component_cpu_data.xml b/itm/data/equipment_component_cpu_data.xml new file mode 100644 index 0000000..69564cb --- /dev/null +++ b/itm/data/equipment_component_cpu_data.xml @@ -0,0 +1,164 @@ + + + + + + Pentium + + + + Celeron + + + + Core 2 duo + + + + Core i3 + + + + Core i5 + + + + Core i7 + + + + Core i9 + + + + Zeon + + + + + + EPYC + + + + Opteron + + + + Ryzen 3 + + + + Ryzen 5 + + + + Ryzen 7 + + + + Ryzen 9 + + + + Ryzen Threadripper + + + + + + 1 + + + + 2 + + + + 4 + + + + 6 + + + + 8 + + + + 10 + + + + 12 + + + + 14 + + + + 16 + + + + 24 + + + + 32 + + + + 64 + + + + + + 2 + + + + 4 + + + + 8 + + + + 12 + + + + 16 + + + + 20 + + + + 24 + + + + 28 + + + + 32 + + + + 64 + + + + 128 + + + + diff --git a/itm/data/equipment_component_data.xml b/itm/data/equipment_component_data.xml new file mode 100644 index 0000000..6d7b1ae --- /dev/null +++ b/itm/data/equipment_component_data.xml @@ -0,0 +1,385 @@ + + + + + + Processor + + + Random Access Memory + + + Hard Disk Drive (HDD) + + + Solid State Drive (SSD) + + + Network Adapter + + + Wireless Adapter + + + Modem + + + Sound Card + + + Graphics Card + + + Video Capture/TV Tuner + + + SATA Controller + + + RAID Controller + + + Motherboard + + + Case + + + Power Supply Unit + + + Mobile Device Screen + + + Mobile Device Keyboard + + + Mobile Device Power Adapter + + + Mobile Device Battery + + + + + Intel CPU + + + AMD CPU + + + ARM CPU + + + CPU Cores + + + CPU Threads + + + RAM Speed + + + Storage Capacity + + + Storage Attachment + + + Storage Form Factor + + + Number + + + Network Speed + + + Wireless Device Class + + + Wireless Frequency + + + Bus Interface + + + Bus Interface Type + + + Chassis + + + Form Factor + + + Main Connector + + + Power + + + + + Intel CPU + + + + + AMD CPU + + + + + ARM CPU + + + + + Cores + + + + + Threads + + + + + RAM Speed + + + + + Storage Capacity + + + + + Attachement + + + + + Form Factor + + + + + RJ-45 Ports + + + + + Network Speed + + + + + Wireless Device Class + + + + + Wireless Frequency + + + + + Interface + + + + + Chassis Type + + + + + Form Factor + + + + + Main Connector + + + + + Maximum Power + + + + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + + + PCI + + + + PCI-X + + + + PCI Express (PCIe) + + + + Mini PCI Express + + + + Cardbus + + + + Mini Card + + + + + + Desktop + + + + Full Tower + + + + Mid Tower + + + + Mini Tower + + + + Micro ATX + + + + Mini ITX + + + + Rackmount + + + + + + ATX + + + + E-ATX + + + + Micro ATX + + + + ITX + + + + Mini-ITX + + + + 1U + + + + 2U + + + + + + 20pin + + + + 20+4pin + + + + 20+8pin + + + + 24pin + + + + diff --git a/itm/data/equipment_component_net_data.xml b/itm/data/equipment_component_net_data.xml new file mode 100644 index 0000000..16faadd --- /dev/null +++ b/itm/data/equipment_component_net_data.xml @@ -0,0 +1,146 @@ + + + + + + 2 Mbps + + + + + 10 Mbps + + + + + 11 Mbps + + + + + 54 Mbps + + + + + 100 Mbps + + + + 450 Mbps + + + + 866.7 Mbps + + + + 1000 Mbps + + + + 1.73 Gbps + + + + 2.4 Gbps + + + + 10 Gbps + + + + + + G54 + + + + N150 + + + + N300 + + + + N450 + + + + N600 + + + + N750 + + + + N900 + + + + AC580 + + + + AC750 + + + + AC1200 + + + + AC1300 + + + + AC1600 + + + + AC1750 + + + + AC1900 + + + + AC2350 + + + + AC2600 + + + + AC3100 + + + + AC3200 + + + + AC5300 + + + + + + 2.4 GHz + + + + 5 GHz + + + + 2.4 GHz / 5 GHz + + + + diff --git a/itm/data/equipment_component_ram_data.xml b/itm/data/equipment_component_ram_data.xml new file mode 100644 index 0000000..f583874 --- /dev/null +++ b/itm/data/equipment_component_ram_data.xml @@ -0,0 +1,138 @@ + + + + + + DDR3 1333 + + + + DDR3 1500 + + + + DDR3 1600 + + + + DDR3 1800 + + + + DDR3 2400 + + + + DDR3 2666 + + + + DDR4 2133 + + + + DDR4 2400 + + + + DDR4 2666 + + + + DDR4 2800 + + + + DDR4 2933 + + + + DDR4 3000 + + + + DDR4 3200 + + + + DDR4 3300 + + + + DDR4 3333 + + + + DDR4 3400 + + + + DDR4 3466 + + + + DDR4 3600 + + + + DDR4 3733 + + + + DDR4 3800 + + + + DDR4 3866 + + + + DDR4 4000 + + + + DDR4 4133 + + + + DDR4 4266 + + + + DDR4 4400 + + + + DDR4 4500 + + + + DDR4 4600 + + + + DDR4 4800 + + + + DDR4 5066 + + + + DDR4 5333 + + + + DDR5 4800 + + + + DDR5 5000 + + + + DDR5 5200 + + + + diff --git a/itm/data/equipment_component_storage_data.xml b/itm/data/equipment_component_storage_data.xml new file mode 100644 index 0000000..3664a27 --- /dev/null +++ b/itm/data/equipment_component_storage_data.xml @@ -0,0 +1,102 @@ + + + + + + 128 GB + + + + 256 GB + + + + 320 GB + + + + 512 GB + + + + 750 GB + + + + 1 TB + + + + 1.5 TB + + + + 2 TB + + + + 3 TB + + + + 4 TB + + + + + + Internal + + + + External + + + + Attached + + + + + + IDE + + + + SCSI + + + + SATA 1 + + + + SATA 2 + + + + SATA 3 + + + + Fibrechannel + + + + SAS 1 + + + + SAS 2 + + + + SAS 3 + + + + SAS 4 + + + + diff --git a/itm/data/equipment_db_engine_data.xml b/itm/data/equipment_db_engine_data.xml new file mode 100644 index 0000000..f9554bb --- /dev/null +++ b/itm/data/equipment_db_engine_data.xml @@ -0,0 +1,60 @@ + + + + + Cassandra + + + + Elasticsearch + + + + FileMaker + + + + IBM Db2 + + + + MariaDB + + + + Microsoft Access + + + + MS SQL Server + + + + MongoDB + + + + MySQL + + + + Oracle + + + + PostgreSQL + + + + Redis + + + + SAP HANA + + + + SQLite + + + diff --git a/itm/data/equipment_function.xml b/itm/data/equipment_function.xml new file mode 100644 index 0000000..f76bf21 --- /dev/null +++ b/itm/data/equipment_function.xml @@ -0,0 +1,80 @@ + + + + + Active Directory + + + + Domain Controller + + + + Domain Name Server + + + + File Server + + + + Database Server + + + + Firewall + + + + VPN Server + + + + DHCP Server + + + + FTP Server + + + + VPS + + + + VM Host + + + + VM Guest + + + + Switch + + + + Router + + + + Web Server + + + + Wireless AP + + + + Wireless Bridge + + + + Wireless Extender + + + + Wireless Client + + + diff --git a/itm/data/equipment_mapping_data.xml b/itm/data/equipment_mapping_data.xml new file mode 100644 index 0000000..cd3017f --- /dev/null +++ b/itm/data/equipment_mapping_data.xml @@ -0,0 +1,16 @@ + + + + + Full Control + + + + Change + + + + Read + + + diff --git a/itm/data/equipment_type_data.xml b/itm/data/equipment_type_data.xml new file mode 100644 index 0000000..be99159 --- /dev/null +++ b/itm/data/equipment_type_data.xml @@ -0,0 +1,137 @@ + + + + + + Physical + + + + Product + + + + + IT Assets + + + Non IT Assets + + + Virtual + + + + Components + + + + Keyboard + + + + Mouse + + + + Monitor + + + + Webcam + + + + Scanner + + + + Projector + + + + IP Phone + + + + Mobile Phone + + + + Copier + + + + Printer + + + + Software + + + + Application + + + + License + + + + Network Devices + + + + Router + + + + Switch + + + + Wireless Access Point + + + + Mobile Broadband Device + + + + Modem + + + + Network Antenna + + + + Network Attached Storage + + + + Print Server + + + + Computing Machine + + + + Server + + + + PC + + + + Laptop + + + + Tablet + + + + diff --git a/itm/data/migration.xml b/itm/data/migration.xml new file mode 100644 index 0000000..bd6420d --- /dev/null +++ b/itm/data/migration.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/itm/i18n/itm.pot b/itm/i18n/itm.pot new file mode 100644 index 0000000..a6baad6 --- /dev/null +++ b/itm/i18n/itm.pot @@ -0,0 +1,3229 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itm +# +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: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_object_form +msgid "    " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment.py:0 +#, python-format +msgid "" +"
" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#, python-format +msgid "" +"
" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/access.py:0 +#, python-format +msgid "" +"
" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#, python-format +msgid "" +"
" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_component.py:0 +#, python-format +msgid "" +"
" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/access.py:0 code:addons/itm/models/equipment.py:0 +#: code:addons/itm/models/equipment.py:0 +#: code:addons/itm/models/service_ad.py:0 +#, python-format +msgid "
  • %(dsc)s record was deleted: %(name)s
  • " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/access.py:0 code:addons/itm/models/service_ad.py:0 +#: code:addons/itm/models/service_ad.py:0 +#, python-format +msgid "
  • %(dsc)s was deleted: %(name)s
  • " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#, python-format +msgid "
  • %s(dsc) record was deleted: %(name)s
  • " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_component.py:0 +#, python-format +msgid "
  • A %(dsc)s record was deleted: %(name)s
  • " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_component.py:0 +#, python-format +msgid "
  • A %(dsc)s was installed: %(name)s
  • " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_component.py:0 +#, python-format +msgid "
  • A %(dsc)s was removed: %(name)s
  • " +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/access.py:0 code:addons/itm/models/access.py:0 +#, python-format +msgid "
  • A %(dsc)s's password was updated: %(name)s
  • " +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__developer +msgid "A company or person who create and develop this application" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__description +msgid "" +"A device description, eg. 'A basic scanner device for scanning paper into " +".pdf files' " +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__name +msgid "A device name, eg. Scanner" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_backup__partner_id +#: model:ir.model.fields,help:itm.field_itm_equipment__partner_id +msgid "A partner or user which are using this device" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__contract_owner +msgid "A person holding the title" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__site_id +msgid "A site or place of which this device is deployed" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__parent_id +msgid "AD Folder" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__type +msgid "AD Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__aduser_id +msgid "AD User" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__adobj_id +msgid "AD object name" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__encryption_type__aes +msgid "AES" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_rule__permission__allow +msgid "ALLOW" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +msgid "Access" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_res_partner__access_count +#: model:ir.model.fields,field_description:itm.field_res_users__access_count +msgid "Access Count" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__access_id +msgid "Access Credentials" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +msgid "Access Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless__type__ap +msgid "Access Point" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_needaction +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_needaction +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_needaction +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_needaction +#: model:ir.model.fields,field_description:itm.field_itm_site__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__active +#: model:ir.model.fields,field_description:itm.field_itm_application__active +#: model:ir.model.fields,field_description:itm.field_itm_backup__active +#: model:ir.model.fields,field_description:itm.field_itm_equipment__active +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__active +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__active +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__active +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__active +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__active +#: model:ir.model.fields,field_description:itm.field_itm_site__active +msgid "Active" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_service_ad_action +#: model:ir.model,name:itm.model_itm_service_ad +#: model:ir.model.fields,field_description:itm.field_itm_equipment__ad_service_id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__ad_id +#: model:ir.model.fields,field_description:itm.field_itm_site__ad_ids +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__ad_id +#: model:ir.ui.menu,name:itm.itm_ad_menu +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_form +msgid "Active Directory" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_service_ad_object +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_object_form +msgid "Active Directory Object" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_service_ad_object_action +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__obj_ids +#: model:ir.ui.menu,name:itm.itm_ad_object_menu +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_form +msgid "Active Directory Objects" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_search +msgid "Active Directory Search" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_ids +msgid "Activities" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_exception_decoration +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_exception_decoration +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_state +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_state +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_state +msgid "Activity State" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_type_icon +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_type_icon +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_mapping_permission_advanced +msgid "Advanced Share Mapping Permission" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_mapping.py:0 +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_mapping_line__type__advanced +#, python-format +msgid "Advanced Sharing" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__perm_advanced +msgid "Advanced permissions" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__application_ids +msgid "App information of this asset or device" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_application +#: model:ir.model.fields,field_description:itm.field_itm_equipment__is_application +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__application_id +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "Application" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "Application Name" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_application_action +#: model:ir.model.fields,field_description:itm.field_itm_equipment__application_ids +#: model:ir.ui.menu,name:itm.itm_application +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Applications" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_form +#: model_terms:ir.ui.view,arch_db:itm.component_search +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_type_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_type_search +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_form +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_object_form +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_search +#: model_terms:ir.ui.view,arch_db:itm.itm_site_form +#: model_terms:ir.ui.view,arch_db:itm.itm_site_search +#: model_terms:ir.ui.view,arch_db:itm.spec_value_form +#: model_terms:ir.ui.view,arch_db:itm.spec_value_search +msgid "Archived" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +msgid "Are you sure?" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_backup__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__equipment_id +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__equipment_id +#: model_terms:ir.ui.view,arch_db:itm.component_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Asset" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_component_specification +msgid "Asset Component Specification" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_component_type +msgid "Asset Component Type" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_equipment_type_action +#: model:ir.model,name:itm.model_itm_equipment_type +#: model:ir.ui.menu,name:itm.itm_equipment_type_menu +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Asset Type" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_type_search +msgid "Asset Type Search" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_worklog +msgid "Asset Worklog" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__asset_type_id +msgid "Asset type" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_partner_2_equipment +#: model:ir.actions.act_window,name:itm.act_site_2_equipment +#: model:ir.model.fields,field_description:itm.field_itm_application__equipment_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__equipment_count +#: model:ir.model.fields,field_description:itm.field_res_partner__equipment_ids +#: model:ir.model.fields,field_description:itm.field_res_users__equipment_ids +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Assets" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Assets with applications" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Assets with backup" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Assets with partitions" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Assets without applications" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Assets without backup" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_site__equipment_ids +msgid "Asset{s)" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_attachment_count +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_attachment_count +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_attachment_count +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_attachment_count +#: model:ir.model.fields,field_description:itm.field_itm_site__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Audit Data" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__auth_type +msgid "Authentication Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__auto +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__encryption_type__auto +msgid "Auto" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_forward__type__both +msgid "BOTH" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_partner_2_backup +#: model:ir.model,name:itm.model_itm_backup +#: model:ir.model.fields,field_description:itm.field_itm_equipment__is_backup +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_form +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "Backup" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__backup_count +#: model:ir.model.fields,field_description:itm.field_res_partner__backup_count +#: model:ir.model.fields,field_description:itm.field_res_users__backup_count +msgid "Backup Count" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "Backup Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__type +msgid "Backup Type" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_equipment_2_backup +#: model:ir.actions.act_window,name:itm.itm_backup_action +#: model:ir.model.fields,field_description:itm.field_itm_equipment__backup_ids +#: model:ir.model.fields,field_description:itm.field_res_partner__backup_ids +#: model:ir.model.fields,field_description:itm.field_res_users__backup_ids +#: model:ir.ui.menu,name:itm.itm_backup +msgid "Backups" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Basic Configuration" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__brand_id +msgid "Brand" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__brand +msgid "Brand Name" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_equipment_brand_action +#: model:ir.ui.menu,name:itm.itm_equipment_brand +msgid "Brands" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless__type__bridge +msgid "Bridge" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__product_buydate +msgid "Buy Date" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_application__license_type__closedsource +msgid "COMMERCIAL" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_csr +msgid "CSR" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_csr_filename +msgid "CSR Filename" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_wizard_credential_form +msgid "Cancel" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_cert +msgid "Cert" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_cert_filename +msgid "Cert Filename" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__cacn +msgid "Client Authorization by common name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__contract_client_number +msgid "Client Number" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +msgid "Closed Source" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "ClosedSource Applications" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__code +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Code" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__codification +msgid "Codification" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "Commercial" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__company_id +#: model:ir.model.fields,field_description:itm.field_itm_application__company_id +#: model:ir.model.fields,field_description:itm.field_itm_backup__company_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment__company_id +#: model:ir.model.fields,field_description:itm.field_itm_site__company_id +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +#: model_terms:ir.ui.view,arch_db:itm.itm_site_form +msgid "Company" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__complete_logon +msgid "Complete Logon" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__identification +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__complete_name +msgid "Complete Name" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_component +#: model_terms:ir.ui.view,arch_db:itm.component_form +msgid "Component" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__component_count +msgid "Component Count" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__is_components +msgid "Component Devices" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_search +msgid "Component Search" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.spec_selector_form +msgid "Component Selector" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_component_specification_key +msgid "Component Specification Key" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_component_specification_selector +msgid "Component Specification Selector" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_component_specification_value +msgid "Component Specification Value" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__component_type_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__component_type_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__component_type_ids +#: model_terms:ir.ui.view,arch_db:itm.component_search +#: model_terms:ir.ui.view,arch_db:itm.component_type_form +#: model_terms:ir.ui.view,arch_db:itm.spec_key_form +msgid "Component Type" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.component_type_action +#: model:ir.ui.menu,name:itm.component_type_menu +#: model_terms:ir.ui.view,arch_db:itm.spec_key_form +msgid "Component Types" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__equipment_id +#: model_terms:ir.ui.view,arch_db:itm.component_search +msgid "Component of" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_equipment_2_component +#: model:ir.actions.act_window,name:itm.component_action +#: model:ir.model.fields,field_description:itm.field_itm_equipment__component_ids +#: model:ir.ui.menu,name:itm.component_menu +#: model:ir.ui.menu,name:itm.itm_menu_component_config +msgid "Components" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__is_accessories +msgid "Computing Accessories" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__is_computer +msgid "Computing Devices" +msgstr "" + +#. module: itm +#: model:ir.ui.menu,name:itm.itm_menu_others +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Configuration" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__config_file +msgid "Configuration File" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__config_file_filename +msgid "Configuration File Filename" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__configuration_file_ids +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Configuration Files" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_res_partner +msgid "Contact" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Contract Information" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Contracted" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__is_contracted +msgid "Contracted Service" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__contract_partner_id +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Contractor" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__contract_partner_id +msgid "Contractor name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application_license__copy +msgid "Copy" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__crack +msgid "Crack" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_object_form +msgid "Create" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_adobject_2_newcreds +msgid "Create Credential" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.new_credential_wizard_action +msgid "Create New Credential" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_wizard_credential +msgid "Create New Credential Wizard" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_application__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_application_license__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_backup__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_site__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_site_network__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__create_uid +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__create_uid +msgid "Created by" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__create_date +#: model:ir.model.fields,field_description:itm.field_itm_application__create_date +#: model:ir.model.fields,field_description:itm.field_itm_application_license__create_date +#: model:ir.model.fields,field_description:itm.field_itm_backup__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__create_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__create_date +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__create_date +#: model:ir.model.fields,field_description:itm.field_itm_site__create_date +#: model:ir.model.fields,field_description:itm.field_itm_site_network__create_date +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__create_date +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__create_date +msgid "Created on" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_access +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +msgid "Credential" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_site__access_ids +msgid "Credential(s)" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_equipment_2_access +#: model:ir.actions.act_window,name:itm.act_partner_2_access +#: model:ir.actions.act_window,name:itm.act_site_2_access +#: model:ir.actions.act_window,name:itm.itm_access_action +#: model:ir.model.fields,field_description:itm.field_itm_equipment__access_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__access_count +#: model:ir.model.fields,field_description:itm.field_res_partner__access_ids +#: model:ir.model.fields,field_description:itm.field_res_users__access_ids +#: model:ir.ui.menu,name:itm.itm_access +msgid "Credentials" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__access_count +msgid "Credentials Count" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_partner_customer_action +#: model:ir.ui.menu,name:itm.itm_partner_customer +msgid "Customers" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_rule__permission__deny +msgid "DENY" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_service_dhcp4_action +#: model:ir.model.fields,field_description:itm.field_itm_equipment__dhcp_service_id +#: model:ir.model.fields,field_description:itm.field_itm_site_network__dhcp4_ids +#: model:ir.ui.menu,name:itm.itm_dhcp4_menu +msgid "DHCP" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__display_ipv4 +msgid "DHCP IPv4 Address" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_service_dhcp4 +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__dhcp_id +msgid "DHCP Service" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_dhcp4_form +#: model_terms:ir.ui.view,arch_db:itm.itm_site_network_form +msgid "DHCP Settings" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_backup__type__diff +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "DIFF" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__router_dmz +msgid "DMZ" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_site_network_form +msgid "DNS" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_site_network__dns_ids +msgid "DNS Servers" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_db +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__db_id +msgid "Database" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_db_engine +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__engine_id +msgid "Database Engine" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__function_database +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Database Server" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_dbsetting +msgid "Database Setting" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__db_ids +msgid "Database list" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__db_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment__db_ids +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Databases" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__date +msgid "Date" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_site_network__default_gw +msgid "Default Gateway" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_service_dhcp4__lease_time +msgid "Default lease time in seconds" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__function_ids +msgid "Defining the function of the devices, eg. scanning" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__description +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__description +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__description +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__name +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__description +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__name +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_worklog_form +msgid "Description" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__destination +msgid "Destination" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__destination_address +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__destination_address +msgid "Destination Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__destination_port +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__destination_port +msgid "Destination Port" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__developer +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "Developer" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_disk_amount +msgid "Disk Size" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment_partition__type +msgid "Disk storage controllers" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__disks +#: model:ir.model.fields,help:itm.field_itm_equipment_partition__disks +msgid "Disks" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__display_name +#: model:ir.model.fields,field_description:itm.field_itm_application__display_name +#: model:ir.model.fields,field_description:itm.field_itm_application_license__display_name +#: model:ir.model.fields,field_description:itm.field_itm_backup__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__display_name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__display_name +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__display_name +#: model:ir.model.fields,field_description:itm.field_itm_site__display_name +#: model:ir.model.fields,field_description:itm.field_itm_site_network__display_name +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__display_name +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__display_name +msgid "Display Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__documentation +msgid "Documentation" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__documentation_filename +msgid "Documentation Filename" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__documentation +msgid "Documentation sheet of technical use or standard operational procedure" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +msgid "Does not have a password" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__name +#: model:ir.model.fields,field_description:itm.field_itm_site_network__name +msgid "Domain" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__name_pre2000 +msgid "Domain (Pre-Windows 2000)" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__ad_service_id +msgid "Domain Active Directory that related to this asset" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__dhcp_service_id +msgid "Domain Host Control Protocol address which related to this asset" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__link_download +msgid "Download Link" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__link_download +msgid "Download link of the application" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__encryption_type +msgid "Encryption Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__end_address +msgid "End Address" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_partition_form +msgid "Enter a partition entry" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "Equipment" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_brand_form +msgid "Equipment Brand" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_configuration +msgid "Equipment Configuration" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_res_partner__equipment_count +#: model:ir.model.fields,field_description:itm.field_res_users__equipment_count +msgid "Equipment Count" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__image +msgid "Equipment Photo, limited to 1024x1024px." +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_type_form +msgid "Equipment Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless__type__extender +msgid "Extender" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_backup__type__full +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "FULL" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__function_fileserver +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "File Server" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__equipment_mapping_ids +msgid "File server information" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__path +#: model:ir.model.fields,help:itm.field_itm_equipment_mapping__path +msgid "Filesystem Path" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__router_rules_ids +msgid "Firewall Rules" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__first_name +msgid "First Name" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#: model:ir.model.fields.selection,name:itm.selection__itm_service_ad_object__type__folder +#, python-format +msgid "Folder" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__folder_name +msgid "Folder Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_follower_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_follower_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_follower_ids +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_follower_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_partner_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_partner_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_partner_ids +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_partner_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__activity_type_icon +#: model:ir.model.fields,help:itm.field_itm_equipment_component__activity_type_icon +#: model:ir.model.fields,help:itm.field_itm_site__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__format +msgid "Format" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__router_forward_ids +msgid "Forward Rules" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__frequency +msgid "Frequency" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__full_name +msgid "Full Name" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_function_form +msgid "Function" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Function Configuration" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_equipment_function_action +#: model:ir.model.fields,field_description:itm.field_itm_equipment__function_ids +#: model:ir.ui.menu,name:itm.itm_equipment_function +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Functions" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Functions..." +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +msgid "General Information" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +msgid "Generate" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#: model:ir.model.fields.selection,name:itm.selection__itm_service_ad_object__type__group +#, python-format +msgid "Group" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_search +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_search +#: model_terms:ir.ui.view,arch_db:itm.spec_value_search +msgid "Group By..." +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__group_name +msgid "Group Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_ids +msgid "Guest(s)" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.act_equipment_2_equipment +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_count +msgid "Guests" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__has_message +#: model:ir.model.fields,field_description:itm.field_itm_equipment__has_message +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__has_message +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__has_message +#: model:ir.model.fields,field_description:itm.field_itm_site__has_message +msgid "Has Message" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +msgid "Has Password" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__is_config_file +msgid "Has a configuration files" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +msgid "Has a password" +msgstr "" + +#. module: itm +#: model:ir.module.category,description:itm.module_category_it +msgid "Helps you manage your infrastructure equipment, access and backups." +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__worklog_ids +msgid "Historical progress of work that spent on the asset or device" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__function_host +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Host" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__id +#: model:ir.model.fields,field_description:itm.field_itm_application__id +#: model:ir.model.fields,field_description:itm.field_itm_application_license__id +#: model:ir.model.fields,field_description:itm.field_itm_backup__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__id +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__id +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__id +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__id +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__id +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__id +#: model:ir.model.fields,field_description:itm.field_itm_site__id +#: model:ir.model.fields,field_description:itm.field_itm_site_network__id +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__id +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__id +msgid "ID" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "INC" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_backup__type__inc +msgid "INCREMENTAL" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_site_network_form +msgid "IP Addresses" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_ipreservation +msgid "IP Reservation" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_dhcp4_form +msgid "IP Reservations" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__ip_address +msgid "IP address" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/site.py:0 +#, python-format +msgid "IP address '%s' already exists." +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__dhcp_ipv4_id +msgid "IPv4 Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__ip4_ids +#: model:ir.model.fields,field_description:itm.field_itm_site_network__ip4_ids +msgid "IPv4 Addresses" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__reservation_ids +msgid "IPv4 reservations" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment +msgid "IT Asset" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_brand +msgid "IT Asset Brand Name" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_equipment_action +#: model:ir.ui.menu,name:itm.itm_equipment +#: model:ir.ui.menu,name:itm.itm_menu_general +msgid "IT Assets" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_function +msgid "IT Function" +msgstr "" + +#. module: itm +#: model:ir.module.category,name:itm.module_category_it +msgid "IT Infrastructure Management" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_site_network_form +msgid "IT Network" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_site +#: model_terms:ir.ui.view,arch_db:itm.itm_site_form +msgid "IT Site" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_exception_icon +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_exception_icon +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__activity_exception_icon +#: model:ir.model.fields,help:itm.field_itm_equipment_component__activity_exception_icon +#: model:ir.model.fields,help:itm.field_itm_site__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__name +msgid "Identificator" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment_partition__name +msgid "Identificator or flag for ease identification" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_access__message_needaction +#: model:ir.model.fields,help:itm.field_itm_equipment__message_needaction +#: model:ir.model.fields,help:itm.field_itm_equipment_component__message_needaction +#: model:ir.model.fields,help:itm.field_itm_service_ad__message_needaction +#: model:ir.model.fields,help:itm.field_itm_site__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_access__message_has_error +#: model:ir.model.fields,help:itm.field_itm_equipment__message_has_error +#: model:ir.model.fields,help:itm.field_itm_equipment_component__message_has_error +#: model:ir.model.fields,help:itm.field_itm_service_ad__message_has_error +#: model:ir.model.fields,help:itm.field_itm_site__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_service_wireless_ssid__is_guest +msgid "If checked, this is a Guest SSID" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment__state__in_repair +msgid "In repair" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment__state__in_store +msgid "In store" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment__state__in_use +msgid "In use" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_form +msgid "Information" +msgstr "" + +#. module: itm +#: model:ir.ui.menu,name:itm.menu_main_itm +msgid "Infrastructure" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +msgid "Installations" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__name +msgid "Interface Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__contract_direction +#: model:ir.model.fields,help:itm.field_itm_equipment__contract_direction +msgid "Invoice Direction" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_is_follower +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_is_follower +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_is_follower +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_is_follower +#: model:ir.model.fields,field_description:itm.field_itm_site__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__is_guest +msgid "Is Guest" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__key +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__key_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__key_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__key_ids +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__passkey +msgid "Key" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_type_form +msgid "Key Form" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__keygen +msgid "Keygen" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access____last_update +#: model:ir.model.fields,field_description:itm.field_itm_application____last_update +#: model:ir.model.fields,field_description:itm.field_itm_application_license____last_update +#: model:ir.model.fields,field_description:itm.field_itm_backup____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type____last_update +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_ad____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless____last_update +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid____last_update +#: model:ir.model.fields,field_description:itm.field_itm_site____last_update +#: model:ir.model.fields,field_description:itm.field_itm_site_network____last_update +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4____last_update +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential____last_update +msgid "Last Modified on" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__last_name +msgid "Last Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_application__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_application_license__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_backup__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_site__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_site_network__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__write_uid +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__write_date +#: model:ir.model.fields,field_description:itm.field_itm_application__write_date +#: model:ir.model.fields,field_description:itm.field_itm_application_license__write_date +#: model:ir.model.fields,field_description:itm.field_itm_backup__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_configuration__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__write_date +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__write_date +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__write_date +#: model:ir.model.fields,field_description:itm.field_itm_site__write_date +#: model:ir.model.fields,field_description:itm.field_itm_site_network__write_date +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__write_date +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__write_date +msgid "Last Updated on" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__lease_time +msgid "Lease Time" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_application_license +#: model:ir.model.fields,field_description:itm.field_itm_application__license_id +#: model_terms:ir.ui.view,arch_db:itm.itm_application_license_form +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "License" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__license_type +msgid "License Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__license_type +msgid "License name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__license_id +msgid "License type" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_application_license_action +#: model:ir.ui.menu,name:itm.itm_application_license +msgid "Licenses" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__link_page +msgid "Link" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +msgid "Links and Docs" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment__state__loaned +msgid "Loaned" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__location +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Location" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__description +msgid "Long Description" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__mac +msgid "MAC Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_ipreservation__mac_address +msgid "Mac Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_main_attachment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_main_attachment_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_main_attachment_id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_main_attachment_id +#: model:ir.model.fields,field_description:itm.field_itm_site__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_res_partner__manage_it +#: model:ir.model.fields,field_description:itm.field_res_users__manage_it +#: model_terms:ir.ui.view,arch_db:itm.itm_partner_filter +msgid "Manage IT" +msgstr "" + +#. module: itm +#: model:res.groups,name:itm.group_itm_manager +msgid "Manager" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__manufacturer_id +#: model_terms:ir.ui.view,arch_db:itm.component_search +msgid "Manufacturer" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__map_id +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_mapping_form +msgid "Mapping" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__active +msgid "Mark if this app is currently used and running" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_memory_amount +msgid "Memory" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_has_error +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_has_error +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_has_error +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_has_error +#: model:ir.model.fields,field_description:itm.field_itm_site__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_ids +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__message_ids +msgid "Messages" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__model +msgid "Model" +msgstr "" + +#. module: itm +#: model:res.groups,name:itm.group_itm_mod +msgid "Moderator" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__mount_ids +msgid "Mount on this partition" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment_partition__mount_ids +msgid "Mount partition" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__my_activity_date_deadline +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__my_activity_date_deadline +#: model:ir.model.fields,field_description:itm.field_itm_site__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__contract_nif +msgid "NIF" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__none +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__encryption_type__none +msgid "NONE" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__name +#: model:ir.model.fields,field_description:itm.field_itm_application_license__name +#: model:ir.model.fields,field_description:itm.field_itm_backup__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_type__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db_engine__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_function__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__name +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__name +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__name +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__name +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__name +#: model:ir.model.fields,field_description:itm.field_itm_site__name +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__name +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__name +#: model_terms:ir.ui.view,arch_db:itm.component_search +#: model_terms:ir.ui.view,arch_db:itm.spec_value_search +msgid "Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__name +msgid "Name of the application" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_site_network__netmask +msgid "Netmask" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_site_network +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__network_id +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__network_id +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__network_id +#: model:ir.model.fields,field_description:itm.field_itm_site_network_ip4__network_id +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_network_form +#: model_terms:ir.ui.view,arch_db:itm.itm_site_network_form +msgid "Network" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Network Asset" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Network Configuration" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_brand__is_network +msgid "Network Devices" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_site_network_ip4 +msgid "Network IPv4 Address" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_network +msgid "Network Interface" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_network_proxy +msgid "Network Proxy Configuration" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_service_proxy +msgid "Network Proxy Service" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_mapping +msgid "Network Share Mapping" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_mapping_line +msgid "Network Share Mapping Line" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__equipment_mapping_ids +msgid "Network Shares" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__equipment_network_ids +msgid "Network on this equipment" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__equipment_network_ids +msgid "Network setup that configured within this asset or device" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_network_action +#: model:ir.model.fields,field_description:itm.field_itm_site__network_ids +#: model:ir.ui.menu,name:itm.itm_network_menu +#: model_terms:ir.ui.view,arch_db:itm.itm_site_form +msgid "Networks" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_wizard_credential_form +msgid "New Credential" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_date_deadline +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_date_deadline +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_summary +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_summary +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_type_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_type_id +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +msgid "No Password" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__note +#: model:ir.model.fields,field_description:itm.field_itm_backup__note +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__note +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__note +msgid "Note" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__note +msgid "Note for this application eg" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_needaction_counter +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_needaction_counter +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_needaction_counter +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_needaction_counter +#: model:ir.model.fields,field_description:itm.field_itm_site__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_network_amount +msgid "Number of Network" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_processor_amount +msgid "Number of Processor" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__message_has_error_counter +#: model:ir.model.fields,field_description:itm.field_itm_equipment__message_has_error_counter +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__message_has_error_counter +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__message_has_error_counter +#: model:ir.model.fields,field_description:itm.field_itm_site__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_access__message_needaction_counter +#: model:ir.model.fields,help:itm.field_itm_equipment__message_needaction_counter +#: model:ir.model.fields,help:itm.field_itm_equipment_component__message_needaction_counter +#: model:ir.model.fields,help:itm.field_itm_service_ad__message_needaction_counter +#: model:ir.model.fields,help:itm.field_itm_site__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_access__message_has_error_counter +#: model:ir.model.fields,help:itm.field_itm_equipment__message_has_error_counter +#: model:ir.model.fields,help:itm.field_itm_equipment_component__message_has_error_counter +#: model:ir.model.fields,help:itm.field_itm_service_ad__message_has_error_counter +#: model:ir.model.fields,help:itm.field_itm_site__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_application__license_type__opensource +msgid "OPEN SOURCE" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__os_name +msgid "OS Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_backup__type__other +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +msgid "OTHER" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__type +msgid "Object Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_application__link_page +msgid "Official website link of the application" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "OpenSource" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +msgid "OpenSource Applications" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__is_os +msgid "Operating System" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__os_name +msgid "Operating system which is installed on device, eg. Windows 10, Ubuntu" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__code +msgid "Organization specific inventory code" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__other +msgid "Other" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Own" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__owner +msgid "Owner" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_ad__type__primary +msgid "PRIMARY" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__name +msgid "Parameter" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__parent_id +msgid "Parent" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_type__parent_path +msgid "Parent Path" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_partition +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__partition_id +msgid "Partition" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Partition Information" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_partition_mount +msgid "Partition Mounts" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment_partition__format +msgid "Partition format type" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__partitions_ids +msgid "Partition on this equipment" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Partitioned" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__is_partitioned +msgid "Partitions" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__partitions_ids +msgid "Partitions on this equipment" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__partner_id +#: model:ir.model.fields,field_description:itm.field_itm_backup__partner_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment__partner_id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__partner_id +#: model:ir.model.fields,field_description:itm.field_itm_site__partner_id +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__partner_id +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_search +msgid "Partner" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__password +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__password +msgid "Password" +msgstr "" + +#. module: itm +#. odoo-javascript +#: code:addons/itm/static/src/js/itm_password_char_field.esm.js:0 +#, python-format +msgid "Password copied to clipboard" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__permission +msgid "Permission" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_mapping_form +msgid "Permission Lines" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__line_ids +msgid "Permission lines" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment_mapping__line_ids +msgid "Permission setup" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__image +msgid "Photo" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Physical Asset" +msgstr "" + +#. module: itm +#: model:res.groups,name:itm.group_itm_portal +msgid "Portal" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__possible_key_ids +msgid "Possible Key" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_privatekey +msgid "Private Key" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_privatekey_filename +msgid "Private Key Filename" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__product_id +msgid "Product" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Product Data" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__product_note +msgid "Product Note" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_component_action +#: model:ir.ui.menu,name:itm.itm_component +msgid "Products" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__adblocking +msgid "Proxy Ad Blocking" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__cache_size +msgid "Proxy Cache File Size" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__proxy_client_config_id +msgid "Proxy Configuration" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__enable_ssk +msgid "Proxy Enable Single Sign-On (Kerberos)" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network_proxy__name +msgid "Proxy Hostname" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__port +msgid "Proxy Port" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__proxy_service_id +msgid "Proxy Service" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_publickey +msgid "Public Key" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__ssl_publickey_filename +msgid "Public Key Filename" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_partition_form +msgid "RAID1" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__use_random +msgid "Random password" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_mapping.py:0 +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_mapping_line__perm_simple__read +#, python-format +msgid "Read" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_mapping.py:0 +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_mapping_line__perm_simple__write +#, python-format +msgid "Read/Write" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__gateway +msgid "Redirect Gateway" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__access_id +msgid "Related Credential" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__activity_user_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__activity_user_id +#: model:ir.model.fields,field_description:itm.field_itm_site__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment__state__retired +msgid "Retired" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__function_router +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Router" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Router Configuration" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_forward +msgid "Router Forwarding Rule" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_equipment_rule +msgid "Router Rule" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__router_rules_ids +msgid "Router's firewall rules" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__router_forward_ids +msgid "Router's forward rules" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_ad__type__secundary +msgid "SECONDARY" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_ad__type__slave +msgid "SLAVE" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__bssid_ids +msgid "SSI" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__name +msgid "SSID" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_wireless_form +msgid "SSID List" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_access_form +msgid "SSL" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__script +msgid "Script" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__script_filename +msgid "Script Filename" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__script_location +msgid "Script Location" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__product_serial_number +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__serial_number +msgid "Serial Number" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Service Information" +msgstr "" + +#. module: itm +#: model:ir.ui.menu,name:itm.itm_menu_services +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Services" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_db__setting_ids +msgid "Settings" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping__name +msgid "Share Name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_permission_advanced__line_id +msgid "Share mapping" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment_mapping_line__name +msgid "Sharing partition or folder name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__name +msgid "Short Description" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_mapping.py:0 +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_mapping_line__type__simple +#, python-format +msgid "Simple Sharing" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__perm_simple +msgid "Simple permissions" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__site_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment__site_id +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__site_id +#: model:ir.model.fields,field_description:itm.field_itm_site_network__site_id +#: model:ir.model.fields,field_description:itm.field_itm_wizard_credential__site_id +#: model_terms:ir.ui.view,arch_db:itm.itm_access_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +#: model_terms:ir.ui.view,arch_db:itm.itm_service_ad_search +msgid "Site" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_site_search +msgid "Site Search" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_site_action +#: model:ir.ui.menu,name:itm.itm_menu_sites +#: model:ir.ui.menu,name:itm.itm_site_menu +msgid "Sites" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition_mount__size +msgid "Size" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Software Asset" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__source +msgid "Source" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__source_address +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__source_address +msgid "Source Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__source_port +#: model:ir.model.fields,field_description:itm.field_itm_equipment_rule__source_port +msgid "Source Port" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__spec_line_ids +msgid "Spec Line" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_form +#: model_terms:ir.ui.view,arch_db:itm.specification_form +msgid "Specification" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.spec_key_action +#: model:ir.ui.menu,name:itm.spec_key_menu +msgid "Specification Keys" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.spec_value_search +msgid "Specification Selector" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.spec_selector_action +#: model:ir.ui.menu,name:itm.spec_selector_menu +msgid "Specification Selectors" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.spec_value_form +msgid "Specification Value" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.spec_value_search +msgid "Specification Value Search" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.spec_value_action +#: model:ir.ui.menu,name:itm.spec_value_menu +msgid "Specification Values" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_form +msgid "Specifications" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__spent_time +msgid "Spent Time" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__start_address +msgid "Start Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__state +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "State" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__static_ipv4_id +msgid "Static IPv4 Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__activity_state +#: model:ir.model.fields,help:itm.field_itm_equipment_component__activity_state +#: model:ir.model.fields,help:itm.field_itm_site__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__is_config_file +msgid "Store Config Files" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_wizard_credential_form +msgid "Submit" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__subnet +#: model:ir.model.fields,field_description:itm.field_itm_site_network__subnet +msgid "Subnet" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_dhcp4__subnet_mask +msgid "Subnet Mask" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_forward__type__tcp +#: model:ir.model.fields.selection,name:itm.selection__itm_service_vpn__protocol__tcp +msgid "TCP" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__encryption_type__tkip +msgid "TKIP" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__brand +msgid "The assets or device brand" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__contract_client_number +msgid "The client number of the contractor" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__contract_nif +msgid "The tax number for natural and legal person" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_component.py:0 +#, python-format +msgid "" +"The value you entered must be unique within its Value Type.\n" +"Previous record: Value Type: %(vname)s, Name: %(name)s" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__function_wireless +msgid "This asset acts as a wireless access point or router" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__is_backup +msgid "This asset or device is a backup" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__function_database +msgid "This asset or device is a database server" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__function_fileserver +msgid "This asset or device is a fileserver" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__function_host +msgid "This asset or device is a host" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__function_router +msgid "This asset or device is a network router" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__is_application +msgid "This asset or device is an application" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__is_contracted +msgid "This asset or device is contracted from other company" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__is_partitioned +msgid "This device is partitioned" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_backup__time_schedule +msgid "Time Schedule" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__contract_owner +msgid "Titular" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_proxy__transparent +msgid "Transparent Proxy" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_forward__type +#: model:ir.model.fields,field_description:itm.field_itm_equipment_mapping_line__type +#: model:ir.model.fields,field_description:itm.field_itm_equipment_partition__type +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless__type +#: model_terms:ir.ui.view,arch_db:itm.itm_application_search +#: model_terms:ir.ui.view,arch_db:itm.itm_backup_search +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Type" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__activity_exception_decoration +#: model:ir.model.fields,help:itm.field_itm_equipment_component__activity_exception_decoration +#: model:ir.model.fields,help:itm.field_itm_site__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_equipment_forward__type__udp +#: model:ir.model.fields.selection,name:itm.selection__itm_service_vpn__protocol__udp +msgid "UDP" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/equipment_mapping.py:0 +#, python-format +msgid "Unknown" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_network__use_dhcp4 +msgid "Use IPv4 DHCP" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__use_proxy +msgid "Use Proxy" +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#: model:ir.model.fields,field_description:itm.field_itm_equipment_worklog__user_id +#: model:ir.model.fields.selection,name:itm.selection__itm_service_ad_object__type__user +#: model:res.groups,name:itm.group_itm_user +#, python-format +msgid "User" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_ad_object__logon_name +msgid "User logon name" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__name +msgid "Username" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__address +msgid "VPN Address" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__c2c +msgid "VPN Allow Client to Client connections" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__nat +msgid "VPN Network Address Traslation" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__protocol +msgid "VPN Protocol" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__search_domain +msgid "VPN Search Domain" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__server_cert +msgid "VPN Server Certificate" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_service_vpn +#: model:ir.model.fields,field_description:itm.field_itm_equipment__vpn_service_id +msgid "VPN Service" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__tun +msgid "VPN Tun Interface" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_vpn__wins_server +msgid "VPN WINS Server" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.component_type_form +#: model_terms:ir.ui.view,arch_db:itm.spec_selector_form +msgid "Valid Keys" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.spec_selector_form +msgid "Valid Values" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__value_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_selector__value_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_dbsetting__value +msgid "Value" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification__value_type_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_key__value_type_id +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component_specification_value__value_type_id +msgid "Value Type" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Virtual Asset" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__virtual_parent_id +msgid "Virtual Machine" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +msgid "Virtual Machine Data" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__wep128 +msgid "WEP-128bits" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__wep64 +msgid "WEP-64bits" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__wpa_ent +msgid "WPA Enterprise" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__wpa +msgid "WPA Personal (Pre-shared key)" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__wpa2_ent +msgid "WPA2 Enterprise" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless_ssid__auth_type__wpa2 +msgid "WPA2 Personal (Pre-shared key)" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__product_warranty +msgid "Warranty" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_application__is_webapp +msgid "Web Application" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_access__website_message_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment__website_message_ids +#: model:ir.model.fields,field_description:itm.field_itm_equipment_component__website_message_ids +#: model:ir.model.fields,field_description:itm.field_itm_service_ad__website_message_ids +#: model:ir.model.fields,field_description:itm.field_itm_site__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_access__website_message_ids +#: model:ir.model.fields,help:itm.field_itm_equipment__website_message_ids +#: model:ir.model.fields,help:itm.field_itm_equipment_component__website_message_ids +#: model:ir.model.fields,help:itm.field_itm_service_ad__website_message_ids +#: model:ir.model.fields,help:itm.field_itm_site__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: itm +#: model:ir.actions.act_window,name:itm.itm_service_wireless_action +#: model:ir.ui.menu,name:itm.itm_wireless_menu +msgid "Wireless" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__function_wireless +msgid "Wireless Access Device" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_service_wireless_ssid +msgid "Wireless Base Station ID" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Wireless Device" +msgstr "" + +#. module: itm +#: model:ir.model.fields.selection,name:itm.selection__itm_service_wireless__type__router_wireless +msgid "Wireless Router" +msgstr "" + +#. module: itm +#: model:ir.model,name:itm.model_itm_service_wireless +#: model:ir.model.fields,field_description:itm.field_itm_equipment__wireless_service_id +msgid "Wireless Service" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_service_wireless_form +msgid "Wireless Settings" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_service_wireless_ssid__wireless_id +msgid "Wireless service" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "With Applications" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "With Backup" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Without Applications" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_search +msgid "Without Backup" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_worklog_form +msgid "Worklog" +msgstr "" + +#. module: itm +#: model:ir.model.fields,field_description:itm.field_itm_equipment__worklog_ids +msgid "Worklogs on this equipment" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_application_form +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_network_form +msgid "Write a note ..." +msgstr "" + +#. module: itm +#. odoo-python +#: code:addons/itm/models/service_ad.py:0 +#, python-format +msgid "You cannot create recursive Active Directory objects." +msgstr "" + +#. module: itm +#: model:ir.model.fields,help:itm.field_itm_equipment__configuration_file_ids +msgid "configuration file of this asset or device" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_network_form +msgid "eth0" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_equipment_partition_form +msgid "ext4" +msgstr "" + +#. module: itm +#: model_terms:ir.ui.view,arch_db:itm.itm_wizard_credential_form +msgid "or" +msgstr "" diff --git a/itm/models/__init__.py b/itm/models/__init__.py new file mode 100644 index 0000000..b5b8519 --- /dev/null +++ b/itm/models/__init__.py @@ -0,0 +1,30 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +# flake8: noqa +from . import access +from . import application +from . import application_license +from . import backup +from . import equipment +from . import equipment_component +from . import equipment_configuration +from . import equipment_db +from . import equipment_dbsetting +from . import equipment_forward +from . import equipment_function +from . import equipment_ipreservation +from . import equipment_mapping +from . import equipment_network +from . import equipment_partition +from . import equipment_rule +from . import equipment_type +from . import equipment_worklog +from . import partner +from . import service_ad +from . import service_dhcp +from . import service_proxy +from . import service_vpn +from . import service_wireless +from . import site diff --git a/itm/models/access.py b/itm/models/access.py new file mode 100644 index 0000000..78241f0 --- /dev/null +++ b/itm/models/access.py @@ -0,0 +1,280 @@ +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +import base64 +import os +from random import choice + +from cryptography.fernet import Fernet +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC + +from odoo import api, fields, models + +PARAM_PASS = "itm_passkey" +PARAM_SALT = "itm_salt" + + +class ItAccess(models.Model): + _name = "itm.access" + _inherit = ["mail.thread"] + _description = "Credential" + + @api.onchange("equipment_id") + def onchange_equipment(self): + if self.equipment_id: + self.partner_id = self.equipment_id.partner_id + else: + self.partner_id = None + + @api.model + def get_random_string(self): + longitud = 16 + valores = ( + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<=>@#%&+" + ) + p = "" + p = p.join([choice(valores) for i in range(longitud)]) + return p + + def get_random_password(self): + for access in self: + access.password = self.get_random_string() + + def get_urlsafe_key(self): + ConfigParam = self.env["ir.config_parameter"] + salt = None + passphrase = ConfigParam.sudo().get_param(PARAM_PASS) + if not passphrase: + passphrase = base64.urlsafe_b64encode(os.urandom(64)).decode() + salt = os.urandom(16) + ConfigParam.sudo().set_param(PARAM_PASS, passphrase) + ConfigParam.sudo().set_param( + PARAM_SALT, base64.urlsafe_b64encode(salt).decode() + ) + else: + salt = base64.urlsafe_b64decode( + ConfigParam.sudo().get_param(PARAM_SALT).encode() + ) + + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256, + length=32, + salt=salt, + iterations=100000, + ) + return base64.urlsafe_b64encode(kdf.derive(passphrase.encode())) + + @api.model + def encrypt_string(self, plaintext): + """Returns a URL-safe string containing the encrypted version of plaintext.""" + + key = self.get_urlsafe_key() + f = Fernet(key) + cipher = f.encrypt(plaintext.encode()) + return base64.urlsafe_b64encode(cipher) + + @api.model + def decrypt_password_as_string(self, obj_id): + """Returns a string representing the plaintext password in record with + database ID obj_id. Returns empty string if the password is not set.""" + + key = self.get_urlsafe_key() + f = Fernet(key) + + plaintext = "" + rec = self.browse(obj_id) + if rec and rec.password: + token = base64.urlsafe_b64decode(rec.password) + plaintext = f.decrypt(token).decode() + return plaintext + + @api.model + def _get_partner_id(self): + # Get the partner from either asset or site + # + if self.env.context.get("active_model") == "itm.equipment": + equip = self.env["itm.equipment"].browse(self.env.context.get("id")) + if equip.partner_id: + return equip.partner_id.id + elif self.env.context.get("active_model") == "itm.site": + site = self.env["itm.site"].browse(self.env.context.get("id")) + if site.partner_id: + return site.partner_id.id + return False + + @api.model + def _get_site_id(self): + if self.env.context.get("active_model") == "itm.equipment": + equip = self.env["itm.equipment"].browse(self.env.context.get("id")) + if equip.site_id: + return equip.site_id.id + return False + + company_id = fields.Many2one( + "res.company", + "Company", + default=lambda self: self.env.company, + ) + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="restrict") + site_id = fields.Many2one( + "itm.site", "Site", required=True, ondelete="restrict", default=_get_site_id + ) + name = fields.Char("Username", required=True, tracking=True) + password = fields.Char() + partner_id = fields.Many2one( + "res.partner", + "Partner", + domain="[('manage_it','=',1)]", + default=_get_partner_id, + tracking=True, + ) + active = fields.Boolean(default=True, tracking=True) + ssl_csr = fields.Binary("CSR", tracking=True) + ssl_csr_filename = fields.Char("CSR Filename") + ssl_cert = fields.Binary("Cert", tracking=True) + ssl_cert_filename = fields.Char("Cert Filename") + ssl_publickey = fields.Binary("Public Key", tracking=True) + ssl_publickey_filename = fields.Char("Public Key Filename") + ssl_privatekey = fields.Binary("Private Key", tracking=True) + ssl_privatekey_filename = fields.Char("Private Key Filename") + + def write(self, vals): + # Log a note to Site and Equipment chatter. + # Map access records to sites and equipment. + # + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + sites = {} + equips = {} + for res in self: + if res.site_id: + if res.site_id.id not in sites.keys(): + sites.update({res.site_id.id: [{"id": res.id, "name": res.name}]}) + else: + sites[res.site_id.id].append({"id": res.id, "name": res.name}) + if res.equipment_id: + if res.equipment_id.id not in equips.keys(): + equips.update( + {res.equipment_id.id: [{"id": res.id, "name": res.name}]} + ) + else: + equips[res.equipment_id.id].append({"id": res.id, "name": res.name}) + + Site = self.env["itm.site"] + for k, v in sites.items(): + msg = "" + for r in v: + msg = msg + self.env._( + "
  • A %(dsc)s's password was updated: %(name)s
  • " + ) % { + "dsc": self._description, + "name": r["name"], + } + note = '
      ' + msg + "
    " + Site.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + Equipment = self.env["itm.equipment"] + for k, v in equips.items(): + msg = "" + for r in v: + msg = msg + self.env._( + "
  • A %(dsc)s's password was updated: %(name)s
  • " + ) % { + "dsc": self._description, + "name": r["name"], + } + note = '
      ' + msg + "
    " + Equipment.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + # Encrypt the password before saving it. The unencrypted password should not be + # saved to the database even temporarily. + # + if "password" in vals.keys() and vals["password"] is not False: + vals["password"] = self.encrypt_string(vals["password"]) + + return super().write(vals) + + @api.model_create_multi + def create(self, lst): + for item in lst: + # Encrypt the password before saving it. The unencrypted password should + # not be saved to the database even temporarily. + # + if "password" in item.keys() and item["password"] is not False: + item["password"] = self.encrypt_string(item["password"]) + + res = super().create(lst) + + for r in res: + # Log a note to Site and Equipment chatter. + # + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + msg = self.env._( + '
    ' + ) % {"dsc": r._description, "id": r.id, "name": r.name} + if r.site_id: + r.site_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + if r.equipment_id: + r.equipment_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + + return res + + def update_chatter(self, model, lst): + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + + res_model = self.env[model] + for k, v in lst: + msg = "" + for r in v: + msg = msg + self.env._("
  • %(dsc)s was deleted: %(name)s
  • ") % { + "dsc": self._description, + "name": r["name"], + } + note = '
      ' + msg + "
    " + res_model.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + # Log a note on deletion of credential to Site and Equipment chatter. Since + # more than one record at a time may be deleted post all deleted records + # for each site and each equipment together in one post. + # + def unlink(self): + # map access records to sites and equipment + # + sites = {} + equips = {} + for res in self: + if res.site_id: + if res.site_id.id not in sites.keys(): + sites.update({res.site_id.id: [{"id": res.id, "name": res.name}]}) + else: + sites[res.site_id.id].append({"id": res.id, "name": res.name}) + if res.equipment_id: + if res.equipment_id.id not in equips.keys(): + equips.update( + {res.equipment_id.id: [{"id": res.id, "name": res.name}]} + ) + else: + equips[res.equipment_id.id].append({"id": res.id, "name": res.name}) + + self.update_chatter("itm.site", sites.items()) + self.update_chatter("itm.equipment", equips.items()) + + return super().unlink() diff --git a/itm/models/application.py b/itm/models/application.py new file mode 100644 index 0000000..c4f576e --- /dev/null +++ b/itm/models/application.py @@ -0,0 +1,71 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItApplication(models.Model): + _name = "itm.application" + _description = "Application" + + name = fields.Char(required=True, help="Name of the application") + is_webapp = fields.Boolean("Web Application") + company_id = fields.Many2one( + "res.company", + "Company", + default=lambda self: self.env.company, + ) + active = fields.Boolean( + default=True, help="Mark if this app is currently used and running" + ) + developer = fields.Char( + help="A company or person who create and develop this application" + ) + link_download = fields.Char( + "Download Link", help="Download link of the application" + ) + link_page = fields.Char("Link", help="Official website link of the application") + license_id = fields.Many2one( + "itm.application.license", "License", help="License type" + ) + license_type = fields.Selection( + [("opensource", "OPEN SOURCE"), ("closedsource", "COMMERCIAL")], + required=True, + default="opensource", + help="License name", + ) + documentation = fields.Binary( + help="Documentation sheet of technical use or standard operational procedure" + ) + documentation_filename = fields.Char() + note = fields.Text(help="Note for this application eg") + equipment_ids = fields.Many2many( + "itm.equipment", + "equipment_application_rel", + "application_id", + "equipment_id", + "Assets", + ) + db_ids = fields.One2many("itm.equipment.db", "application_id", "Databases") + # Closed Source + key = fields.Char() + keygen = fields.Binary() + crack = fields.Binary() diff --git a/itm/models/application_license.py b/itm/models/application_license.py new file mode 100644 index 0000000..7f16369 --- /dev/null +++ b/itm/models/application_license.py @@ -0,0 +1,30 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItApplicationLicense(models.Model): + _name = "itm.application.license" + _description = "License" + + name = fields.Char(required=True) + copy = fields.Text() diff --git a/itm/models/backup.py b/itm/models/backup.py new file mode 100644 index 0000000..a1ef94d --- /dev/null +++ b/itm/models/backup.py @@ -0,0 +1,68 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItBackup(models.Model): + _name = "itm.backup" + _description = "Backup" + + equipment_id = fields.Many2one( + comodel_name="itm.equipment", + string="Asset", + domain="[('is_backup','=',1)]", + ondelete="restrict", + required=True, + ) + partner_id = fields.Many2one( + comodel_name="res.partner", + related="equipment_id.partner_id", + readonly=True, + string="Partner", + store=True, + ) + name = fields.Char(required=True) + type = fields.Selection( + [ + ("diff", "DIFF"), + ("full", "FULL"), + ("inc", "INCREMENTAL"), + ("other", "OTHER"), + ], + "Backup Type", + required=True, + default="full", + ) + destination = fields.Char() + source = fields.Char() + script = fields.Binary() + script_filename = fields.Char() + script_location = fields.Char() + frequency = fields.Char() + time_schedule = fields.Float() + note = fields.Text() + company_id = fields.Many2one( + "res.company", + "Company", + default=lambda self: self.env.company, + ) + active = fields.Boolean(default=True) diff --git a/itm/models/equipment.py b/itm/models/equipment.py new file mode 100644 index 0000000..3084969 --- /dev/null +++ b/itm/models/equipment.py @@ -0,0 +1,477 @@ +############################################################################## +# +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +import base64 + +from odoo import api, fields, models +from odoo.tools.misc import file_path + + +class ItEquipmentBrand(models.Model): + _name = "itm.equipment.brand" + _description = "IT Asset Brand Name" + + name = fields.Char(required=True) + is_computer = fields.Boolean("Computing Devices") + is_network = fields.Boolean("Network Devices") + is_accessories = fields.Boolean("Computing Accessories") + is_components = fields.Boolean("Component Devices") + + +class ItEquipment(models.Model): + _name = "itm.equipment" + _inherit = ["mail.activity.mixin", "mail.thread"] + _description = "IT Asset" + + @api.depends("virtual_ids") + def _compute_virtual_count(self): + for equipment in self: + equipment.virtual_count = len(equipment.virtual_ids) + + @api.depends("access_ids") + def _compute_access_count(self): + for equipment in self: + equipment.access_count = len(equipment.access_ids) + + @api.depends("backup_ids") + def _compute_backup_count(self): + for equipment in self: + equipment.backup_count = len(equipment.backup_ids) + + @api.depends("component_ids") + def _compute_component_count(self): + for equipment in self: + equipment.component_count = len(equipment.component_ids) + + @api.model + def _get_default_image(self): + image_path = file_path("itm/static/src/img/default_image_equipment.png") + return base64.b64encode(open(image_path, "rb").read()) + + @api.model + def _get_partner_id(self): + # Get the partner from either asset or site + # + if self.env.context.get("active_model") == "itm.equipment": + equip = self.env["itm.equipment"].browse(self.env.context.get("id")) + if equip.partner_id: + return equip.partner_id.id + elif self.env.context.get("active_model") == "itm.site": + site = self.env["itm.site"].browse(self.env.context.get("id")) + if site.partner_id: + return site.partner_id.id + return False + + @api.model + def _get_site_id(self): + if self.env.context.get("active_model") == "itm.equipment": + equip = self.env["itm.equipment"].browse(self.env.context.get("id")) + if equip.site_id: + return equip.site_id.id + return False + + @api.model + def _get_type(self): + # work-arround for upgrading a module + if not self.env.ref("itm.type_bundle", False): + return False + if self.env.context.get("search_default_type_virtual"): + return self.env.ref("itm.type_virtual").id + elif self.env.context.get("search_default_type_network"): + return self.env.ref("itm.type_network").id + elif self.env.context.get("search_default_type_software"): + return self.env.ref("itm.type_software").id + return self.env.ref("itm.type_bundle").id + + # For openerp structure + company_id = fields.Many2one( + "res.company", + "Company", + default=lambda self: self.env.company, + ) + site_id = fields.Many2one( + "itm.site", + "Site", + required=True, + tracking=True, + default=_get_site_id, + help="A site or place of which this device is deployed", + ) + + brand = fields.Many2one( + "itm.equipment.brand", "Brand Name", help="The assets or device brand" + ) + + active = fields.Boolean(default=True, tracking=True) + # Counts + access_count = fields.Integer( + compute="_compute_access_count", string="Credentials Count", store=False + ) + access_ids = fields.One2many("itm.access", "equipment_id", string="Credentials") + backup_count = fields.Integer(compute="_compute_backup_count") + backup_ids = fields.One2many("itm.backup", "equipment_id", "Backups") + virtual_count = fields.Integer( + compute="_compute_virtual_count", string="Guests", store=False + ) + virtual_ids = fields.One2many("itm.equipment", "virtual_parent_id", "Guest(s)") + # General Info + identification = fields.Char( + compute="_compute_identification", string="Complete Name", store=True + ) + name = fields.Char( + required=True, + tracking=True, + index=True, + help="A device name, eg. Scanner", + ) + code = fields.Char( + tracking=True, index=True, help="Organization specific inventory code" + ) + brand_id = fields.Many2one("itm.equipment.brand", "Brand") + model = fields.Char() + partner_id = fields.Many2one( + "res.partner", + "Partner", + required=True, + domain="[('manage_it','=',1)]", + tracking=True, + default=_get_partner_id, + help="A partner or user which are using this device", + ) + function_ids = fields.Many2many( + "itm.equipment.function", + "equipment_function_rel", + "equipment_id", + "function_id", + "Functions", + help="Defining the function of the devices, eg. scanning", + ) + description = fields.Char( + required=False, + help="A device description, eg. 'A basic scanner device for " + "scanning paper into .pdf files' ", + ) + image = fields.Binary( + "Photo", + default=_get_default_image, + help="Equipment Photo, limited to 1024x1024px.", + ) + asset_type_id = fields.Many2one( + "itm.equipment.type", "Asset type", default=_get_type + ) + owner = fields.Char() + location = fields.Char() + state = fields.Selection( + selection=[ + ("in_store", "In store"), + ("in_use", "In use"), + ("loaned", "Loaned"), + ("in_repair", "In repair"), + ("retired", "Retired"), + ], + default="in_store", + tracking=True, + index=True, + ) + ip4_ids = fields.Many2many( + "itm.site.network.ip4", + string="IPv4 Addresses", + readonly=True, + compute="_compute_ip4_ids", + ) + + # Applications Page + application_ids = fields.Many2many( + "itm.application", + "equipment_application_rel", + "equipment_id", + "application_id", + "Applications", + help="App information of this asset or device", + ) + + # Config Page + is_contracted = fields.Boolean( + "Contracted Service", + help="This asset or device is contracted from other company", + ) + is_partitioned = fields.Boolean("Partitions", help="This device is partitioned") + is_backup = fields.Boolean("Backup", help="This asset or device is a backup") + is_os = fields.Boolean("Operating System") + is_application = fields.Boolean( + "Application", help="This asset or device is an application" + ) + is_config_file = fields.Boolean( + "Store Config Files", help="Has a configuration files" + ) + # Config Page - Functions + function_fileserver = fields.Boolean( + "File Server", help="This asset or device is a fileserver" + ) + function_host = fields.Boolean("Host", help="This asset or device is a host") + function_router = fields.Boolean( + "Router", help="This asset or device is a network router" + ) + function_database = fields.Boolean( + "Database Server", help="This asset or device is a database server" + ) + function_wireless = fields.Boolean( + "Wireless Access Device", + help="This asset acts as a wireless access point or router", + ) + # Worklogs Page + worklog_ids = fields.One2many( + "itm.equipment.worklog", + "equipment_id", + "Worklogs on this equipment", + tracking=True, + help="Historical progress of work that spent on the asset or device", + ) + # Contract Page + contract_partner_id = fields.Many2one( + "res.partner", "Contractor", help="Contractor name" + ) + contract_client_number = fields.Char( + "Client Number", help="The client number of the contractor" + ) + contract_owner = fields.Char("Titular", help="A person holding the title") + contract_nif = fields.Char( + "NIF", help="The tax number for natural and legal person" + ) + contract_direction = fields.Char("Invoice Direction", help="Invoice Direction") + # Virtual Machine Page + virtual_parent_id = fields.Many2one( + "itm.equipment", "Virtual Machine", domain="[('function_host','=',1)]" + ) + virtual_memory_amount = fields.Char("Memory") + virtual_disk_amount = fields.Char("Disk Size") + virtual_processor_amount = fields.Char("Number of Processor") + virtual_network_amount = fields.Char("Number of Network") + # Partition Page + partitions_ids = fields.One2many( + "itm.equipment.partition", + "equipment_id", + "Partitions on this equipment", + help="Partition on this equipment", + ) + # Router Page + router_dmz = fields.Char("DMZ") + router_forward_ids = fields.One2many( + "itm.equipment.forward", + "equipment_id", + "Forward Rules", + tracking=True, + help="Router's forward rules", + ) + router_rules_ids = fields.One2many( + "itm.equipment.rule", + "equipment_id", + "Firewall Rules", + tracking=True, + help="Router's firewall rules", + ) + # Network Configuration + equipment_network_ids = fields.One2many( + "itm.equipment.network", + "equipment_id", + "Network on this equipment", + tracking=True, + help="Network setup that configured within this asset or device", + ) + # Product Page + product_id = fields.Many2one("product.product", "Product") + product_serial_number = fields.Char("Serial Number") + product_warranty = fields.Char("Warranty") + product_buydate = fields.Date("Buy Date") + product_note = fields.Text() + # Fileserver Page + equipment_mapping_ids = fields.One2many( + "itm.equipment.mapping", + "equipment_id", + "Network Shares", + tracking=True, + help="File server information", + ) + # OS Page + os_name = fields.Char( + "OS Name", + help="Operating system which is installed on device, eg. Windows 10, Ubuntu", + ) + # Services + ad_service_id = fields.Many2one( + "itm.service.ad", + "Active Directory", + help="Domain Active Directory that related to this asset", + ) + dhcp_service_id = fields.Many2one( + "itm.service.dhcp4", + "DHCP", + help="Domain Host Control Protocol address which related to this asset", + ) + wireless_service_id = fields.Many2one("itm.service.wireless", "Wireless Service") + proxy_service_id = fields.Many2one("itm.service.proxy", "Proxy Service") + vpn_service_id = fields.Many2one("itm.service.vpn", "VPN Service") + # Database Page + db_ids = fields.One2many( + "itm.equipment.db", "equipment_id", "Databases", help="Database list" + ) + use_proxy = fields.Boolean() + proxy_client_config_id = fields.Many2one( + "itm.equipment.network.proxy", "Proxy Configuration" + ) + # Store Config File Page + configuration_file_ids = fields.One2many( + "itm.equipment.configuration", + "equipment_id", + "Configuration Files", + help="configuration file of this asset or device", + ) + # Components + component_count = fields.Integer(compute=_compute_component_count) + component_ids = fields.One2many( + "itm.equipment.component", "equipment_id", "Components" + ) + + @api.depends( + "equipment_network_ids", + "equipment_network_ids.static_ipv4_id", + "equipment_network_ids.dhcp_ipv4_id", + ) + def _compute_ip4_ids(self): + for equip in self: + ifs = self.env["itm.site.network.ip4"] + for net in equip.equipment_network_ids: + if net.static_ipv4_id: + ifs |= net.static_ipv4_id + if net.dhcp_ipv4_id: + ifs |= net.dhcp_ipv4_id + equip.ip4_ids = ifs + + # Log a note on creation of equipment to Site and Equipment chatter. + # + @api.model_create_multi + def create(self, lst): + res = super().create(lst) + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + for r in res: + msg = self.env._( + '
    ' + ) % { + "desc": r._description, + "id": r.id, + "name": r.name, + } + if r.site_id: + r.site_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + if r.virtual_parent_id: + r.virtual_parent_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + return res + + def update_chatter(self, model, verb, lst): + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + res_model = self.env[model] + for k, v in lst: + msg = "" + for r in v: + msg = msg + self.env._( + "
  • %(dsc)s record was %(verb)s: %(name)s
  • " + ) % { + "dsc": self._description, + "name": r["name"], + "verb": verb, + } + note = '
      ' + msg + "
    " + res_model.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + # Log a note on deletion of credential to Site and Equipment chatter. Since + # more than one record at a time may be deleted post all deleted records + # for each site and each equipment together in one post. + # + def unlink(self): + # map access records to sites and equipment + # + sites = {} + equips = {} + for res in self: + if res.site_id: + if res.site_id.id not in sites.keys(): + sites.update({res.site_id.id: [{"id": res.id, "name": res.name}]}) + else: + sites[res.site_id.id].append({"id": res.id, "name": res.name}) + if res.virtual_parent_id: + if res.virtual_parent_id.id not in equips.keys(): + equips.update( + {res.virtual_parent_id.id: [{"id": res.id, "name": res.name}]} + ) + else: + equips[res.virtual_parent_id.id].append( + {"id": res.id, "name": res.name} + ) + + self.update_chatter("itm.site", "deleted", sites.items()) + self.update_chatter("itm.equipment", "deleted", equips.items()) + + return super().unlink() + + def add_ip4_network_interface( + self, name, network, mac, static_ip, dhcp_ip, use_dhcp, note=False + ): + # If an IPv4 address does not exist, create it + ip_obj = self.env["itm.site.network.ip4"] + static_ip4 = ip_obj.search( + [ + ("name", "=", static_ip), + ("network_id", "=", network.id), + ] + ) + if static_ip and not static_ip4: + static_ip4 = ip_obj.create({"name": static_ip, "network_id": network.id}) + dhcp_ip4 = ip_obj.search( + [ + ("name", "=", dhcp_ip), + ("network_id", "=", network.id), + ] + ) + if dhcp_ip and not dhcp_ip4: + dhcp_ip4 = ip_obj.create({"name": dhcp_ip, "network_id": network.id}) + return self.env["itm.equipment.network"].create( + { + "equipment_id": self.id, + "name": name, + "mac": mac, + "network_id": network.id, + "note": note, + "use_dhcp4": use_dhcp, + "static_ipv4_id": static_ip4.id, + "dhcp_ipv4_id": dhcp_ip4.id, + } + ) diff --git a/itm/models/equipment_component.py b/itm/models/equipment_component.py new file mode 100644 index 0000000..69d129e --- /dev/null +++ b/itm/models/equipment_component.py @@ -0,0 +1,297 @@ +############################################################################## +# +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class EquipmentComponent(models.Model): + _name = "itm.equipment.component" + _inherit = ["mail.activity.mixin", "mail.thread"] + _description = "Component" + + name = fields.Char(required=True) + equipment_id = fields.Many2one( + "itm.equipment", + "Component of", + required=True, + tracking=True, + ondelete="restrict", + ) + component_type_id = fields.Many2one("itm.equipment.component.type", required=True) + serial_number = fields.Char() + manufacturer_id = fields.Many2one("itm.equipment.brand") + note = fields.Text() + active = fields.Boolean(default=True) + spec_line_ids = fields.Many2many( + "itm.equipment.component.specification", + "itm_equipment_component_specification_rel", + domain="[('component_type_id', '=', component_type_id)]", + ) + + def write(self, vals): + # If the equipment is being changed log a note to Equipment chatter + # that a compnent was removed. Log a note to the new equipment that + # a component was added. + # + + new_eq_id = vals.get("equipment_id", False) + if not new_eq_id: + return super().write(vals) + + new_equip = {new_eq_id: []} + old_equips = {} + for res in self: + new_equip[new_eq_id].append({"id": res.id, "name": res.name}) + if res.equipment_id: + if res.equipment_id.id not in old_equips.keys(): + old_equips.update( + {res.equipment_id.id: [{"id": res.id, "name": res.name}]} + ) + else: + old_equips[res.equipment_id.id].append( + {"id": res.id, "name": res.name} + ) + + # Log removal from old + self.update_chatter("itm.equipment", old_equips.items(), "removed") + + # Log installation in new + self.update_chatter("itm.equipment", new_equip.items(), "installed") + + return super().write(vals) + + def update_chatter(self, model, lst, verb): + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + res_model = self.env[model] + + for k, v in lst.items(): + msg = "" + for r in v: + msg = msg + self.env._( + "
  • A %(dsc)s record was %(verb)s: %(name)s
  • " + ) % { + "dsc": self._description, + "name": r["name"], + "verb": verb, + } + note = '
      ' + msg + "
    " + res_model.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + @api.model_create_multi + def create(self, lst): + res = super().create(lst) + + # Log a note to Site and Equipment chatter. + # + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + for r in res: + msg = self.env._( + '
    ' + ) % { + "dsc": r._description, + "id": r.id, + "name": r.name, + } + if r.equipment_id: + r.equipment_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + + return res + + # Log a note on deletion of a component to Equipment chatter. Since + # more than one record at a time may be deleted post all deleted records + # for each equipment together in one post. + # + def unlink(self): + # map access records to equipment + # + equips = {} + for res in self: + if res.equipment_id: + if res.equipment_id.id not in equips.keys(): + equips.update( + {res.equipment_id.id: [{"id": res.id, "name": res.name}]} + ) + else: + equips[res.equipment_id.id].append({"id": res.id, "name": res.name}) + + self.update_chatter("itm.equipment", equips) + + return super().unlink() + + +class ComponentType(models.Model): + _name = "itm.equipment.component.type" + _description = "Asset Component Type" + + name = fields.Char(required=True) + key_ids = fields.Many2many( + "itm.equipment.component.specification.key", + "itm_equipment_component_type_key_rel", + ) + + +class ComponentSpecification(models.Model): + _name = "itm.equipment.component.specification" + _description = "Asset Component Specification" + + component_type_id = fields.Many2one( + "itm.equipment.component.type", compute="_compute_component_type", store=True + ) + possible_key_ids = fields.One2many( + "itm.equipment.component.specification.key", + compute="_compute_possible_keys", + ) + key_id = fields.Many2one( + "itm.equipment.component.specification.key", + domain="[('id', 'in', possible_key_ids)]", + required=True, + ) + value_id = fields.Many2one( + "itm.equipment.component.specification.value", + domain="[ \ + '|', \ + ('value_type_id', '=', False), \ + ('value_type_id', '=', value_type_id) \ + ]", + ) + value_type_id = fields.Many2one( + "itm.equipment.component.specification.selector", + related="key_id.value_type_id", + store=True, + ) + + def _compute_component_type(self): + default_ctype_id = self.env.context.get("default_component_type_id") + for res in self: + if default_ctype_id: + res.component_type_id = default_ctype_id + + @api.depends("component_type_id") + def _compute_possible_keys(self): + for res in self: + res.possible_key_ids = res.component_type_id.key_ids + + +class SpecificationKey(models.Model): + _name = "itm.equipment.component.specification.key" + _description = "Component Specification Key" + + name = fields.Char(required=True) + component_type_ids = fields.Many2many( + "itm.equipment.component.type", + "itm_equipment_component_type_key_rel", + ) + value_type_id = fields.Many2one( + "itm.equipment.component.specification.selector", required=True + ) + + @api.model_create_multi + def create(self, dicts): + res = super().create(dicts) + + default_ctype_id = self.env.context.get("default_component_type_id") + if default_ctype_id: + for r in res: + ctype = self.env["itm.equipment.component.type"].browse( + default_ctype_id + ) + if r.id not in ctype.key_ids.ids: + ctype.key_ids += r + + return res + + +class SpecificationValueType(models.Model): + """ + This class is a convenient place to group values around. Instead of linking a + key to all possible values we link it to a value type and then all possible + values for the key are linked to this type. This also has the added bonus + that values (via key type) can be re-used in multiple keys without duplications. + """ + + _name = "itm.equipment.component.specification.selector" + _description = "Component Specification Selector" + + name = fields.Char(required=True) + key_ids = fields.One2many( + "itm.equipment.component.specification.key", + "value_type_id", + ) + value_ids = fields.One2many( + "itm.equipment.component.specification.key", + "value_type_id", + ) + + +class SpecificationValue(models.Model): + _name = "itm.equipment.component.specification.value" + _description = "Component Specification Value" + + name = fields.Char(required=True) + value_type_id = fields.Many2one("itm.equipment.component.specification.selector") + active = fields.Boolean(default=True) + + @api.constrains("name", "value_type_id") + def _check_name_unique(self): + for rec in self: + domain = [ + ("name", "=ilike", rec.name), + ("value_type_id", "=", rec.value_type_id.id), + ("id", "!=", rec.id), + ] + count = self.search_count(domain) + if count > 0: + ids = self.search(domain) + raise ValidationError( + self.env._( + "The value you entered must be unique within its Value Type.\n" + "Previous record: Value Type: %(vname)s, Name: %(name)s" + ) + % { + "vname": ids[0].value_type_id.name, + "name": ids[0].name, + } + ) + + @api.model_create_multi + def create(self, lst): + # When a new value is created from the specification list of the component + # we need to setup the linkage between value and key type otherwise + # the new value will show as a possible value for *ALL* keys. + # + default_sel_id = self.env.context.get("default_value_type_id") + if default_sel_id: + for item in lst: + if "value_type_id" not in item: + item.update({"value_type_id": default_sel_id}) + + return super().create(lst) diff --git a/itm/models/equipment_configuration.py b/itm/models/equipment_configuration.py new file mode 100644 index 0000000..ae686f7 --- /dev/null +++ b/itm/models/equipment_configuration.py @@ -0,0 +1,35 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentConfiguration(models.Model): + _name = "itm.equipment.configuration" + _description = "Equipment Configuration" + + _order = "date desc" + + name = fields.Char("Description", required=True) + date = fields.Datetime(default=fields.Datetime.now()) + config_file = fields.Binary("Configuration File") + config_file_filename = fields.Char("Configuration File Filename") + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="restrict") diff --git a/itm/models/equipment_db.py b/itm/models/equipment_db.py new file mode 100644 index 0000000..006dbbc --- /dev/null +++ b/itm/models/equipment_db.py @@ -0,0 +1,42 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentDb(models.Model): + _name = "itm.equipment.db" + _description = "Database" + + name = fields.Char(required=True) + codification = fields.Char() + description = fields.Text() + setting_ids = fields.One2many("itm.equipment.dbsetting", "db_id", "Settings") + engine_id = fields.Many2one("itm.equipment.db.engine", "Database Engine") + application_id = fields.Many2one("itm.application", "Application") + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="restrict") + + +class ItEquipmentDbEngine(models.Model): + _name = "itm.equipment.db.engine" + _description = "Database Engine" + + name = fields.Char(required=True) diff --git a/itm/models/equipment_dbsetting.py b/itm/models/equipment_dbsetting.py new file mode 100644 index 0000000..dfba39e --- /dev/null +++ b/itm/models/equipment_dbsetting.py @@ -0,0 +1,32 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentDbsetting(models.Model): + _name = "itm.equipment.dbsetting" + _description = "Database Setting" + + name = fields.Char("Parameter", required=True) + value = fields.Char(required=True) + description = fields.Text() + db_id = fields.Many2one("itm.equipment.dbsetting", "Database", ondelete="cascade") diff --git a/itm/models/equipment_forward.py b/itm/models/equipment_forward.py new file mode 100644 index 0000000..8a720af --- /dev/null +++ b/itm/models/equipment_forward.py @@ -0,0 +1,38 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentForward(models.Model): + _name = "itm.equipment.forward" + _description = "Router Forwarding Rule" + + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="cascade") + name = fields.Char(required=True) + source_port = fields.Char() + destination_port = fields.Char() + source_address = fields.Char() + destination_address = fields.Char() + type = fields.Selection( + [("tcp", "TCP"), ("udp", "UDP"), ("both", "BOTH")], + default="both", + ) diff --git a/itm/models/equipment_function.py b/itm/models/equipment_function.py new file mode 100644 index 0000000..ec2d50a --- /dev/null +++ b/itm/models/equipment_function.py @@ -0,0 +1,28 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from odoo import fields, models + + +class ItEquipmentFunction(models.Model): + _name = "itm.equipment.function" + _description = "IT Function" + + name = fields.Char(required=True) diff --git a/itm/models/equipment_ipreservation.py b/itm/models/equipment_ipreservation.py new file mode 100644 index 0000000..12f7b2f --- /dev/null +++ b/itm/models/equipment_ipreservation.py @@ -0,0 +1,32 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentIpreservation(models.Model): + _name = "itm.equipment.ipreservation" + _description = "IP Reservation" + + name = fields.Char(required=True, string="Description") + mac_address = fields.Char(required=True) + ip_address = fields.Many2one("itm.site.network.ip4", "IP address", required=True) + dhcp_id = fields.Many2one("itm.service.dhcp4", "DHCP Service", ondelete="cascade") diff --git a/itm/models/equipment_mapping.py b/itm/models/equipment_mapping.py new file mode 100644 index 0000000..42d45e4 --- /dev/null +++ b/itm/models/equipment_mapping.py @@ -0,0 +1,67 @@ +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class ItEquipmentMapping(models.Model): + _name = "itm.equipment.mapping" + _description = "Network Share Mapping" + + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="cascade") + name = fields.Char("Share Name", required=True) + path = fields.Char("Filesystem Path", required=True, help="Filesystem Path") + line_ids = fields.One2many( + "itm.equipment.mapping.line", + "map_id", + "Permission lines", + help="Permission setup", + ) + + +class ItEquipmentMappingLine(models.Model): + _name = "itm.equipment.mapping.line" + _description = "Network Share Mapping Line" + + def _compute_name(self): + for rec in self: + _name = self.env._("Unknown") + if rec.adobj_id: + _name = rec.adobj_id.name + rec.name = _name + + map_id = fields.Many2one("itm.equipment.mapping", "Mapping") + name = fields.Char( + compute="_compute_name", + store=True, + help="Sharing partition or folder name", + ) + adobj_id = fields.Many2one( + comodel_name="itm.service.ad.object", string="AD object name" + ) + type = fields.Selection( + [ + ("simple", "Simple Sharing"), + ("advanced", "Advanced Sharing"), + ] + ) + perm_simple = fields.Selection( + [ + ("read", "Read"), + ("write", "Read/Write"), + ], + string="Simple permissions", + ) + perm_advanced = fields.One2many( + "itm.equipment.mapping.permission.advanced", "line_id", "Advanced permissions" + ) + + +class ItMappingAdvancedPermissions(models.Model): + _name = "itm.equipment.mapping.permission.advanced" + _description = "Advanced Share Mapping Permission" + + name = fields.Char() + line_id = fields.Many2one("itm.equipment.mapping.line", "Share mapping") diff --git a/itm/models/equipment_network.py b/itm/models/equipment_network.py new file mode 100644 index 0000000..b050a28 --- /dev/null +++ b/itm/models/equipment_network.py @@ -0,0 +1,55 @@ +############################################################################## +# +# Copyright (C) 2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import api, fields, models + + +class ItEquipmentNetwork(models.Model): + _name = "itm.equipment.network" + _description = "Network Interface" + + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="cascade") + name = fields.Char("Interface Name", required=True) + mac = fields.Char("MAC Address", required=True) + network_id = fields.Many2one("itm.site.network", "Network") + static_ipv4_id = fields.Many2one("itm.site.network.ip4", "Static IPv4 Address") + dhcp_ipv4_id = fields.Many2one("itm.site.network.ip4", "IPv4 Address") + display_ipv4 = fields.Char( + "DHCP IPv4 Address", compute="_compute_display_ipv4_address" + ) + use_dhcp4 = fields.Boolean("Use IPv4 DHCP", default=True) + note = fields.Text() + + @api.depends("use_dhcp4", "static_ipv4_id") + def _compute_display_ipv4_address(self): + for net in self: + if net.use_dhcp4: + net.display_ipv4 = net.dhcp_ipv4_id.name + else: + net.display_ipv4 = net.static_ipv4_id.name + + +class ItEquipmentNetworkProxy(models.Model): + _name = "itm.equipment.network.proxy" + _description = "Network Proxy Configuration" + + name = fields.Char("Proxy Hostname", required=True) diff --git a/itm/models/equipment_partition.py b/itm/models/equipment_partition.py new file mode 100644 index 0000000..8081c1b --- /dev/null +++ b/itm/models/equipment_partition.py @@ -0,0 +1,54 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentPartition(models.Model): + _name = "itm.equipment.partition" + _description = "Partition" + + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="cascade") + name = fields.Char( + "Identificator", + required=True, + help="Identificator or flag for ease identification", + ) + disks = fields.Char(help="Disks") + type = fields.Char(help="Disk storage controllers") + format = fields.Char(help="Partition format type") + mount_ids = fields.One2many( + "itm.equipment.partition.mount", + "partition_id", + "Mount on this partition", + help="Mount partition", + ) + + +class ItEquipmentPartitionMount(models.Model): + _name = "itm.equipment.partition.mount" + _description = "Partition Mounts" + + partition_id = fields.Many2one( + "itm.equipment.partition", "Partition", ondelete="cascade" + ) + name = fields.Char(required=True) + size = fields.Char() diff --git a/itm/models/equipment_rule.py b/itm/models/equipment_rule.py new file mode 100644 index 0000000..56cf184 --- /dev/null +++ b/itm/models/equipment_rule.py @@ -0,0 +1,38 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentRule(models.Model): + _name = "itm.equipment.rule" + _description = "Router Rule" + + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="cascade") + name = fields.Char(required=True) + source_port = fields.Char() + destination_port = fields.Char() + source_address = fields.Char() + destination_address = fields.Char() + permission = fields.Selection( + [("allow", "ALLOW"), ("deny", "DENY")], + default="allow", + ) diff --git a/itm/models/equipment_type.py b/itm/models/equipment_type.py new file mode 100644 index 0000000..88e3fad --- /dev/null +++ b/itm/models/equipment_type.py @@ -0,0 +1,15 @@ +# Copyright (C) 2022 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ItEquipmentType(models.Model): + _name = "itm.equipment.type" + _description = "Asset Type" + _parent_store = True + + name = fields.Char(required=True) + parent_id = fields.Many2one("itm.equipment.type", "Parent") + parent_path = fields.Char(index=True) + active = fields.Boolean(default=True) diff --git a/itm/models/equipment_worklog.py b/itm/models/equipment_worklog.py new file mode 100644 index 0000000..cc81c66 --- /dev/null +++ b/itm/models/equipment_worklog.py @@ -0,0 +1,38 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItEquipmentWorklog(models.Model): + _name = "itm.equipment.worklog" + _description = "Asset Worklog" + + _order = "date desc" + + name = fields.Char("Short Description", required=True) + description = fields.Text("Long Description") + date = fields.Datetime(default=fields.Datetime.now()) + spent_time = fields.Float() + equipment_id = fields.Many2one("itm.equipment", "Asset", ondelete="cascade") + user_id = fields.Many2one( + "res.users", "User", required=True, default=lambda self: self.env.user.id + ) diff --git a/itm/models/partner.py b/itm/models/partner.py new file mode 100644 index 0000000..5d453ec --- /dev/null +++ b/itm/models/partner.py @@ -0,0 +1,49 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import api, fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + @api.depends("equipment_ids") + def _equipment_count(self): + for partner in self: + partner.equipment_count = len(partner.equipment_ids) + + @api.depends("access_ids") + def _access_count(self): + for partner in self: + partner.access_count = len(partner.access_ids) + + @api.depends("backup_ids") + def _backup_count(self): + for partner in self: + partner.backup_count = len(partner.backup_ids) + + manage_it = fields.Boolean("Manage IT") + equipment_ids = fields.One2many("itm.equipment", "partner_id", "Assets") + equipment_count = fields.Integer(compute=_equipment_count) + access_ids = fields.One2many("itm.access", "partner_id", "Credentials") + access_count = fields.Integer(compute=_access_count) + backup_ids = fields.One2many("itm.backup", "partner_id", "Backups") + backup_count = fields.Integer(compute=_backup_count) diff --git a/itm/models/service_ad.py b/itm/models/service_ad.py new file mode 100644 index 0000000..7b156bb --- /dev/null +++ b/itm/models/service_ad.py @@ -0,0 +1,303 @@ +# Copyright (C) 2021,2022 TREVI Software +# Copyright (C) 2014 Leandro Ezequiel Baldi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class ItServiceAD(models.Model): + _name = "itm.service.ad" + _inherit = ["mail.thread"] + _description = "Active Directory" + + active = fields.Boolean(default=True) + name = fields.Char("Domain", required=True) + name_pre2000 = fields.Char("Domain (Pre-Windows 2000)", required=True) + type = fields.Selection( + [("primary", "PRIMARY"), ("secundary", "SECONDARY"), ("slave", "SLAVE")], + "AD Type", + ) + obj_ids = fields.One2many( + "itm.service.ad.object", "ad_id", "Active Directory Objects" + ) + site_id = fields.Many2one("itm.site", "Site", ondelete="restrict") + equipment_id = fields.Many2one("itm.equipment", "Asset") + partner_id = fields.Many2one( + "res.partner", + "Partner", + compute="_compute_partner_id", + store=True, + ) + + # Both site_id and equipment_id have partner fields. But, theoreticaly + # the asset that the AD lives on could be owned by someone other than + # the AD owner. We can be pretty sure that the owner of the site is + # the owner of the AD. + # + @api.depends("site_id.partner_id") + def _compute_partner_id(self): + for ad in self: + if ad.site_id and ad.site_id.partner_id: + ad.partner_id = ad.site_id.partner_id + + @api.model_create_multi + def create(self, lst): + res = super().create(lst) + + # Log a note to Site and Equipment chatter. + # + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + for r in res: + msg = self.env._( + '
    ' + ) % { + "dsc": r._description, + "id": r.id, + "name": r.name, + } + if r.site_id: + r.site_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + if r.equipment_id: + r.equipment_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + + return res + + @api.model + def update_chatter(self, structure, lst): + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + site = self.env[structure] + for k, v in lst.items(): + msg = "" + for r in v: + msg = msg + self.env._("
  • %(dsc)s was deleted: %(name)s
  • ") % { + "dsc": self._description, + "name": r["name"], + } + note = '
      ' + msg + "
    " + site.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + # Log a note on deletion of AD to Site and Equipment chatter. Since + # more than one record at a time may be deleted post all deleted records + # for each site and each equipment together in one post. + # + def unlink(self): + # map AD records to sites and equipment + # + sites = {} + equips = {} + for res in self: + if res.site_id: + if res.site_id.id not in sites.keys(): + sites.update({res.site_id.id: [{"id": res.id, "name": res.name}]}) + else: + sites[res.site_id.id].append({"id": res.id, "name": res.name}) + if res.equipment_id: + if res.equipment_id.id not in equips.keys(): + equips.update( + {res.equipment_id.id: [{"id": res.id, "name": res.name}]} + ) + else: + equips[res.equipment_id.id].append({"id": res.id, "name": res.name}) + + self.update_chatter("itm.site", sites) + self.update_chatter("itm.equipment", equips) + + return super().unlink() + + +class ItServiceAdObject(models.Model): + _name = "itm.service.ad.object" + _description = "Active Directory Object" + _rec_name = "complete_name" + _order = "complete_name" + + @api.model + def default_get(self, fields): + if "ad_id" not in fields: + fields.append("ad_id") + res = super().default_get(fields) + return res + + def _get_default_ad(self): + if self.env.context.get("default_ad_id"): + return self.env.context.get("default_ad_id") + return False + + parent_id = fields.Many2one( + "itm.service.ad.object", + "AD Folder", + domain="[('type', '=', 'folder'), ('ad_id', '=', ad_id)]", + ) + ad_id = fields.Many2one( + "itm.service.ad", + "Active Directory", + ondelete="cascade", + default=_get_default_ad, + ) + access_id = fields.Many2one("itm.access", "Related Credential") + complete_name = fields.Char( + compute="_compute_complete_name", store=True, recursive=True + ) + description = fields.Text() + active = fields.Boolean(default=True) + type = fields.Selection( + [("folder", "Folder"), ("group", "Group"), ("user", "User")], + string="Object Type", + default="folder", + ) + + # Folder related fields + folder_name = fields.Char() + + # Group related fields + group_name = fields.Char() + + # User related fields + logon_name = fields.Char(string="User logon name") + complete_logon = fields.Char(compute="_compute_complete_logon") + first_name = fields.Char() + last_name = fields.Char() + full_name = fields.Char(compute="_compute_full_name", store=True) + + @api.constrains("parent_id") + def _check_parent_id(self): + if not self._check_recursion(): + raise ValidationError( + self.env._("You cannot create recursive Active Directory objects.") + ) + + @api.depends("logon_name", "ad_id.name") + def _compute_complete_logon(self): + for rec in self: + if rec.logon_name and rec.ad_id and rec.ad_id.name: + rec.complete_logon = f"{rec.logon_name}@{rec.ad_id.name}" + else: + rec.complete_logon = False + + @api.depends("first_name", "last_name") + def _compute_full_name(self): + for rec in self: + rec.full_name = "{} {}".format( + rec.first_name or "", rec.last_name or "" + ).strip() + + @api.depends("folder_name", "group_name", "logon_name", "parent_id.complete_name") + def _compute_complete_name(self): + for obj in self: + name = False + if obj.type == "folder": + name = obj.folder_name + elif obj.type == "group": + name = obj.group_name + elif obj.type == "user": + name = obj.logon_name + + if obj.parent_id: + obj.complete_name = f"{obj.parent_id.complete_name} \\ {name}" + else: + obj.complete_name = name + + @api.model_create_multi + def create(self, lst): + res = super().create(lst) + + for r in res: + self.create_chatter(r) + + return res + + def create_chatter(self, res): + # Log a note to Site and Equipment chatter. + # + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + msg = self.env._( + '
    ' + ) % { + "dsc": res._description, + "id": res.id, + "name": res.complete_name, + } + if res.ad_id and res.ad_id.site_id: + res.ad_id.site_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + if res.ad_id and res.ad_id.equipment_id: + res.ad_id.equipment_id.message_post( + body=msg, subtype_id=mt_note.id, author_id=author + ) + + @api.model + def update_chatter(self, structure, lst): + mt_note = self.env.ref("mail.mt_note") + author = self.env.user.partner_id and self.env.user.partner_id.id or False + site = self.env[structure] + for k, v in lst.items(): + msg = "" + for r in v: + msg = msg + self.env._("
  • %(dsc)s was deleted: %(name)s
  • ") % { + "dsc": self._description, + "name": r["name"], + } + note = '
      ' + msg + "
    " + site.browse(k).message_post( + body=note, subtype_id=mt_note.id, author_id=author + ) + + # Log a note on deletion of AD object to Site and Equipment chatter. Since + # more than one record at a time may be deleted post all deleted records + # for each site and each equipment together in one post. + # + def unlink(self): + # map AD records to sites and equipment + # + sites = {} + equips = {} + for obj in self: + if obj.ad_id.site_id: + if obj.ad_id.site_id.id not in sites.keys(): + sites.update( + { + obj.ad_id.site_id.id: [ + {"id": obj.id, "name": obj.complete_name} + ] + } + ) + else: + sites[obj.ad_id.site_id.id].append( + {"id": obj.id, "name": obj.complete_name} + ) + if obj.ad_id.equipment_id: + if obj.ad_id.equipment_id.id not in equips.keys(): + equips.update( + { + obj.ad_id.equipment_id.id: [ + {"id": obj.id, "name": obj.complete_name} + ] + } + ) + else: + equips[obj.ad_id.equipment_id.id].append( + {"id": obj.id, "name": obj.complete_name} + ) + + self.update_chatter("itm.site", sites) + self.update_chatter("itm.equipment", equips) + + return super().unlink() diff --git a/itm/models/service_dhcp.py b/itm/models/service_dhcp.py new file mode 100644 index 0000000..0feeac4 --- /dev/null +++ b/itm/models/service_dhcp.py @@ -0,0 +1,22 @@ +# Copyright (C) 2021,2022 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class ItServiceDhcp4(models.Model): + _name = "itm.service.dhcp4" + _description = "DHCP Service" + + name = fields.Char(required=True) + equipment_id = fields.Many2one("itm.equipment", "Asset", required=False) + network_id = fields.Many2one("itm.site.network", "Network", required=False) + subnet = fields.Char() + subnet_mask = fields.Char() + start_address = fields.Many2one("itm.site.network.ip4") + end_address = fields.Many2one("itm.site.network.ip4") + lease_time = fields.Integer(help="Default lease time in seconds") + reservation_ids = fields.One2many( + "itm.equipment.ipreservation", "dhcp_id", "IPv4 reservations" + ) diff --git a/itm/models/service_proxy.py b/itm/models/service_proxy.py new file mode 100644 index 0000000..b7c4d5c --- /dev/null +++ b/itm/models/service_proxy.py @@ -0,0 +1,34 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItServiceProxy(models.Model): + _name = "itm.service.proxy" + _description = "Network Proxy Service" + + name = fields.Char(required=True) + transparent = fields.Boolean("Transparent Proxy") + enable_ssk = fields.Boolean("Proxy Enable Single Sign-On (Kerberos)") + adblocking = fields.Boolean("Proxy Ad Blocking") + port = fields.Char("Proxy Port") + cache_size = fields.Char("Proxy Cache File Size") diff --git a/itm/models/service_vpn.py b/itm/models/service_vpn.py new file mode 100644 index 0000000..8da8129 --- /dev/null +++ b/itm/models/service_vpn.py @@ -0,0 +1,39 @@ +############################################################################## +# +# Copyright (C) 2014 Leandro Ezequiel Baldi +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from odoo import fields, models + + +class ItServiceVpn(models.Model): + _name = "itm.service.vpn" + _description = "VPN Service" + + name = fields.Char(required=True) + protocol = fields.Selection([("tcp", "TCP"), ("udp", "UDP")], "VPN Protocol") + address = fields.Char("VPN Address") + server_cert = fields.Binary("VPN Server Certificate") + cacn = fields.Boolean("Client Authorization by common name") + tun = fields.Boolean("VPN Tun Interface") + nat = fields.Boolean("VPN Network Address Traslation") + c2c = fields.Boolean("VPN Allow Client to Client connections") + gateway = fields.Boolean("Redirect Gateway") + search_domain = fields.Char("VPN Search Domain") + wins_server = fields.Char("VPN WINS Server") diff --git a/itm/models/service_wireless.py b/itm/models/service_wireless.py new file mode 100644 index 0000000..1fb7c60 --- /dev/null +++ b/itm/models/service_wireless.py @@ -0,0 +1,67 @@ +# Copyright (C) 2021,2022 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class ItServiceWireless(models.Model): + _name = "itm.service.wireless" + _description = "Wireless Service" + + name = fields.Char("Description", required=True) + type = fields.Selection( + [ + ("ap", "Access Point"), + ("bridge", "Bridge"), + ("extender", "Extender"), + ("router_wireless", "Wireless Router"), + ], + ) + network_id = fields.Many2one("itm.site.network", "Network") + access_id = fields.Many2one("itm.access", "Access Credentials") + bssid_ids = fields.One2many("itm.service.wireless.ssid", "wireless_id", "SSI") + + def _compute_display_name(self): + res = super()._compute_display_name() + + for rec in self: + if len(rec.bssid_ids) == 1: + rec.display_name = f"{rec.name} ({rec.bssid_ids.name})" + elif len(rec.bssid_ids) > 1: + rec.display_name = f"{rec.name} (multi SSID)" + return res + + +class WirelessSsid(models.Model): + _name = "itm.service.wireless.ssid" + _description = "Wireless Base Station ID" + + name = fields.Char("SSID", required=True) + wireless_id = fields.Many2one("itm.service.wireless", "Wireless service") + is_guest = fields.Boolean(help="If checked, this is a Guest SSID") + auth_type = fields.Selection( + [ + ("none", "NONE"), + ("wep64", "WEP-64bits"), + ("wep128", "WEP-128bits"), + ("wpa", "WPA Personal (Pre-shared key)"), + ("wpa_ent", "WPA Enterprise"), + ("wpa2", "WPA2 Personal (Pre-shared key)"), + ("wpa2_ent", "WPA2 Enterprise"), + ("auto", "Auto"), + ("other", "Other"), + ], + "Authentication Type", + default="wpa2", + ) + encryption_type = fields.Selection( + [ + ("none", "NONE"), + ("auto", "Auto"), + ("tkip", "TKIP"), + ("aes", "AES"), + ], + default="auto", + ) + passkey = fields.Char("Key") diff --git a/itm/models/site.py b/itm/models/site.py new file mode 100644 index 0000000..94daf54 --- /dev/null +++ b/itm/models/site.py @@ -0,0 +1,107 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + +_logger = logging.getLogger(__name__) + + +class ItSite(models.Model): + _name = "itm.site" + _inherit = ["mail.activity.mixin", "mail.thread"] + _description = "IT Site" + + @api.depends("equipment_ids") + def _compute_equipment_count(self): + for site in self: + site.equipment_count = len(site.equipment_ids) + + @api.depends("access_ids") + def _compute_access_count(self): + for site in self: + site.access_count = len(site.access_ids) + + company_id = fields.Many2one( + "res.company", + "Company", + default=lambda self: self.env.company, + ) + name = fields.Char(required=True) + partner_id = fields.Many2one("res.partner", "Partner", tracking=True) + equipment_count = fields.Integer( + compute="_compute_equipment_count", + string="Assets", + store=True, + ) + equipment_ids = fields.One2many("itm.equipment", "site_id", "Asset{s)") + access_count = fields.Integer( + compute="_compute_access_count", string="Credentials", store=False + ) + active = fields.Boolean(default=True, tracking=True) + access_ids = fields.One2many("itm.access", "site_id", "Credential(s)") + ad_ids = fields.One2many("itm.service.ad", "site_id", "Active Directory") + network_ids = fields.One2many("itm.site.network", "site_id", string="Networks") + + +class ItSiteNetwork(models.Model): + _name = "itm.site.network" + _description = "Network" + + site_id = fields.Many2one("itm.site", "Site") + name = fields.Char(string="Domain", required=True) + subnet = fields.Char(required=True) + netmask = fields.Char(required=True) + default_gw = fields.Many2one("itm.site.network.ip4", "Default Gateway") + dns_ids = fields.Many2many( + comodel_name="itm.site.network.ip4", string="DNS Servers" + ) + dhcp4_ids = fields.One2many("itm.service.dhcp4", "network_id", "DHCP") + ip4_ids = fields.One2many( + "itm.site.network.ip4", "network_id", string="IPv4 Addresses" + ) + + +class ItSiteNetworkIp4(models.Model): + _name = "itm.site.network.ip4" + _description = "Network IPv4 Address" + + name = fields.Char(required=True) + network_id = fields.Many2one("itm.site.network", required=True) + + # Upgrade earlier installations that didn't have 'network_id' field + # + def _initialize_network_id(self): + _logger.info( + "Beginning initialize of 'network_id' field of itm.site.network.ip4" + ) + iface_obj = self.env["itm.equipment.network"] + ips = self.env["itm.site.network.ip4"].search([("network_id", "=", False)]) + _logger.info(f"Found {len(ips)} records to update") + for ip in ips: + iface = iface_obj.search( + [ + "|", + ("static_ipv4_id", "=", ip.id), + ("dhcp_ipv4_id", "=", ip.id), + ] + ) + if iface: + _logger.warning(f"IP {ip.name}: set network: {iface.network_id.name}") + ip.network_id = iface.network_id + + @api.constrains("name", "network_id") + def check_name(self): + IpAddr = self.env["itm.site.network.ip4"] + for rec in self: + duplicates = IpAddr.search( + [ + ("name", "=", rec.name), + ("network_id", "=", rec.network_id.id), + ("id", "!=", rec.id), + ] + ) + if duplicates: + raise ValidationError(_("IP address '%s' already exists.", rec.name)) diff --git a/itm/pyproject.toml b/itm/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/itm/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/itm/readme/CREDITS.md b/itm/readme/CREDITS.md new file mode 100644 index 0000000..96b0c57 --- /dev/null +++ b/itm/readme/CREDITS.md @@ -0,0 +1,2 @@ +- Leandro Ezequiel Baldi \ +- Altela Eleviansyah Pramardhika \ diff --git a/itm/readme/DESCRIPTION.md b/itm/readme/DESCRIPTION.md new file mode 100644 index 0000000..fe3e319 --- /dev/null +++ b/itm/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module is used to record information about a site's IT +infrastructure. You can record information about equipment, software, +backups, networks and access credentials. diff --git a/itm/readme/HISTORY.md b/itm/readme/HISTORY.md new file mode 100644 index 0000000..6bdf4be --- /dev/null +++ b/itm/readme/HISTORY.md @@ -0,0 +1,3 @@ +## 16.0.2.0.0 (2022-11-01) + +- \[IMP\] Use the new Odoo javascript framework OWL diff --git a/itm/readme/ROADMAP.md b/itm/readme/ROADMAP.md new file mode 100644 index 0000000..977f1ca --- /dev/null +++ b/itm/readme/ROADMAP.md @@ -0,0 +1,11 @@ +- Manually set (or install) the python library 'cryptography' to version + 36.0.2. Because of Odoo Python requirements this module will **NOT** + work with versions of cryptography greater than 36.0.2. It will also + **NOT** work with the version in the Odoo requirements.txt file + (currently 3.4.8). +- The password for encrypting and decrypting credentials is stored in + Odoo as a system parameter. An attacker who has the + 'Administration/Settings' priviledge or has access to the Odoo + database itself can easily decrypt a credential's password field. +- To Do: store the encryption password in Odoo's configuration file + instead of a system parameter in the database diff --git a/itm/security/ir.model.access.csv b/itm/security/ir.model.access.csv new file mode 100644 index 0000000..fa4492d --- /dev/null +++ b/itm/security/ir.model.access.csv @@ -0,0 +1,114 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +itm_rule_equipment_manager,itm_equipment,model_itm_equipment,group_itm_manager,1,1,1,1 +itm_rule_equipment_mod,itm_equipment,model_itm_equipment,group_itm_mod,1,1,1,0 +itm_rule_equipment_user,itm_equipment,model_itm_equipment,group_itm_user,1,0,0,0 +itm_rule_equipment_brand_manager,itm_equipment_brand,model_itm_equipment_brand,group_itm_manager,1,1,1,1 +itm_rule_equipment_brand_mod,itm_equipment_brand,model_itm_equipment_brand,group_itm_mod,1,1,1,0 +itm_rule_equipment_brand_user,itm_equipment_brand,model_itm_equipment_brand,group_itm_user,1,0,0,0 +itm_rule_equipment_worklog_manager,itm_equipment_worklog,model_itm_equipment_worklog,group_itm_manager,1,1,1,1 +itm_rule_equipment_worklog_mod,itm_equipment_worklog,model_itm_equipment_worklog,group_itm_mod,1,1,1,0 +itm_rule_equipment_worklog_user,itm_equipment_worklog,model_itm_equipment_worklog,group_itm_user,1,0,0,0 +itm_rule_equipment_function_manager,itm_equipment_function,model_itm_equipment_function,group_itm_manager,1,1,1,1 +itm_rule_equipment_function_mod,itm_equipment_function,model_itm_equipment_function,group_itm_mod,1,1,1,0 +itm_rule_equipment_function_user,itm_equipment_function,model_itm_equipment_function,group_itm_user,1,0,0,0 +itm_rule_equipment_network_manager,itm_equipment_network,model_itm_equipment_network,group_itm_manager,1,1,1,1 +itm_rule_equipment_network_mod,itm_equipment_network,model_itm_equipment_network,group_itm_mod,1,1,1,0 +itm_rule_equipment_network_user,itm_equipment_network,model_itm_equipment_network,group_itm_user,1,0,0,0 +itm_rule_equipment_network_proxy_manager,itm_equipment_network_proxy,model_itm_equipment_network_proxy,group_itm_manager,1,1,1,1 +itm_rule_equipment_network_proxy_mod,itm_equipment_network_proxy,model_itm_equipment_network_proxy,group_itm_mod,1,1,1,0 +itm_rule_equipment_network_proxy_user,itm_equipment_network_proxy,model_itm_equipment_network_proxy,group_itm_user,1,0,0,0 +itm_rule_equipment_partition_manager,itm_equipment_partition,model_itm_equipment_partition,group_itm_manager,1,1,1,1 +itm_rule_equipment_partition_mod,itm_equipment_partition,model_itm_equipment_partition,group_itm_mod,1,1,1,0 +itm_rule_equipment_partition_user,itm_equipment_partition,model_itm_equipment_partition,group_itm_user,1,0,0,0 +itm_rule_equipment_partition_mount_manager,itm_equipment_partition_mount,model_itm_equipment_partition_mount,group_itm_manager,1,1,1,1 +itm_rule_equipment_partition_mount_mod,itm_equipment_partition_mount,model_itm_equipment_partition_mount,group_itm_mod,1,1,1,0 +itm_rule_equipment_partition_mount_user,itm_equipment_partition_mount,model_itm_equipment_partition_mount,group_itm_user,1,0,0,0 +itm_rule_equipment_rule_manager,itm_equipment_rule,model_itm_equipment_rule,group_itm_manager,1,1,1,1 +itm_rule_equipment_rule_mod,itm_equipment_rule,model_itm_equipment_rule,group_itm_mod,1,1,1,0 +itm_rule_equipment_rule_user,itm_equipment_rule,model_itm_equipment_rule,group_itm_user,1,0,0,0 +itm_rule_equipment_forward_manager,itm_equipment_forward,model_itm_equipment_forward,group_itm_manager,1,1,1,1 +itm_rule_equipment_forward_mod,itm_equipment_forward,model_itm_equipment_forward,group_itm_mod,1,1,1,0 +itm_rule_equipment_forward_user,itm_equipment_forward,model_itm_equipment_forward,group_itm_user,1,0,0,0 +itm_rule_equipment_mapping_manager,itm_equipment_mapping,model_itm_equipment_mapping,group_itm_manager,1,1,1,1 +itm_rule_equipment_mapping_mod,itm_equipment_mapping,model_itm_equipment_mapping,group_itm_mod,1,1,1,0 +itm_rule_equipment_mapping_user,itm_equipment_mapping,model_itm_equipment_mapping,group_itm_user,1,0,0,0 +itm_rule_equipment_mapping_line_manager,itm_equipment_mapping_line,model_itm_equipment_mapping_line,group_itm_manager,1,1,1,1 +itm_rule_equipment_mapping_line_mod,itm_equipment_mapping_line,model_itm_equipment_mapping_line,group_itm_mod,1,1,1,0 +itm_rule_equipment_mapping_line_user,itm_equipment_mapping_line,model_itm_equipment_mapping_line,group_itm_user,1,0,0,0 +itm_rule_mapping_perm_advanced_manager,itm_equipment_mapping_permission_advanced,model_itm_equipment_mapping_permission_advanced,group_itm_manager,1,1,1,1 +itm_rule_mapping_perm_advanced_mod,itm_equipment_mapping_permission_advanced,model_itm_equipment_mapping_permission_advanced,group_itm_mod,1,1,1,0 +itm_rule_mapping_perm_advanced_user,itm_equipment_mapping_permission_advanced,model_itm_equipment_mapping_permission_advanced,group_itm_user,1,0,0,0 +itm_rule_equipment_db_manager,itm_equipment_db,model_itm_equipment_db,group_itm_manager,1,1,1,1 +itm_rule_equipment_db_mod,itm_equipment_db,model_itm_equipment_db,group_itm_mod,1,1,1,0 +itm_rule_equipment_db_user,itm_equipment_db,model_itm_equipment_db,group_itm_user,1,0,0,0 +itm_rule_equipment_db_engine_manager,itm_equipment_db_engine,model_itm_equipment_db_engine,group_itm_user,1,1,1,1 +itm_rule_equipment_db_engine_mod,itm_equipment_db_engine,model_itm_equipment_db_engine,group_itm_mod,1,1,1,0 +itm_rule_equipment_db_engine_user,itm_equipment_db_engine,model_itm_equipment_db_engine,group_itm_user,1,0,0,0 +itm_rule_equipment_dbsetting_manager,itm_equipment_dbsetting,model_itm_equipment_dbsetting,group_itm_manager,1,1,1,1 +itm_rule_equipment_dbsetting_mod,itm_equipment_dbsetting,model_itm_equipment_dbsetting,group_itm_mod,1,1,1,0 +itm_rule_equipment_dbsetting_user,itm_equipment_dbsetting,model_itm_equipment_dbsetting,group_itm_user,1,0,0,0 +itm_rule_equipment_ipreservation_manager,itm_equipment_ipreservation,model_itm_equipment_ipreservation,group_itm_manager,1,1,1,1 +itm_rule_equipment_ipreservation_mod,itm_equipment_ipreservation,model_itm_equipment_ipreservation,group_itm_mod,1,1,1,0 +itm_rule_equipment_ipreservation_user,itm_equipment_ipreservation,model_itm_equipment_ipreservation,group_itm_user,1,0,0,0 +itm_rule_equipment_dcgroup_manager,itm_equipment_dcobject,model_itm_service_ad_object,group_itm_manager,1,1,1,1 +itm_rule_equipment_dcgroup_mod,itm_equipment_dcobject,model_itm_service_ad_object,group_itm_mod,1,1,1,0 +itm_rule_equipment_dcgroup_user,itm_equipment_dcobject,model_itm_service_ad_object,group_itm_user,1,0,0,0 +itm_rule_equipment_type_manager,itm_equipment_type,model_itm_equipment_type,group_itm_manager,1,1,1,1 +itm_rule_equipment_type_mod,itm_equipment_type,model_itm_equipment_type,group_itm_mod,1,1,1,0 +itm_rule_equipment_type_user,itm_equipment_type,model_itm_equipment_type,group_itm_user,1,0,0,0 +itm_rule_service_ad_manager,itm_service_ad,model_itm_service_ad,group_itm_manager,1,1,1,1 +itm_rule_service_ad_mod,itm_service_ad,model_itm_service_ad,group_itm_mod,1,1,1,0 +itm_rule_service_ad_user,itm_service_ad,model_itm_service_ad,group_itm_user,1,0,0,0 +itm_rule_service_dhcp_manager,itm_service_dhcp,model_itm_service_dhcp4,group_itm_manager,1,1,1,1 +itm_rule_service_dhcp_mod,itm_service_dhcp,model_itm_service_dhcp4,group_itm_mod,1,1,1,0 +itm_rule_service_dhcp_user,itm_service_dhcp,model_itm_service_dhcp4,group_itm_user,1,0,0,0 +itm_rule_service_proxy_manager,itm_service_proxy,model_itm_service_proxy,group_itm_manager,1,1,1,1 +itm_rule_service_proxy_mod,itm_service_proxy,model_itm_service_proxy,group_itm_mod,1,1,1,0 +itm_rule_service_proxy_user,itm_service_proxy,model_itm_service_proxy,group_itm_user,1,0,0,0 +itm_rule_service_vpn_manager,itm_service_vpn,model_itm_service_vpn,group_itm_manager,1,1,1,1 +itm_rule_service_vpn_mod,itm_service_vpn,model_itm_service_vpn,group_itm_mod,1,1,1,0 +itm_rule_service_vpn_user,itm_service_vpn,model_itm_service_vpn,group_itm_user,1,0,0,0 +itm_rule_service_wireless_manager,itm_service_wireless,model_itm_service_wireless,group_itm_manager,1,1,1,1 +itm_rule_service_wireless_mode,itm_service_wireless,model_itm_service_wireless,group_itm_mod,1,1,1,0 +itm_rule_service_wireless_user,itm_service_wireless,model_itm_service_wireless,group_itm_user,1,0,0,0 +itm_rule_service_wireless_ssid_manager,itm_service_wireless_ssid,model_itm_service_wireless_ssid,group_itm_manager,1,1,1,1 +itm_rule_service_wireless_ssid_mode,itm_service_wireless_ssid,model_itm_service_wireless_ssid,group_itm_mod,1,1,1,0 +itm_rule_service_wireless_ssid_user,itm_service_wireless_ssid,model_itm_service_wireless_ssid,group_itm_user,1,0,0,0 +itm_rule_site_manager,itm_site,model_itm_site,group_itm_manager,1,1,1,1 +itm_rule_site_mod,itm_site,model_itm_site,group_itm_mod,1,1,0,0 +itm_rule_site_user,itm_site,model_itm_site,group_itm_user,1,0,0,0 +itm_rule_site_network_manager,itm_site_network,model_itm_site_network,group_itm_manager,1,1,1,1 +itm_rule_site_network_mod,itm_site_network,model_itm_site_network,group_itm_mod,1,1,0,0 +itm_rule_site_network_user,itm_site_network,model_itm_site_network,group_itm_user,1,0,0,0 +itm_rule_site_network_ip4_manager,itm_site_network_ip4,model_itm_site_network_ip4,group_itm_manager,1,1,1,1 +itm_rule_site_network_ip4_mod,itm_site_network_ip4,model_itm_site_network_ip4,group_itm_mod,1,1,1,0 +itm_rule_site_network_ip4_user,itm_site_network_ip4,model_itm_site_network_ip4,group_itm_user,1,1,1,1 +itm_rule_equipment_configuration_manager,itm_equipment_configuration,model_itm_equipment_configuration,group_itm_manager,1,1,1,1 +itm_rule_equipment_configuration_mod,itm_equipment_configuration,model_itm_equipment_configuration,group_itm_mod,1,1,1,0 +itm_rule_equipment_configuration_user,itm_equipment_configuration,model_itm_equipment_configuration,group_itm_user,1,0,0,0 +itm_rule_access_manager,itm_access,model_itm_access,group_itm_manager,1,1,1,1 +itm_rule_access_mod,itm_access,model_itm_access,group_itm_mod,1,1,1,0 +itm_rule_access_user,itm_access,model_itm_access,group_itm_user,1,0,0,0 +itm_rule_backup_manager,itm_backup,model_itm_backup,group_itm_manager,1,1,1,1 +itm_rule_backup_mod,itm_backup,model_itm_backup,group_itm_mod,1,1,1,0 +itm_rule_backup_user,itm_backup,model_itm_backup,group_itm_user,1,0,0,0 +itm_rule_application_manager,itm_application,model_itm_application,group_itm_manager,1,1,1,1 +itm_rule_application_mod,itm_application,model_itm_application,group_itm_mod,1,1,1,0 +itm_rule_application_user,itm_application,model_itm_application,group_itm_user,1,0,0,0 +itm_rule_application_license_manager,itm_application_license,model_itm_application_license,group_itm_manager,1,1,1,1 +itm_rule_application_license_mod,itm_application_license,model_itm_application_license,group_itm_mod,1,1,1,0 +itm_rule_application_license_user,itm_application_license,model_itm_application_license,group_itm_user,1,0,0,0 +itm_wizard_credential_manager,itm_wizard_credential,model_itm_wizard_credential,group_itm_manager,1,1,1,1 +itm_wizard_credential_mod,itm_wizard_credential,model_itm_wizard_credential,group_itm_mod,1,1,1,0 +rule_itm_equipment_component,access_itm_equipment_component,model_itm_equipment_component,group_itm_user,1,0,0,0 +rule_itm_equipment_component_type,access_itm_equipment_component_type,model_itm_equipment_component_type,group_itm_user,1,0,0,0 +rule_itm_equipment_component_specification,access_itm_equipment_component_specification,model_itm_equipment_component_specification,group_itm_user,1,1,1,0 +rule_itm_equipment_component_specification_selector,access_itm_equipment_component_specification_selector,model_itm_equipment_component_specification_selector,group_itm_user,1,0,0,0 +rule_itm_equipment_component_specification_key,access_itm_equipment_component_specification_key,model_itm_equipment_component_specification_key,group_itm_user,1,0,0,0 +rule_itm_equipment_component_specification_value,access_itm_equipment_component_specification_value,model_itm_equipment_component_specification_value,group_itm_user,1,0,0,0 +rule_itm_equipment_component_mgr,access_itm_equipment_component,model_itm_equipment_component,group_itm_manager,1,1,1,1 +rule_itm_equipment_component_type_mgr,access_itm_equipment_component_type,model_itm_equipment_component_type,group_itm_manager,1,1,1,1 +rule_itm_equipment_component_specification_mgr,access_itm_equipment_component_specification,model_itm_equipment_component_specification,group_itm_manager,1,1,1,1 +rule_itm_equipment_component_specification_selector_mgr,access_itm_equipment_component_specification_selector,model_itm_equipment_component_specification_selector,group_itm_manager,1,1,1,1 +rule_itm_equipment_component_specification_key_mgr,access_itm_equipment_component_specification_key,model_itm_equipment_component_specification_key,group_itm_manager,1,1,1,1 +rule_itm_equipment_component_specification_value_mgr,access_itm_equipment_component_specification_value,model_itm_equipment_component_specification_value,group_itm_manager,1,1,1,1 diff --git a/itm/security/it_security.xml b/itm/security/it_security.xml new file mode 100644 index 0000000..daaa40a --- /dev/null +++ b/itm/security/it_security.xml @@ -0,0 +1,126 @@ + + + + + + + + IT Infrastructure Management + Helps you manage your infrastructure equipment, access and backups. + + + + User + + + + + Moderator + + + + + + Portal + + + + + + Manager + + + + + + + + + + + + IT Assets: multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + + IT Credentials: multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + + IT Backup: multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + + IT Application: multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + + + IT Portal - Equipment + + + + [('partner_id','=',user.partner_id.id)] + + + + IT Portal - Access + + + + [('partner_id','=',user.partner_id.id)] + + + + IT Portal - Backup + + + + [('partner_id','=',user.partner_id.id)] + + + + + + diff --git a/itm/static/description/asset.png b/itm/static/description/asset.png new file mode 100644 index 0000000..67c0c9d Binary files /dev/null and b/itm/static/description/asset.png differ diff --git a/itm/static/description/credential.png b/itm/static/description/credential.png new file mode 100644 index 0000000..bb5b665 Binary files /dev/null and b/itm/static/description/credential.png differ diff --git a/itm/static/description/icon.jpg b/itm/static/description/icon.jpg new file mode 100644 index 0000000..8e0fdac Binary files /dev/null and b/itm/static/description/icon.jpg differ diff --git a/itm/static/description/icon.png b/itm/static/description/icon.png new file mode 100644 index 0000000..8e0fdac Binary files /dev/null and b/itm/static/description/icon.png differ diff --git a/itm/static/description/index.html b/itm/static/description/index.html new file mode 100644 index 0000000..4f9d5a2 --- /dev/null +++ b/itm/static/description/index.html @@ -0,0 +1,78 @@ +
    +
    +

    ODOO IT INFRASTRUCTURE MANAGEMENT MODULE

    +

    IT Assets, Credentials, Backups, and more..

    +
    +
    +
    +

    + This module is used for infrastructure management. You can record assets, credentials and network and service specific details. +

    +
    +
    +
    + +
    +
    +

    Partners

    +
    +
    + +
    +
    +
    +

    + Access your partner's infrastructure directly from the partner's screen. +

    +
    +
    +
    + +
    +
    +

    IT Assets

    +
    +

    + Register all your IT equipment. Machines, switches, routers, notebooks, storages, keybords, everything!. Discover all the settings provided by the module for recording information about your equipment. +

    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Access Credentials

    +
    +
    + +
    +
    +
    +

    + Dont lose access to your infrastructure! Credentials are stored in the database in encrypted form. +

    +
    +
    +
    + +
    +
    +

    Technical Support

    +

    + For technical support for this, or any of our other modules, you can email our help desk for free email based support. We welcome any and all feedback you may have about this module and any new features you would like to see added to it. Join us on github if you would like to collaborate on development of this module! +

    +
    + +
    diff --git a/itm/static/description/partner.png b/itm/static/description/partner.png new file mode 100644 index 0000000..964ec33 Binary files /dev/null and b/itm/static/description/partner.png differ diff --git a/itm/static/src/img/default_image_equipment.png b/itm/static/src/img/default_image_equipment.png new file mode 100644 index 0000000..8e0fdac Binary files /dev/null and b/itm/static/src/img/default_image_equipment.png differ diff --git a/itm/static/src/img/main_screenshot.png b/itm/static/src/img/main_screenshot.png new file mode 100644 index 0000000..ab78e06 Binary files /dev/null and b/itm/static/src/img/main_screenshot.png differ diff --git a/itm/static/src/js/itm_password_char_field.esm.js b/itm/static/src/js/itm_password_char_field.esm.js new file mode 100644 index 0000000..4f82e65 --- /dev/null +++ b/itm/static/src/js/itm_password_char_field.esm.js @@ -0,0 +1,145 @@ +/** + * Copyright 2021,2022 TREVI Software + * Copyright 2018 Modoolar + * License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html). + * + */ + +import { CharField } from "@web/views/fields/char/char_field"; +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; + +const { + onMounted, + onWillUnmount, + onWillStart, + onWillUpdateProps, + useRef, + useState, +} = owl; + +export class PasswordCharField extends CharField { + setup() { + super.setup(); + this.notification = useService("notification"); + this.inputRef = useRef("input"); + this.orm = useService("orm"); + this.state = useState({ + is_visible: 0, + name: this.env.config.getDisplayName(), + }); + this.cbRef = useRef("clipboard-btn"); + this.ciphertext = ""; + this.is_edited = 0; + + onWillStart(async () => { + this.ciphertext = this.props.value; + try { + this.plaintext = await this.decrypt_password(); + } catch (err) { + console.log("Failed to decrypt password."); + console.log(err); + } + }); + + onWillUpdateProps((nextProps) => this.willUpdateProps(nextProps)); + + onMounted(() => { + var $clipboardBtn = + this.cbRef.el.getElementsByClassName("o_clipboard_button"); + var me = this; + // eslint-disable-next-line no-undef + var clipboard = new ClipboardJS($clipboardBtn, { + text: function () { + return me.choosePasswordText(); + }, + }); + this.clipboard = clipboard; + }); + + onWillUnmount(async () => { + this.clipboard.destroy(); + }); + } + + async willUpdateProps(nextProps) { + // Set the ciphertext if changed. + // FIXME: this is not optimal, maybe we can hook the manual save instead? + if ( + this.props.record.data.create_date !== false && + this.props.value !== this.ciphertext + ) { + if (this.is_edited === 1) { + this.ciphertext = nextProps.value; + this.plaintext = await this.decrypt_password(); + } + } + + if (nextProps.value !== this.ciphertext) { + this.is_edited = 1; + } else if (this.is_edited === 1) { + this.is_edited = 0; + } + } + + choosePasswordText() { + var txt = this.plaintext; + if (this.is_edited === 1) { + txt = this.props.value; + } + this.notification.add(this.env._t("Password copied to clipboard"), { + title: this.state.name, + type: "info", + }); + return txt; + } + + onClickShowPassword() { + if (this.state.is_visible === 0) { + // State: password is NOT visible + + // If the user is editing the password show that, otherwise + // show decrypted password. + if (this.is_edited === 1) { + this.props.isPassword = 0; + this.state.is_visible = 1; + } else { + this.show_decrypted_password(); + } + } else { + // State: password is visible + if (this.is_edited === 0) { + // We do this to show the same number of '*' as before + this.props.value = this.ciphertext; + } + this.props.isPassword = 1; + this.state.is_visible = 0; + } + } + + decrypt_password() { + if ( + this.props.record.data.create_date === false || + this.props.value === "" || + this.props.value === false + ) { + return ""; + } + return this.orm + .call("itm.access", "decrypt_password_as_string", [ + this.props.record.data.id, + ]) + .then(function (plaintext) { + return plaintext; + }); + } + + async show_decrypted_password() { + var plaintext = await this.decrypt_password(); + this.props.value = plaintext; + this.props.isPassword = 0; + this.state.is_visible = 1; + } +} +PasswordCharField.template = "itm.PasswordCharField"; +registry.category("fields").add("password_char", PasswordCharField); diff --git a/itm/static/src/js/itm_password_char_field.xml b/itm/static/src/js/itm_password_char_field.xml new file mode 100644 index 0000000..c605647 --- /dev/null +++ b/itm/static/src/js/itm_password_char_field.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/itm/tests/__init__.py b/itm/tests/__init__.py new file mode 100644 index 0000000..1a51113 --- /dev/null +++ b/itm/tests/__init__.py @@ -0,0 +1,8 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_access # noqa +from . import test_component # noqa +from . import test_equipment # noqa +from . import test_network # noqa +from . import test_worklog # noqa diff --git a/itm/tests/test_access.py b/itm/tests/test_access.py new file mode 100644 index 0000000..1e98f98 --- /dev/null +++ b/itm/tests/test_access.py @@ -0,0 +1,85 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +import base64 + +from cryptography.fernet import Fernet + +from odoo.tests.common import TransactionCase + + +class TestAccess(TransactionCase): + def setUp(self): + super().setUp() + + self.ItAccess = self.env["itm.access"] + self.ItSite = self.env["itm.site"] + self.defaultSite = self.ItSite.create({"name": "site"}) + + # Prime salt and decryption password creation + self.ItAccess.create( + {"name": "a", "password": "a", "site_id": self.defaultSite.id} + ) + + def _decrypt(self, ciphertext): + key = self.ItAccess.get_urlsafe_key() + f = Fernet(key) + + token = base64.urlsafe_b64decode(ciphertext) + plaintext = f.decrypt(token).decode() + return plaintext + + def test_change_password(self): + """Changing password results in encrypted version of new password""" + + cred = self.ItAccess.create( + {"name": "a", "password": "123", "site_id": self.defaultSite.id} + ) + self.assertEqual("123", self._decrypt(cred.password)) + cred.write({"password": "456"}) + self.assertEqual("456", self._decrypt(cred.password)) + + def test_random_password(self): + """Random password isn't mangled""" + + # Not sure there's a way to test randomness. Just test that + # it's the expected length. + # + cred = self.ItAccess.create({"name": "a", "site_id": self.defaultSite.id}) + self.assertFalse(cred.password) + cred.get_random_password() + strRandom = self.ItAccess.decrypt_password_as_string(cred.id) + self.assertEqual(16, len(strRandom)) + + def test_uniqueness(self): + """Identical passwords have differing encrypted outputs""" + + cred1 = self.ItAccess.create( + { + "name": "a", + "password": "P@$$w0rd", + "site_id": self.defaultSite.id, + } + ) + cred2 = self.ItAccess.create( + { + "name": "b", + "password": "P@$$w0rd", + "site_id": self.defaultSite.id, + } + ) + strPass1 = self.ItAccess.decrypt_password_as_string(cred1.id) + strPass2 = self.ItAccess.decrypt_password_as_string(cred2.id) + self.assertEqual(strPass2, strPass1) + token1 = base64.urlsafe_b64decode(cred1.password) + token2 = base64.urlsafe_b64decode(cred2.password) + self.assertNotEqual(token1, token2) + + def test_unset_password(self): + """Unset password returns empty string""" + + cred = self.ItAccess.create({"name": "a", "site_id": self.defaultSite.id}) + self.assertFalse(cred.password) + strRandom = self.ItAccess.decrypt_password_as_string(cred.id) + self.assertEqual(0, len(strRandom)) diff --git a/itm/tests/test_component.py b/itm/tests/test_component.py new file mode 100644 index 0000000..9620986 --- /dev/null +++ b/itm/tests/test_component.py @@ -0,0 +1,108 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo.exceptions import ValidationError +from odoo.tests import common + + +class TestEquipmentComponent(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.Equipment = cls.env["itm.equipment"] + cls.Component = cls.env["itm.equipment.component"] + cls.ComponentType = cls.env["itm.equipment.component.type"] + cls.Specification = cls.env["itm.equipment.component.specification"] + cls.Selector = cls.env["itm.equipment.component.specification.selector"] + cls.Key = cls.env["itm.equipment.component.specification.key"] + cls.Value = cls.env["itm.equipment.component.specification.value"] + cls.ItSite = cls.env["itm.site"] + cls.Partner = cls.env["res.partner"] + + cls.defaultComponentType = cls.ComponentType.create({"name": "A"}) + cls.defaultSite = cls.ItSite.create({"name": "site"}) + cls.defaultPartner = cls.Partner.create( + { + "name": "Partner A", + "email": "a@example.org", + } + ) + cls.equipment = cls.Equipment.create( + { + "name": "My Equipment", + "partner_id": cls.defaultPartner.id, + "site_id": cls.defaultSite.id, + } + ) + + def test_create_updates_equipment_chatter(self): + """Creating a component updates equipment chatter""" + + msg_count = len(self.equipment.message_ids) + self.Component.create( + { + "name": "Component X", + "equipment_id": self.equipment.id, + "component_type_id": self.defaultComponentType.id, + } + ) + + self.assertEqual(msg_count + 1, len(self.equipment.message_ids)) + + def test_new_key_from_specification(self): + """ + When a new key is created from the component specification form the + relevant linkages between component type and key are created. + """ + + component = self.Component.create( + { + "name": "Component X", + "equipment_id": self.equipment.id, + "component_type_id": self.defaultComponentType.id, + } + ) + selector = self.Selector.create({"name": "Some Selector"}) + key = self.Key.with_context( + default_component_type_id=component.component_type_id.id + ).create( + { + "name": "K", + "value_type_id": selector.id, + } + ) + + self.assertIn(component.component_type_id, key.component_type_ids) + + def test_new_value_set_specification(self): + """ + When a new value is created automatically set the selector + """ + + selector = self.Selector.create({"name": "Some Selector"}) + val = self.Value.with_context(default_value_type_id=selector.id).create( + {"name": "V"} + ) + + self.assertEqual(val.value_type_id, selector) + + def test_unique_value_name(self): + """ + The (name, value_type_id) field combo of ITM Value should be + (case insensitive) unique. + """ + + typeA = self.Selector.create({"name": "Some Selector A"}) + typeB = self.Selector.create({"name": "Some Selector B"}) + self.Value.create({"name": "SCSI", "value_type_id": typeA.id}) + self.Value.create({"name": "SATA", "value_type_id": typeB.id}) + + with self.assertRaises(ValidationError): + self.Value.create({"name": "scsi", "value_type_id": typeA.id}) + + try: + self.Value.create({"name": "scsi", "value_type_id": typeB.id}) + except ValidationError: + self.fail("Unexpected ValidationError!") diff --git a/itm/tests/test_equipment.py b/itm/tests/test_equipment.py new file mode 100644 index 0000000..45471dd --- /dev/null +++ b/itm/tests/test_equipment.py @@ -0,0 +1,171 @@ +# Copyright (C) 2022 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests import common + + +class TestEquipment(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.Equipment = cls.env["itm.equipment"] + cls.NetInterface = cls.env["itm.equipment.network"] + cls.NetworkIp4 = cls.env["itm.site.network.ip4"] + cls.SiteNetwork = cls.env["itm.site.network"] + cls.ItSite = cls.env["itm.site"] + cls.Partner = cls.env["res.partner"] + + cls.defaultSite = cls.ItSite.create({"name": "site"}) + cls.defaultNetwork = cls.SiteNetwork.create( + { + "name": "local.lan", + "subnet": "192.168.0", + "netmask": "255.255.255.0", + "site_id": cls.defaultSite.id, + } + ) + cls.defaultPartner = cls.Partner.create( + { + "name": "Partner A", + "email": "a@example.org", + } + ) + + def create_equipment(self, name, partner=False, site=False): + if not partner: + partner = self.defaultPartner + if not site: + site = self.defaultSite + return self.Equipment.create( + { + "name": name, + "partner_id": partner.id, + "site_id": site.id, + } + ) + + def test_ip_dhcp_switch(self): + static_ip = "192.168.0.1" + dhcp_ip = "192.168.0.2" + server = self.create_equipment("My Server") + iface = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:00", static_ip, dhcp_ip, False + ) + + self.assertTrue( + iface.static_ipv4_id, "The network interface has a " "static IP address" + ) + self.assertEqual( + iface.display_ipv4, + static_ip, + "When 'use_dhcp' is NOT set the Static IP is displayed", + ) + + iface.use_dhcp4 = True + self.assertEqual( + iface.display_ipv4, + dhcp_ip, + "When 'use_dhcp' is set the DHCP IP is displayed", + ) + + def test_ip_no_static(self): + dhcp_ip = "192.168.0.1" + static_ip = False + server = self.create_equipment("My Server") + iface = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:00", static_ip, dhcp_ip, False + ) + + self.assertTrue( + iface.dhcp_ipv4_id, "The DHCP network interface has an IP address" + ) + self.assertFalse( + iface.static_ipv4_id, "The static interface does NOT have " "an IP address" + ) + + def test_ip_no_dhcp(self): + static_ip = "192.168.0.1" + dhcp_ip = False + server = self.create_equipment("My Server") + iface = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:00", static_ip, dhcp_ip, False + ) + + self.assertTrue( + iface.static_ipv4_id, "The network interface has a " "static IP address" + ) + self.assertFalse( + iface.dhcp_ipv4_id, "The DHCP interface does NOT have " "an IP address" + ) + + def test_equipment_ip4_addresses(self): + lan1 = "192.168.0.1" + lan2 = "192.168.1.2" + server = self.create_equipment("My Server") + iface1 = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:00", lan1, False, False + ) + iface2 = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:01", lan2, False, False + ) + + self.assertIn( + iface1.static_ipv4_id, + server.ip4_ids, + "The IP of the first interface is in the server's list of " "ip addresses", + ) + self.assertIn( + iface2.static_ipv4_id, + server.ip4_ids, + "The IP of the second interface is in the server's " "list of ip addresses", + ) + + def test_equipment_change_ip4_00(self): + lan1 = "192.168.0.1" + server = self.create_equipment("My Server") + iface1 = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:00", lan1, False, False + ) + + self.assertIn( + iface1.static_ipv4_id, + server.ip4_ids, + "The IP of the interface is in the server's list of ip addresses", + ) + + ip4 = self.NetworkIp4.create( + {"name": "10.250.250.250", "network_id": self.defaultNetwork.id} + ) + iface1.static_ipv4_id = ip4 + self.assertIn( + ip4, + server.ip4_ids, + "The interfaces new IP is in the server's list of ip addresses", + ) + + def test_equipment_change_ip4_01(self): + lan1 = "192.168.0.1" + server = self.create_equipment("My Server") + iface1 = server.add_ip4_network_interface( + "Lan", self.defaultNetwork, "00:00:00:00:00:00", lan1, False, False + ) + + self.assertEqual( + len(server.ip4_ids), 1, "There is already one IP in the IP4 list" + ) + + ip4 = self.NetworkIp4.create( + {"name": "10.250.250.250", "network_id": self.defaultNetwork.id} + ) + iface1.dhcp_ipv4_id = ip4 + self.assertIn( + iface1.static_ipv4_id, + server.ip4_ids, + "The IP of the interface is in the server's list of ip addresses", + ) + self.assertIn( + ip4, + server.ip4_ids, + "The interfaces new IP is in the server's list of ip addresses", + ) diff --git a/itm/tests/test_network.py b/itm/tests/test_network.py new file mode 100644 index 0000000..be6d88d --- /dev/null +++ b/itm/tests/test_network.py @@ -0,0 +1,57 @@ +# Copyright (C) 2022 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests import common + + +class TestEquipment(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.Equipment = cls.env["itm.equipment"] + cls.NetworkIp4 = cls.env["itm.site.network.ip4"] + cls.SiteNetwork = cls.env["itm.site.network"] + + def test_ip_in_multiple_networks(self): + net1 = self.SiteNetwork.create( + { + "name": "local.lan", + "subnet": "192.168.0", + "netmask": "255.255.255.0", + } + ) + net2 = self.SiteNetwork.create( + { + "name": "remote.lan", + "subnet": "192.168.0", + "netmask": "255.255.255.0", + } + ) + ip1 = self.NetworkIp4.create({"name": "192.168.0.1", "network_id": net1.id}) + ip2 = self.NetworkIp4.create({"name": "192.168.0.1", "network_id": net2.id}) + + self.assertEqual(ip1.network_id, net1, "First IP is in first network") + self.assertEqual(ip2.network_id, net2, "Second IP is in second network") + + def test_automatic_network_id(self): + net1 = self.SiteNetwork.create( + { + "name": "local.lan", + "subnet": "192.168.0", + "netmask": "255.255.255.0", + } + ) + self.SiteNetwork.create( + { + "name": "remote.lan", + "subnet": "192.168.0", + "netmask": "255.255.255.0", + } + ) + ip1 = self.NetworkIp4.with_context(default_network_id=net1.id).create( + {"name": "192.168.0.1"} + ) + self.assertEqual( + ip1.network_id, net1, "The network from the context is auto-assigned" + ) diff --git a/itm/tests/test_worklog.py b/itm/tests/test_worklog.py new file mode 100644 index 0000000..14cd3ae --- /dev/null +++ b/itm/tests/test_worklog.py @@ -0,0 +1,39 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo.tests import common + + +class TestEquipmentComponent(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.Equipment = cls.env["itm.equipment"] + cls.ItSite = cls.env["itm.site"] + cls.Partner = cls.env["res.partner"] + cls.Log = cls.env["itm.equipment.worklog"] + + cls.defaultSite = cls.ItSite.create({"name": "site"}) + cls.defaultPartner = cls.Partner.create( + { + "name": "Partner A", + "email": "a@example.org", + } + ) + cls.equipment = cls.Equipment.create( + { + "name": "My Equipment", + "partner_id": cls.defaultPartner.id, + "site_id": cls.defaultSite.id, + } + ) + + def test_fix_issue17(self): + """Creating worklog entry doesn't cause an exception""" + + try: + self.Log.default_get(["user_id"]) + except AttributeError: + self.fail("Unexpected failure") diff --git a/itm/views/access_view.xml b/itm/views/access_view.xml new file mode 100644 index 0000000..695e5a9 --- /dev/null +++ b/itm/views/access_view.xml @@ -0,0 +1,196 @@ + + + + + + + itm.access.tree + itm.access + + + + + + + + + + + + itm.access.form + itm.access + +
    + + + +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + + + itm.access.search + itm.access + + + + + + + + + + + + + + + + + + + + + + Credentials + itm.access + list,form + + + + +
    diff --git a/itm/views/application_license_view.xml b/itm/views/application_license_view.xml new file mode 100644 index 0000000..8213cfe --- /dev/null +++ b/itm/views/application_license_view.xml @@ -0,0 +1,61 @@ + + + + + + + itm.application.license.form + itm.application.license + +
    + + + + + + +
    +
    +
    + + + + itm.application.license.tree + itm.application.license + + + + + + + + + Licenses + itm.application.license + list,form + + + + +
    diff --git a/itm/views/application_view.xml b/itm/views/application_view.xml new file mode 100644 index 0000000..13722ae --- /dev/null +++ b/itm/views/application_view.xml @@ -0,0 +1,186 @@ + + + + + + + itm.application.tree + itm.application + + + + + + + + + + + + itm.application.form + itm.application + +
    + +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + itm.application.search + itm.application + + + + + + + + + + + + + + + + + + + + Applications + itm.application + list,form + + + + +
    diff --git a/itm/views/backup_view.xml b/itm/views/backup_view.xml new file mode 100644 index 0000000..92ebb2c --- /dev/null +++ b/itm/views/backup_view.xml @@ -0,0 +1,164 @@ + + + + + + + itm.backup.tree + itm.backup + + + + + + + + + + + + + + + + itm.backup.form + itm.backup + +
    + +
    +
    +
    +

    + +

    +
    +
    +

    + +

    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + itm.backup.search + itm.backup + + + + + + + + + + + + + + + + + + + + + + + Backups + itm.backup + list,form + + + + +
    diff --git a/itm/views/brand_view.xml b/itm/views/brand_view.xml new file mode 100644 index 0000000..82b6142 --- /dev/null +++ b/itm/views/brand_view.xml @@ -0,0 +1,49 @@ + + + + + + itm.equipment.brand.tree + itm.equipment.brand + + + + + + + + + + + + + itm.equipment.brand.form + itm.equipment.brand + +
    + + + + + + + + +
    +
    +
    + + + Brands + itm.equipment.brand + list,form + + + + +
    diff --git a/itm/views/component_view.xml b/itm/views/component_view.xml new file mode 100644 index 0000000..24a93ab --- /dev/null +++ b/itm/views/component_view.xml @@ -0,0 +1,34 @@ + + + + + + Products + product.product + list,form + + + + + diff --git a/itm/views/equipment_component_view.xml b/itm/views/equipment_component_view.xml new file mode 100644 index 0000000..65454be --- /dev/null +++ b/itm/views/equipment_component_view.xml @@ -0,0 +1,449 @@ + + + + + + + + + ITM Component Search + itm.equipment.component + + + + + + + + + + + + + + + + + + + + ITM Component Tree View + itm.equipment.component + + + + + + + + + + + + + ITM Component Form View + itm.equipment.component + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + + + Components + itm.equipment.component + list,form + + + + + + + ITM Component Type List View + itm.equipment.component.type + + + + + + + + + + ITM Component Type Form View + itm.equipment.component.type + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + + + Component Types + itm.equipment.component.type + list,form + + + + + + + ITM Component Specification Tree View + itm.equipment.component.specification + + + + + + + + + + + + + ITM Component Specification Form View + itm.equipment.component.specification + +
    + + + + + + + + + + + + +
    +
    +
    + + + + + ITM Component Specification Selector Tree View + itm.equipment.component.specification.selector + + + + + + + + + + + ITM Component Specification Selector Form View + itm.equipment.component.specification.selector + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + Specification Selectors + itm.equipment.component.specification.selector + list,form + + + + + + + ITM Specification Key Tree View + itm.equipment.component.specification.key + + + + + + + + + + + ITM Specification Key Form View + itm.equipment.component.specification.key + +
    + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + + + Specification Keys + itm.equipment.component.specification.key + list,form + + + + + + + ITM Component Specification Value Search + itm.equipment.component.specification.value + + + + + + + + + + + + + + + + ITM Specification Value List View + itm.equipment.component.specification.value + + + + + + + + + + ITM Specification Value Form View + itm.equipment.component.specification.value + +
    + + + + + + + + + + + +
    +
    +
    + + + Specification Values + itm.equipment.component.specification.value + list,form + + + +
    diff --git a/itm/views/equipment_function_view.xml b/itm/views/equipment_function_view.xml new file mode 100644 index 0000000..8bdc9b8 --- /dev/null +++ b/itm/views/equipment_function_view.xml @@ -0,0 +1,65 @@ + + + + + + + itm.equipment.function.form + itm.equipment.function + +
    + +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    + + + + itm.equipment.function.tree + itm.equipment.function + + + + + + + + + Functions + itm.equipment.function + list,form + + + + +
    diff --git a/itm/views/equipment_mapping_view.xml b/itm/views/equipment_mapping_view.xml new file mode 100644 index 0000000..e128080 --- /dev/null +++ b/itm/views/equipment_mapping_view.xml @@ -0,0 +1,70 @@ + + + + + + + itm.equipment.mapping.form + itm.equipment.mapping + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + itm.equipment.mapping.tree + itm.equipment.mapping + + + + + + + + + diff --git a/itm/views/equipment_network_view.xml b/itm/views/equipment_network_view.xml new file mode 100644 index 0000000..15fe227 --- /dev/null +++ b/itm/views/equipment_network_view.xml @@ -0,0 +1,63 @@ + + + + + + + itm.equipment.network.form + itm.equipment.network + +
    + + + + + + + + + + + +
    +
    + + + + itm.equipment.network.tree + itm.equipment.network + + + + + + + + + + + + + +
    diff --git a/itm/views/equipment_partition_view.xml b/itm/views/equipment_partition_view.xml new file mode 100644 index 0000000..8d02ac6 --- /dev/null +++ b/itm/views/equipment_partition_view.xml @@ -0,0 +1,60 @@ + + + + + + + + + itm.equipment.partition.form + itm.equipment.partition + +
    + + + + + + + + + + + + +
    +
    +
    + + + + itm.equipment.partition.tree + itm.equipment.partition + + + + + + + + + + + +
    diff --git a/itm/views/equipment_type_view.xml b/itm/views/equipment_type_view.xml new file mode 100644 index 0000000..ceb8d07 --- /dev/null +++ b/itm/views/equipment_type_view.xml @@ -0,0 +1,73 @@ + + + + + itm.equipment.type.search + itm.equipment.type + + + + + + + + + + + + itm.equipment.type.form + itm.equipment.type + +
    + + + + + + + + + + + + + +
    +
    +
    + + + itm.equipment.type.tree + itm.equipment.type + + + + + + + + + + + Asset Type + itm.equipment.type + list,form + + + + +
    diff --git a/itm/views/equipment_view.xml b/itm/views/equipment_view.xml new file mode 100644 index 0000000..b3eeb60 --- /dev/null +++ b/itm/views/equipment_view.xml @@ -0,0 +1,598 @@ + + + + + + + itm.access + Credentials + list,form + {'search_default_equipment_id': id } + + + + itm.equipment + Guests + list,form + + { + 'search_default_virtual_parent_id': id, + 'search_default_type_virtual': 1, + } + + + + + itm.backup + Backups + list,form + {'search_default_equipment_id': id } + + + + itm.equipment.component + Components + list,form + {'search_default_equipment_id': id } + + + + + itm.equipment.tree + itm.equipment + + + + + + + + + + + + + + + + + + + itm.equipment.form + itm.equipment + +
    +
    + +
    + +
    + + + + +
    + + + +
    +
    +
    +

    + +

    +
    +
    +

    + +

    +
    +
    +

    + +

    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + + + itm.equipment.search + itm.equipment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IT Assets + itm.equipment + list,form + + + + +
    diff --git a/itm/views/equipment_worklog_view.xml b/itm/views/equipment_worklog_view.xml new file mode 100644 index 0000000..e2a3a09 --- /dev/null +++ b/itm/views/equipment_worklog_view.xml @@ -0,0 +1,53 @@ + + + + + + + itm.equipment.worklog.form + itm.equipment.worklog + +
    + + + + + + + + + + +
    + + + + itm.equipment.worklog.tree + itm.equipment.worklog + + + + + + + + + + +
    diff --git a/itm/views/it_menu_view.xml b/itm/views/it_menu_view.xml new file mode 100644 index 0000000..1ce74c3 --- /dev/null +++ b/itm/views/it_menu_view.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + diff --git a/itm/views/partner_view.xml b/itm/views/partner_view.xml new file mode 100644 index 0000000..072d409 --- /dev/null +++ b/itm/views/partner_view.xml @@ -0,0 +1,127 @@ + + + + + + + Customers + res.partner + list,form + {"search_default_manage_it":1, "default_manage_it":1} + + + + + + + itm.equipment + Assets + list,form + {'search_default_partner_id': id } + + + + itm.access + Credentials + list,form + {'search_default_partner_id': id } + + + + itm.backup + Backup + list,form + {'search_default_partner_id': id } + + + + itm.partner.view + res.partner + + + + + + + + + + itm.partner.view + res.partner + + + + + + + + + + + + + + itm.partner.filter + res.partner + + + + + + + + + diff --git a/itm/views/service_ad_view.xml b/itm/views/service_ad_view.xml new file mode 100644 index 0000000..164991f --- /dev/null +++ b/itm/views/service_ad_view.xml @@ -0,0 +1,255 @@ + + + + + itm.service.ad.search + itm.service.ad + + + + + + + + + + + + + + + + + + + itm.service.ad.tree + itm.service.ad + + + + + + + + + + + + + + itm.service.ad.form + itm.service.ad + +
    + + + +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + + + + Create Credential + itm.wizard.credential + form + + new + + { + 'default_equipment_id': ad_id.equipment_id.id, + 'default_site_id': ad_id.site_id.id, + 'default_partner_id': ad_id.site_id.partner_id.id, + 'default_name': logon_name, + } + + + + + itm.service.ad.object.form + itm.service.ad.object + +
    + + + +
    + +
    +
    +
    +
    +

    + + + +

    +
    + + + + + + + + + + + +
    +
    +
    +
    + + + Active Directory + itm.service.ad + list,form + + + + Active Directory Objects + itm.service.ad.object + list,form + + + + + + +
    diff --git a/itm/views/service_dhcp_view.xml b/itm/views/service_dhcp_view.xml new file mode 100644 index 0000000..d535782 --- /dev/null +++ b/itm/views/service_dhcp_view.xml @@ -0,0 +1,78 @@ + + + + + itm.service.dhcp4.tree + itm.service.dhcp4 + + + + + + + + + + + + + + + + itm.service.dhcp4.form + itm.service.dhcp4 + +
    + +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + DHCP + itm.service.dhcp4 + list,form + + + + +
    diff --git a/itm/views/service_wireless_view.xml b/itm/views/service_wireless_view.xml new file mode 100644 index 0000000..086e239 --- /dev/null +++ b/itm/views/service_wireless_view.xml @@ -0,0 +1,71 @@ + + + + + itm.service.wireless.tree + itm.service.wireless + + + + + + + + + + + itm.service.wireless.form + itm.service.wireless + +
    + +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + Wireless + itm.service.wireless + list,form + + + + +
    diff --git a/itm/views/site_view.xml b/itm/views/site_view.xml new file mode 100644 index 0000000..92fadd9 --- /dev/null +++ b/itm/views/site_view.xml @@ -0,0 +1,217 @@ + + + + + + itm.equipment + Assets + list,form + {'search_default_site_id': id } + + + itm.access + Credentials + list,form + {'search_default_site_id': id } + + + + itm.site.search + itm.site + + + + + + + + + + + itm.site.tree + itm.site + + + + + + + + + + + + itm.site.form + itm.site + +
    + +
    + + +
    + + +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + + + Sites + itm.site + list,form + + + + itm.site.network.tree + itm.site.network + + + + + + + + + + + + + + itm.site.network.form + itm.site.network + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + Networks + itm.site.network + list,form + + + + + + + + +
    diff --git a/itm/wizard/__init__.py b/itm/wizard/__init__.py new file mode 100644 index 0000000..1b9b221 --- /dev/null +++ b/itm/wizard/__init__.py @@ -0,0 +1,5 @@ +# Copyright (C) 2021 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +# flake8: noqa +from . import create_credential diff --git a/itm/wizard/create_credential.py b/itm/wizard/create_credential.py new file mode 100644 index 0000000..6fa90d2 --- /dev/null +++ b/itm/wizard/create_credential.py @@ -0,0 +1,79 @@ +# Copyright (C) 2021,2022 TREVI Software +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import api, fields, models + + +class NewCredential(models.TransientModel): + _name = "itm.wizard.credential" + _description = "Create New Credential Wizard" + + @api.model + def _get_aduser(self): + import logging + + _l = logging.getLogger(__name__) + _l.warning("_get_aduser: %s", self.env.context.get("id")) + _id = self.env.context.get("id") + if _id: + ad = self.env["itm.service.ad.object"].browse(_id) + return ad.id + return False + + name = fields.Char(required=True) + password = fields.Char(required=True) + aduser_id = fields.Many2one("itm.service.ad.object", "AD User", default=_get_aduser) + equipment_id = fields.Many2one("itm.equipment", "Asset") + ad_id = fields.Many2one("itm.service.ad", "Active Directory") + site_id = fields.Many2one("itm.site", "Site") + partner_id = fields.Many2one("res.partner", "Partner") + use_random = fields.Boolean("Random password") + + @api.onchange("aduser_id") + def onchange_aduser(self): + self.ad_id = False + self.site_id = False + self.partner_id = False + self.equipment_id = False + if self.aduser_id: + if self.aduser_id.ad_id: + self.ad_id = self.aduser_id.ad_id + if self.aduser_id.ad_id.site_id: + self.site_id = self.aduser_id.ad_id.site_id + if self.aduser_id.ad_id.partner_id: + self.partner_id = self.aduser_id.ad_id.partner_id + if self.aduser_id.ad_id.equipment_id: + self.equipment_id = self.aduser_id.ad_id.equipment_id + + @api.onchange("use_random") + def onchange_use_random(self): + itm_access = self.env["itm.access"] + if self.use_random: + self.password = itm_access.get_random_string() + + def create_cred(self): + # Remove the password so it doesn't get accidentaly written to the database. + # + plaintext = self.password + self.password = "" + + cred_vals = { + "name": self.name, + "password": plaintext, + "site_id": self.site_id.id, + "partner_id": self.partner_id.id, + "equipment_id": self.equipment_id.id, + } + cred = self.env["itm.access"].create(cred_vals) + self.aduser_id.access_id = cred + + @api.model_create_multi + def create(self, lst): + # Remove the password from the dictionary so it doesn't + # get accidentaly written to the database. + # + for _k, v in lst: + v.update({"password": ""}) + + return super().create(lst) diff --git a/itm/wizard/create_credential_view.xml b/itm/wizard/create_credential_view.xml new file mode 100644 index 0000000..b7528ea --- /dev/null +++ b/itm/wizard/create_credential_view.xml @@ -0,0 +1,59 @@ + + + + + itm.wizard.credential.form + itm.wizard.credential + +
    +
    +
    +
    +

    + +

    +
    + + + + + + + + + + + + +
    +
    +
    +
    +
    + + + Create New Credential + itm.wizard.credential + form + new + + +
    diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..368c5c2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +cryptography