57 Commits

Author SHA1 Message Date
Stéphan Sainléger
ab887e47f6 [MIG] partner_geolocalize_usability: migrate to 18.0 2025-12-16 23:13:30 +01:00
Stéphan Sainléger
9ac67a2788 [MIG] initiate branch 18.0 2025-12-16 23:12:36 +01:00
Boris Gallet
721daadbb2 [ADD] partner_portal_extra_links: add visio_url and wiki_homepage_url to portal
Some checks failed
pre-commit / pre-commit (pull_request) Failing after 1m28s
2025-10-21 17:15:59 +02:00
c3d419c67e Sync config from odoo-elabore-ci:16.0
Some checks failed
pre-commit / pre-commit (pull_request) Failing after 7m41s
2025-09-17 13:39:48 +00:00
8f46bfc892 [ADD]partner_profiles:add standalone contact in domain of groupby 2025-05-12 17:53:05 +02:00
fa0a7aab09 [FIX]partner_complementary_data_view:remove is_main_profile because it requires a dependency on partner_profiles 2025-05-07 11:21:09 +02:00
Stéphan Sainléger
e6dbf49a7f [FIX] partner_gogocarto_export_api: add missing dependency on server_action_mass_edit 2025-04-01 22:53:45 +02:00
Stéphan Sainléger
4642927ce0 [NEW] partner_phone_email_form_widget: create add-on 2025-03-23 11:59:08 +01:00
b42fc550b9 [IMP]partner_gogocarto_export_api: add mass edit in_gogocarto field 2025-02-28 12:23:15 +01:00
43ae6f7d2c [IMP]partner_profiles:add action server sync pub/admin datas in mass 2025-02-28 12:23:15 +01:00
b93d914317 [IMP]partner_profiles:add quick filters for admin, public and fonction profiles 2025-02-28 12:23:15 +01:00
Stéphan Sainléger
45a2e0bdaf [FIX] partner_profile: remove profile data for non contact partner 2025-01-09 15:25:46 +01:00
Stéphan Sainléger
423262d190 [NEW] partner_complementary_data_view: create add-on 2025-01-09 14:06:10 +01:00
clementthomas
d43983212c [IMP] add gitignore 2024-11-07 10:11:28 +01:00
clementthomas
d1a20167ad [FIX] partner-comcom: many2one instead of many2many 2024-11-05 16:22:08 +01:00
clementthomas
d3257c857b [NEW] partner_skills 2024-10-28 10:34:52 +01:00
clementthomas
5b9172ef19 [NEW] l10n_fr_partner_comcom 2024-10-16 15:05:54 +02:00
4de88acf8f [FIX]partner_profiles:avoid automatic creation of society type public profile 2024-09-16 14:51:26 +02:00
5f6a82fc0f [IMP]partner_gogocarto_export_api:allow export htlm fields 2024-03-26 11:14:56 +01:00
Boris Gallet
142a0342c9 [MIG] partner_profiles_gogocarto_export : Migration to 16.0 2024-03-22 10:08:12 +01:00
Boris Gallet
70694c19de [MIG] partner_gogocarto_export_api : Migration to 16.0 2024-03-22 10:08:12 +01:00
Boris Gallet
1c6f4a3d4c [MIG] partner_favorite : Migration to 16.0 2024-03-22 10:08:12 +01:00
Boris Gallet
f16f22fb34 [MIG] partner_profiles_geolocalize_usability: Migration to 16.0 2024-03-22 10:08:12 +01:00
Boris Gallet
e8e08c466e [MIG] partner_geolocalize_usability: Migration to 16.0 2024-03-21 17:05:35 +01:00
Boris Gallet
faf5507f26 [MIG] partner_profiles_portal : Migration to 16.0 2024-03-21 16:55:55 +01:00
Boris Gallet
df455303fa [MIG] partner_profiles: Migration to 16.0 2024-03-21 16:12:57 +01:00
clementthomas
e03fe31c86 remove modules in v12 2023-09-11 17:39:11 +02:00
Stéphan Sainléger
9325c02b53 [I18N] partner_profiles_portal: improve french translations 2023-06-28 16:38:18 +02:00
Stéphan Sainléger
cdcea7ec60 [IMP] partner_profiles: apply migration only on contact type partner 2023-06-28 16:38:18 +02:00
Stéphan Sainléger
d51b9b6d08 [IMP] partner_profiles_portal: add required asterisk in portal forms 2023-06-28 16:38:18 +02:00
Stéphan Sainléger
783faf9f61 [IMP] partner_profiles_portal: remove position profile frm child_ids 2023-06-28 16:38:18 +02:00
Stéphan Sainléger
49f73b86a7 [IMP] partner_profiles: remove position profiles from child_ids 2023-06-28 16:38:18 +02:00
Stéphan Sainléger
0f10de644e [IMP] partner_profiles_portal: improve /my/account name field label 2023-06-28 16:38:18 +02:00
Stéphan Sainléger
8d72f56edc [I18N] partner_profiles_portal: modify profiles french translations
"Profil principal" -> "Fiche administrative"
"Profil public" -> "Coordonnées publiques"
"Profil position" -> "Fonction"
2023-06-28 16:38:18 +02:00
Stéphan Sainléger
124625f74c [I18N] partner_profiles: modify profile name french translations
"Profil principal" -> "Fiche administrative"
"Profil public" -> "Coordonnées publiques"
"Profil position" -> "Fonction"
2023-06-28 16:38:18 +02:00
Stéphan Sainléger
072cdf8978 [FIX] partner_profiles_portal: fix portal boolean fields handling 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
29af98aac3 [IMP] partner_profiles: sync active field values between profiles
Change in main profile is synchronized in public and position profiles.
Change in public profile is sy,chronized in main and position profiles.
Change in position profile is NOT synchronized in main and public profiles.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
cda7190cff [IMP] partner_profiles: add profile in partner kanban view 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
43d21befbf [IMP] partner_profiles_portal: add positions details in portal
Adds several portal views to consult all the positions of a structure,
and their details.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
95ddef62c3 [IMP] partner_profiles_portal: add website page edition slots 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
019019aa93 [IMP] partner_profiles: clarify position profiles display
separates the notebook pages of the child_ids and the position
profiles in both company and individual partner form views.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
9438f19140 [IMP] partner_profiles_portal: refactor position profil creation 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
a4c1c467c5 [IMP] partner_profiles: refactoring of position profile creation 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
379b598754 [IMP] partner_profiles: prevent company type edit in several cases
Prevents the modification of the company type of res.partner:
- if partner is a public or a position profile
- if the partner has position profiles attached

Also synchronize the company type between main and public profiles.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
c95d20d7a1 [I18N] partner_profiles_portal: update french translations 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
e994a2c407 [I18N] partner_profiles: update french translations 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
0c81c36d30 [IMP] partner_profiles_portal: hide My structures button for company users 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
bba6775f07 [IMP] partner_profiles_portal: add odoo user in partner form view 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
bf5eeb0d32 [IMP] partner_profiles: remove useless fields in position form view 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
859d672633 [IMP] partner_profiles_portal: new portal structures data management
refactors the way a portal user can edit the data of the structures he
is affiliated with.
All main, public and position profiles data are gathered in one
"structure" form.
Adds several navigation improvement (back to structures list,
validation message, ...)
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
5c16620fe6 [IMP] partner_profiles_portal: refactoring of user information
Merge the main and public information edition in /my/account portal
page.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
4401cfab79 [IMP] partner_profiles: remove useless fields in public profile view
Hides from the partner public form view the fields and data not
considered as relevant for public profile. The public profile aims to
protect the contact data, but not to replace the other ones which are
considered as "administrative" data.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
2e63b1216f [IMP] partner_profiles: delete profiles when main partner deleted
When a main partner is unlinked, all the linked profiles (public
profile and position profiles) are deleted.
2023-06-27 17:31:24 +02:00
Stéphan Sainléger
6e227a83d4 [IMP] partner_profiles: filter public profiles in name_search answer 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
2162312fb1 [FIX] partner_profiles: add missing add-on dependency 2023-06-27 17:31:24 +02:00
Stéphan Sainléger
8ccfb58a69 Merge pull request #3 from Alusage/12.0_nj_better_import_process
[ADD] permit contact import from files with parent_id
2023-02-14 15:41:00 +01:00
Nicolas JEUDY
8b12b04b38 [ADD] permit contact import from files with parent_id 2023-02-14 15:33:20 +01:00
48 changed files with 892 additions and 2118 deletions

20
.editorconfig Normal file
View File

@@ -0,0 +1,20 @@
# Configuration for known file extensions
[*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{json,yml,yaml,rst,md}]
indent_size = 2
# Do not configure editor for libs and autogenerated content
[{*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst}]
charset = unset
end_of_line = unset
indent_size = unset
indent_style = unset
insert_final_newline = false
trim_trailing_whitespace = false

188
.eslintrc.yml Normal file
View File

@@ -0,0 +1,188 @@
env:
browser: true
es6: true
# See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449
parserOptions:
ecmaVersion: 2019
overrides:
- files:
- "**/*.esm.js"
parserOptions:
sourceType: module
# Globals available in Odoo that shouldn't produce errorings
globals:
_: readonly
$: readonly
fuzzy: readonly
jQuery: readonly
moment: readonly
odoo: readonly
openerp: readonly
owl: readonly
luxon: readonly
# Styling is handled by Prettier, so we only need to enable AST rules;
# see https://github.com/OCA/maintainer-quality-tools/pull/618#issuecomment-558576890
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

View File

@@ -0,0 +1,42 @@
name: pre-commit
on:
pull_request:
branches:
- "16.0*"
jobs:
pre-commit:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Get python version
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
# - uses: actions/cache@v4
# with:
# path: ~/.cache/pre-commit
# key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit
run: pre-commit run --all-files --show-diff-on-failure --color=always
env:
# Consider valid a PR that changes README fragments but doesn't
# change the README.rst file itself. It's not really a problem
# because the bot will update it anyway after merge. This way, we
# lower the barrier for functional contributors that want to fix the
# readme fragments, while still letting developers get README
# auto-generated (which also helps functionals when using runboat).
# DOCS https://pre-commit.com/#temporarily-disabling-hooks
SKIP: oca-gen-addon-readme
- name: Check that all files generated by pre-commit are in git
run: |
newfiles="$(git ls-files --others --exclude-from=.gitignore)"
if [ "$newfiles" != "" ] ; then
echo "Please check-in the following files:"
echo "$newfiles"
exit 1
fi

75
.gitignore vendored Normal file
View File

@@ -0,0 +1,75 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
/.venv
/.pytest_cache
/.ruff_cache
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
*.eggs
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Pycharm
.idea
# Eclipse
.settings
# Visual Studio cache/options directory
.vs/
.vscode
# OSX Files
.DS_Store
# Django stuff:
*.log
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Sphinx documentation
docs/_build/
# Backup files
*~
*.swp
# OCA rules
!static/lib/

150
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,150 @@
exclude: |
(?x)
# NOT INSTALLABLE ADDONS
# END NOT INSTALLABLE ADDONS
# Files and folders generated by bots, to avoid loops
^setup/|/static/description/index\.html$|
# We don't want to mess with tool-generated files
.svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/|^eslint.config.cjs|^prettier.config.cjs|
# Maybe reactivate this when all README files include prettier ignore tags?
^README\.md$|
# Library files can have extraneous formatting (even minimized)
/static/(src/)?lib/|
# Repos using Sphinx to generate docs don't need prettying
^docs/_templates/.*\.html$|
# Don't bother non-technical authors with formatting issues in docs
readme/.*\.(rst|md)$|
# Ignore build and dist directories in addons
/build/|/dist/|
# Ignore test files in addons
/tests/samples/.*|
# You don't usually want a bot to modify your legal texts
(LICENSE.*|COPYING.*)
default_language_version:
python: python3
node: "16.17.0"
repos:
- repo: local
hooks:
# These files are most likely copier diff rejection junks; if found,
# review them manually, fix the problem (if needed) and remove them
- id: forbidden-files
name: forbidden files
entry: found forbidden files; remove them
language: fail
files: "\\.rej$"
- id: en-po-files
name: en.po files cannot exist
entry: found a en.po file
language: fail
files: '[a-zA-Z0-9_]*/i18n/en\.po$'
- repo: https://github.com/oca/maintainer-tools
rev: f9b919b9868143135a9c9cb03021089cabba8223
hooks:
# update the NOT INSTALLABLE ADDONS section above
- id: oca-update-pre-commit-excluded-addons
- id: oca-fix-manifest-website
entry:
bash -c 'oca-fix-manifest-website "https://git.elabore.coop/elabore/$(basename
$(git rev-parse --show-toplevel))"'
- id: oca-gen-addon-readme
entry:
bash -c 'oca-gen-addon-readme
--addons-dir=.
--branch=$(git symbolic-ref
refs/remotes/origin/HEAD | sed "s@^refs/remotes/origin/@@")
--repo-name=$(basename $(git rev-parse --show-toplevel))
--org-name="Elabore"
--if-source-changed --keep-source-digest'
- repo: https://github.com/OCA/odoo-pre-commit-hooks
rev: v0.1.4
hooks:
- id: oca-checks-odoo-module
- id: oca-checks-po
args:
- --disable=po-pretty-format
- repo: local
hooks:
- id: prettier
name: prettier (with plugin-xml)
entry: prettier
args:
- --write
- --list-different
- --ignore-unknown
types: [text]
files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$
language: node
additional_dependencies:
- "prettier@2.7.1"
- "@prettier/plugin-xml@2.2.0"
- repo: local
hooks:
- id: eslint
name: eslint
entry: eslint
args:
- --color
- --fix
verbose: true
types: [javascript]
language: node
additional_dependencies:
- "eslint@8.24.0"
- "eslint-plugin-jsdoc@"
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
# exclude autogenerated files
exclude: /README\.rst$|\.pot?$
- id: end-of-file-fixer
# exclude autogenerated files
exclude: /README\.rst$|\.pot?$
- id: debug-statements
- id: fix-encoding-pragma
args: ["--remove"]
- id: check-case-conflict
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-merge-conflict
# exclude files where underlines are not distinguishable from merge conflicts
exclude: /README\.rst$|^docs/.*\.rst$
- id: check-symlinks
- id: check-xml
- id: mixed-line-ending
args: ["--fix=lf"]
- repo: https://github.com/PyCQA/docformatter
rev: v1.7.7
hooks:
- id: docformatter
args: [
"--in-place", # modify the files
"--recursive", # run on all the files
"--wrap-summaries",
"88", # max length of 1st line
"--wrap-descriptions",
"88", # max length of other lines
"--pre-summary-newline", # new line before a long summary
"--make-summary-multi-line", # force summary on multilines
]
additional_dependencies: ["tomli"] # if Python <3.11
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/OCA/pylint-odoo
rev: v9.1.3
hooks:
- id: pylint_odoo
name: pylint with optional checks
args:
- --rcfile=.pylintrc
- --exit-zero
verbose: true
- id: pylint_odoo
args:
- --rcfile=.pylintrc-mandatory

8
.prettierrc.yml Normal file
View File

@@ -0,0 +1,8 @@
# Defaults for all prettier-supported languages.
# Prettier will complete this with settings from .editorconfig file.
bracketSpacing: false
printWidth: 88
proseWrap: always
semi: true
trailingComma: "es5"
xmlWhitespaceSensitivity: "strict"

123
.pylintrc Normal file
View File

@@ -0,0 +1,123 @@
[MASTER]
load-plugins=pylint_odoo
score=n
[ODOOLINT]
readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst"
manifest-required-authors=Elabore
manifest-required-keys=license
manifest-deprecated-keys=description,active
license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3
valid-odoo-versions=16.0
[MESSAGES CONTROL]
disable=all
# This .pylintrc contains optional AND mandatory checks and is meant to be
# loaded in an IDE to have it check everything, in the hope this will make
# optional checks more visible to contributors who otherwise never look at a
# green travis to see optional checks that failed.
# .pylintrc-mandatory containing only mandatory checks is used the pre-commit
# config as a blocking check.
enable=anomalous-backslash-in-string,
api-one-deprecated,
api-one-multi-together,
assignment-from-none,
attribute-deprecated,
class-camelcase,
dangerous-default-value,
dangerous-view-replace-wo-priority,
development-status-allowed,
duplicate-id-csv,
duplicate-key,
duplicate-xml-fields,
duplicate-xml-record-id,
eval-referenced,
eval-used,
incoherent-interpreter-exec-perm,
license-allowed,
manifest-author-string,
manifest-deprecated-key,
manifest-required-author,
manifest-required-key,
manifest-version-format,
method-compute,
method-inverse,
method-required-super,
method-search,
openerp-exception-warning,
pointless-statement,
pointless-string-statement,
print-used,
redundant-keyword-arg,
redundant-modulename-xml,
reimported,
relative-import,
return-in-init,
rst-syntax-error,
sql-injection,
too-few-format-args,
translation-field,
translation-required,
unreachable,
use-vim-comment,
wrong-tabs-instead-of-spaces,
xml-syntax-error,
attribute-string-redundant,
character-not-valid-in-resource-link,
consider-merging-classes-inherited,
context-overridden,
create-user-wo-reset-password,
dangerous-filter-wo-user,
dangerous-qweb-replace-wo-priority,
deprecated-data-xml-node,
deprecated-openerp-xml-node,
duplicate-po-message-definition,
except-pass,
file-not-used,
invalid-commit,
manifest-maintainers-list,
missing-newline-extrafiles,
missing-readme,
missing-return,
odoo-addons-relative-import,
old-api7-method-defined,
po-msgstr-variables,
po-syntax-error,
renamed-field-parameter,
resource-not-exist,
str-format-used,
test-folder-imported,
translation-contains-variable,
translation-positional-used,
unnecessary-utf8-coding-comment,
website-manifest-key-not-valid-uri,
xml-attribute-translatable,
xml-deprecated-qweb-directive,
xml-deprecated-tree-attribute,
external-request-timeout,
# messages that do not cause the lint step to fail
consider-merging-classes-inherited,
create-user-wo-reset-password,
dangerous-filter-wo-user,
deprecated-module,
file-not-used,
invalid-commit,
missing-manifest-dependency,
missing-newline-extrafiles,
missing-readme,
no-utf8-coding-comment,
odoo-addons-relative-import,
old-api7-method-defined,
redefined-builtin,
too-complex,
unnecessary-utf8-coding-comment
[REPORTS]
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
output-format=colorized
reports=no

98
.pylintrc-mandatory Normal file
View File

@@ -0,0 +1,98 @@
[MASTER]
load-plugins=pylint_odoo
score=n
[ODOOLINT]
readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst"
manifest-required-authors=Elabore
manifest-required-keys=license
manifest-deprecated-keys=description,active
license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3
valid-odoo-versions=16.0
[MESSAGES CONTROL]
disable=all
enable=anomalous-backslash-in-string,
api-one-deprecated,
api-one-multi-together,
assignment-from-none,
attribute-deprecated,
class-camelcase,
dangerous-default-value,
dangerous-view-replace-wo-priority,
development-status-allowed,
duplicate-id-csv,
duplicate-key,
duplicate-xml-fields,
duplicate-xml-record-id,
eval-referenced,
eval-used,
incoherent-interpreter-exec-perm,
license-allowed,
manifest-author-string,
manifest-deprecated-key,
manifest-required-author,
manifest-required-key,
manifest-version-format,
method-compute,
method-inverse,
method-required-super,
method-search,
openerp-exception-warning,
pointless-statement,
pointless-string-statement,
print-used,
redundant-keyword-arg,
redundant-modulename-xml,
reimported,
relative-import,
return-in-init,
rst-syntax-error,
sql-injection,
too-few-format-args,
translation-field,
translation-required,
unreachable,
use-vim-comment,
wrong-tabs-instead-of-spaces,
xml-syntax-error,
attribute-string-redundant,
character-not-valid-in-resource-link,
consider-merging-classes-inherited,
context-overridden,
create-user-wo-reset-password,
dangerous-filter-wo-user,
dangerous-qweb-replace-wo-priority,
deprecated-data-xml-node,
deprecated-openerp-xml-node,
duplicate-po-message-definition,
except-pass,
file-not-used,
invalid-commit,
manifest-maintainers-list,
missing-newline-extrafiles,
missing-readme,
missing-return,
odoo-addons-relative-import,
old-api7-method-defined,
po-msgstr-variables,
po-syntax-error,
renamed-field-parameter,
resource-not-exist,
str-format-used,
test-folder-imported,
translation-contains-variable,
translation-positional-used,
unnecessary-utf8-coding-comment,
website-manifest-key-not-valid-uri,
xml-attribute-translatable,
xml-deprecated-qweb-directive,
xml-deprecated-tree-attribute,
external-request-timeout
[REPORTS]
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
output-format=colorized
reports=no

31
.ruff.toml Normal file
View File

@@ -0,0 +1,31 @@
target-version = "py310"
fix = true
[lint]
extend-select = [
"B",
"C90",
"E501", # line too long (default 88)
"I", # isort
"UP", # pyupgrade
]
extend-safe-fixes = ["UP008"]
exclude = ["setup/*"]
[format]
exclude = ["setup/*"]
[lint.per-file-ignores]
"__init__.py" = ["F401", "I001"] # ignore unused and unsorted imports in __init__.py
"__manifest__.py" = ["B018"] # useless expression
[lint.isort]
section-order = ["future", "standard-library", "third-party", "odoo", "odoo-addons", "first-party", "local-folder"]
[lint.isort.sections]
"odoo" = ["odoo"]
"odoo-addons" = ["odoo.addons"]
[lint.mccabe]
max-complexity = 16

View File

@@ -1,14 +1,27 @@
===============
partner_profiles_portal
===============
=============================
partner_geolocalize_usability
=============================
Provide portal pages and forms to manage partner's profiles from portal home space.
Brings several enhancements on geolocalize functionnalities
Installation
============
Use Odoo normal module installation procedure to install
``partner_profiles_portal``.
``partner_geolocalize_usability``.
Description
===========
This module allows:
- to block or not the edition of partner_latitude and partner_longitude fields in partner form view.
- to massively trigger the geolocalize function
It also modify the partner form vieww for a better understanding of the geolocation data.
Configuration
=============
No configuration needed.
Known issues / Roadmap
======================

View File

@@ -0,0 +1,4 @@
from . import models
# from . import controllers
# from . import wizard

View File

@@ -1,35 +1,27 @@
# Copyright 2022 Stéphan Sainléger (Elabore)
# Copyright 2023 Stéphan Sainléger (Elabore)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "partner_profiles",
"version": "12.0.1.0.5",
"name": "partner_geolocalize_usability",
"version": "18.0.1.0.0",
"author": "Elabore",
"website": "https://elabore.coop",
"maintainer": "Stéphan Sainléger",
"license": "AGPL-3",
"category": "Tools",
"summary": "Provide several profiles for one person.",
"summary": "Brings several enhancements on geolocalize functionnalities",
# any module necessary for this one to work correctly
"depends": [
"base",
"calendar",
"partner_contact_in_several_companies",
],
"qweb": [
# "static/src/xml/*.xml",
"base_geolocalize"
],
"qweb": [],
"external_dependencies": {
"python": [],
},
# always loaded
"data": [
"security/ir.model.access.csv",
"views/res_partner_view.xml",
"views/calendar_event_view.xml",
"views/partner_profile_view.xml",
"data/partner_profile_data.xml",
"data/res_partner_data.xml",
"views/res_partner.xml",
],
# only loaded in demonstration mode
"demo": [],
@@ -40,4 +32,4 @@
# and independently installed. Used for synergetic or glue modules.
"auto_install": False,
"application": False,
}
}

View File

@@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_geolocalize_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-09-12 13:48+0000\n"
"PO-Revision-Date: 2023-09-12 13:48+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_geolocalize_usability
#: model:ir.model,name:partner_geolocalize_usability.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_geolocalize_usability
#: model:ir.actions.server,name:partner_geolocalize_usability.geolocata_partner_action_server
#: model_terms:ir.ui.view,arch_db:partner_geolocalize_usability.partner_geolocalize_form_view
msgid "Geolocate"
msgstr "Géolocaliser"
#. module: partner_geolocalize_usability
#: model:ir.model.fields,field_description:partner_geolocalize_usability.field_res_partner__manual_geolocate
#: model:ir.model.fields,field_description:partner_geolocalize_usability.field_res_users__manual_geolocate
msgid "Geolocate yourself"
msgstr "Géolocaliser manuellement"
#. module: partner_geolocalize_usability
#: model_terms:ir.ui.view,arch_db:partner_geolocalize_usability.partner_geolocalize_form_view
msgid "Geolocation"
msgstr "Géolocalisation"

View File

@@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_geolocalize_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-09-12 13:50+0000\n"
"PO-Revision-Date: 2023-09-12 13:50+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_geolocalize_usability
#: model:ir.model,name:partner_geolocalize_usability.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_geolocalize_usability
#: model:ir.actions.server,name:partner_geolocalize_usability.geolocata_partner_action_server
#: model_terms:ir.ui.view,arch_db:partner_geolocalize_usability.partner_geolocalize_form_view
msgid "Geolocate"
msgstr ""
#. module: partner_geolocalize_usability
#: model:ir.model.fields,field_description:partner_geolocalize_usability.field_res_partner__manual_geolocate
#: model:ir.model.fields,field_description:partner_geolocalize_usability.field_res_users__manual_geolocate
msgid "Geolocate yourself"
msgstr ""
#. module: partner_geolocalize_usability
#: model_terms:ir.ui.view,arch_db:partner_geolocalize_usability.partner_geolocalize_form_view
msgid "Geolocation"
msgstr ""

View File

@@ -0,0 +1,2 @@
from . import res_partner

View File

@@ -0,0 +1,11 @@
from odoo import models, fields, api
class ResPartner(models.Model):
_inherit = 'res.partner'
manual_geolocate = fields.Boolean('Geolocate yourself')
def geo_localize(self):
partners = self.filtered(lambda a: a.manual_geolocate == False)
return super(ResPartner, partners).geo_localize()

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="geolocata_partner_action_server" model="ir.actions.server">
<field name="name">Geolocate</field>
<field name="model_id" ref="model_res_partner" />
<field
name="binding_model_id" ref="model_res_partner" />
<field name="state">code</field>
<field name="code">records.geo_localize() </field>
</record>
<record model="ir.ui.view" id="partner_geolocalize_form_view">
<field name="name">partner.geolocalize.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name='priority'>99</field>
<field name="arch" type="xml">
<xpath expr="//page[@name='geo_location']" position="replace">
<page name="geolocalize" string="Geolocation">
<group colspan="2" col="2">
<separator string="Geolocation" colspan="2" />
<field name="manual_geolocate" />
<button
string="Geolocate"
name="geo_localize"
colspan="2"
icon="fa-check"
type="object" attrs="{'invisible':[('manual_geolocate', '=', True)]}" />
<field name="partner_latitude" attrs="{'readonly':[('manual_geolocate', '=', False)]}" />
<field name="partner_longitude" attrs="{'readonly':[('manual_geolocate', '=', False)]}" />
</group>
</page>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,43 +0,0 @@
================
partner_profiles
================
Provide several profiles for one person.
Installation
============
Use Odoo normal module installation procedure to install
``partner_profiles``.
Known issues / Roadmap
======================
None yet.
Bug Tracker
===========
Bugs are tracked on `our issues website <https://github.com/elabore-coop/member-tools/issues>`_. In case of
trouble, please check there if your issue has already been
reported. If you spotted it first, help us smashing it by providing a
detailed and welcomed feedback.
Credits
=======
Contributors
------------
* Stéphan Sainléger
Funders
-------
The development of this module has been financially supported by:
* Elabore (https://elabore.coop)
Maintainer
----------
This module is maintained by Elabore.

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import models

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="partner_profile_main" model="partner.profile">
<field name="name">Main Profile</field>
<field name="ref">partner_profile_main</field>
</record>
<record id="partner_profile_public" model="partner.profile">
<field name="name">Public Profile</field>
<field name="ref">partner_profile_public</field>
</record>
<record id="partner_profile_position" model="partner.profile">
<field name="name">Position Profile</field>
<field name="ref">partner_profile_position</field>
</record>
</data>
</odoo>

View File

@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data noupdate="1">
<record id="ir_cron_generate_missing_public_profiles" model="ir.cron">
<field name="name">Partner: generate missing public profiles</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="state">code</field>
<field name="code">model._cron_generate_missing_public_profiles()</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active">0</field>
</record>
<record id="ir_cron_migration_partner_profiles" model="ir.cron">
<field name="name">Partner: Migration Standard Partners to Partners with Profiles</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="state">code</field>
<field name="code">
model._migration_create_pro_profiles(limit=200)
model._migration_person_without_parent(limit=200)
model._migration_person_with_parent_and_existing_main(limit=200)
model._migration_person_with_parent_not_existing_main(limit=200)
</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active">0</field>
</record>
</data>
</odoo>

View File

@@ -1,173 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_profiles
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-09 14:54+0000\n"
"PO-Revision-Date: 2022-11-09 14:54+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Administrative Name"
msgstr "Nom Administratif"
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Company"
msgstr "Société"
#. module: partner_profiles
#: model:ir.model,name:partner_profiles.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Create Public Profile"
msgstr "Créer le profil public"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_date
msgid "Created on"
msgstr "Créé le"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__has_position
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__has_position
msgid "Has Position"
msgstr "A une position"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__id
msgid "ID"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_main_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_main_profile
msgid "Is Main Profile"
msgstr "Est un profil Principal"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_position_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_position_profile
msgid "Is Position Profile"
msgstr "Est un profil Position"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_public_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_public_profile
msgid "Is Public Profile"
msgstr "Est un profil Public"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_uid
msgid "Last Updated by"
msgstr "Dernière mise à jour par"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_date
msgid "Last Updated on"
msgstr "Dernière mise à jour le"
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
#: model:partner.profile,name:partner_profiles.partner_profile_main
msgid "Main Profile"
msgstr "Profil principal"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__name
msgid "Name"
msgstr "Nom"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__other_contact_ids
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__other_contact_ids
msgid "Others Positions"
msgstr "Autres fonctions"
#. module: partner_profiles
#: model:ir.actions.act_window,name:partner_profiles.partner_profile_action
msgid "Partner Profiles"
msgstr "Profiles de contact"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__partner_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__partner_profile
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Partner profile"
msgstr "Profil de contact"
#. module: partner_profiles
#: model:ir.model,name:partner_profiles.model_partner_profile
msgid "Partner profile to differentiate the attached partner entries"
msgstr "Profil de contact pour différentier les champs du contact"
#. module: partner_profiles
#: model:ir.ui.menu,name:partner_profiles.menu_partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profile_view_tree
msgid "Partner profiles"
msgstr "Profiles de contact"
#. module: partner_profiles
#: model:ir.actions.server,name:partner_profiles.ir_cron_migration_partner_profiles_ir_actions_server
#: model:ir.cron,cron_name:partner_profiles.ir_cron_migration_partner_profiles
#: model:ir.cron,name:partner_profiles.ir_cron_migration_partner_profiles
msgid "Partner: Migration Standard Partners to Partners with Profiles"
msgstr "Contact : Migration des Contacts standards aux Conctacts à profile"
#. module: partner_profiles
#: model:ir.actions.server,name:partner_profiles.ir_cron_generate_missing_public_profiles_ir_actions_server
#: model:ir.cron,cron_name:partner_profiles.ir_cron_generate_missing_public_profiles
#: model:ir.cron,name:partner_profiles.ir_cron_generate_missing_public_profiles
msgid "Partner: generate missing public profiles"
msgstr "Contact : Générer les profil publics manquant"
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
#: model:partner.profile,name:partner_profiles.partner_profile_position
msgid "Position Profile"
msgstr "Profil position"
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
#: model:partner.profile,name:partner_profiles.partner_profile_public
msgid "Public Profile"
msgstr "Profil public"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__public_profile_id
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__public_profile_id
msgid "Public profile"
msgstr "Profil public"
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__ref
msgid "Ref"
msgstr ""

View File

@@ -1,173 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_profiles
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-09 14:53+0000\n"
"PO-Revision-Date: 2022-11-09 14:53+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Administrative Name"
msgstr ""
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Company"
msgstr ""
#. module: partner_profiles
#: model:ir.model,name:partner_profiles.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Create Public Profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_uid
msgid "Created by"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_date
msgid "Created on"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__display_name
msgid "Display Name"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__has_position
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__has_position
msgid "Has Position"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__id
msgid "ID"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_main_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_main_profile
msgid "Is Main Profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_position_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_position_profile
msgid "Is Position Profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_public_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_public_profile
msgid "Is Public Profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile____last_update
msgid "Last Modified on"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_uid
msgid "Last Updated by"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_date
msgid "Last Updated on"
msgstr ""
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
#: model:partner.profile,name:partner_profiles.partner_profile_main
msgid "Main Profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__name
msgid "Name"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__other_contact_ids
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__other_contact_ids
msgid "Others Positions"
msgstr ""
#. module: partner_profiles
#: model:ir.actions.act_window,name:partner_profiles.partner_profile_action
msgid "Partner Profiles"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__partner_profile
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__partner_profile
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
msgid "Partner profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model,name:partner_profiles.model_partner_profile
msgid "Partner profile to differentiate the attached partner entries"
msgstr ""
#. module: partner_profiles
#: model:ir.ui.menu,name:partner_profiles.menu_partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profile_view_tree
msgid "Partner profiles"
msgstr ""
#. module: partner_profiles
#: model:ir.actions.server,name:partner_profiles.ir_cron_migration_partner_profiles_ir_actions_server
#: model:ir.cron,cron_name:partner_profiles.ir_cron_migration_partner_profiles
#: model:ir.cron,name:partner_profiles.ir_cron_migration_partner_profiles
msgid "Partner: Migration Standard Partners to Partners with Profiles"
msgstr ""
#. module: partner_profiles
#: model:ir.actions.server,name:partner_profiles.ir_cron_generate_missing_public_profiles_ir_actions_server
#: model:ir.cron,cron_name:partner_profiles.ir_cron_generate_missing_public_profiles
#: model:ir.cron,name:partner_profiles.ir_cron_generate_missing_public_profiles
msgid "Partner: generate missing public profiles"
msgstr ""
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
#: model:partner.profile,name:partner_profiles.partner_profile_position
msgid "Position Profile"
msgstr ""
#. module: partner_profiles
#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view
#: model:partner.profile,name:partner_profiles.partner_profile_public
msgid "Public Profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__public_profile_id
#: model:ir.model.fields,field_description:partner_profiles.field_res_users__public_profile_id
msgid "Public profile"
msgstr ""
#. module: partner_profiles
#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__ref
msgid "Ref"
msgstr ""

View File

@@ -1,5 +0,0 @@
# Copyright 2020 Elabore (https://elabore.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import partner_profile
from . import res_partner

View File

@@ -1,14 +0,0 @@
# Copyright 2022 Elabore (https://elabore.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class PartnerProfile(models.Model):
_name = "partner.profile"
_description = "Partner profile to differentiate the attached partner entries"
name = fields.Char(string="Name", required=True, translate=True, readonly=False)
ref = fields.Char(string="Ref", required=True, translate=False, readonly=False)
# TODO: block unlink method.

View File

@@ -1,345 +0,0 @@
# Copyright 2022 Elabore (https://elabore.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
class res_partner(models.Model):
_inherit = "res.partner"
partner_profile = fields.Many2one(
"partner.profile",
string="Partner profile",
required=False,
translate=False,
readonly=False,
)
is_main_profile = fields.Boolean(compute="_compute_profile_booleans", store=True)
is_public_profile = fields.Boolean(compute="_compute_profile_booleans", store=True)
is_position_profile = fields.Boolean(
compute="_compute_profile_booleans", store=True
)
has_position = fields.Boolean(compute="_compute_has_position", store=True)
# If current partner is Main partner, this field indicates what its public profile is.
public_profile_id = fields.Many2one(
"res.partner",
compute="_compute_public_profile_id",
string="Public profile",
store=True,
ondelete="cascade",
)
# If current partner is Main partner, this field indicates what its position profiles are.
other_contact_ids = fields.One2many(
domain=[("is_position_profile", "=", True)]
)
@api.depends("partner_profile", "other_contact_ids")
def _compute_profile_booleans(self):
for partner in self:
partner.is_main_profile = (
partner.partner_profile.ref == "partner_profile_main"
)
partner.is_public_profile = (
partner.partner_profile.ref == "partner_profile_public"
)
partner.is_position_profile = (
partner.partner_profile.ref == "partner_profile_position"
)
@api.depends("other_contact_ids")
def _compute_has_position(self):
for partner in self:
partner.has_position = len(partner.other_contact_ids) > 0
@api.depends("partner_profile", "contact_id")
def _compute_public_profile_id(self):
for partner in self:
if partner.is_main_profile:
partner.public_profile_id = self.env["res.partner"].search(
[
("contact_id", "=", partner.id),
("is_public_profile", "=", True),
],
limit=1,
)
@api.onchange("type")
def _onchange_type(self):
self.contact_type = "standalone"
self.partner_profile = False
if self.type == "contact" and self.parent_id:
_logger.debug("Contact type: attached")
# A contact with parent_id is partner_profile=Position, and contact_type=attached
position_profile = self.env.ref("partner_profiles.partner_profile_position")
self.contact_type = "attached"
self.partner_profile = position_profile.id
@api.model
def create(self, vals):
"""Assume if not type, default is contact"""
vals["type"] = vals.get("type", "contact")
if vals["type"] == "contact":
"""When creating, if partner_profile is not defined by a previous process, the defaut value is Main"""
modified_self = self._basecontact_check_context("create")
if not vals.get("partner_profile") and not vals.get("contact_id"):
profile = self.env.ref("partner_profiles.partner_profile_main").read()[0]
vals["partner_profile"] = profile["id"]
res = super(res_partner, modified_self).create(vals)
# Creation of the public profile
if (
res.partner_profile.ref == "partner_profile_main" #TODO: replace by check on boolean is_main_profile ? Is this boolean computed at this step of the process?
and not res.public_profile_id
):
res.create_public_profile()
if res.partner_profile.ref == "partner_profile_public": #TODO: replace by check on boolean is_public_profile ? Is this boolean computed at this step of the process?
# Public profile can't be customer or supplier. Only main or position profiles can
res.customer = False
res.supplier = False
else:
modified_self = self._basecontact_check_context("create")
res = super(res_partner, modified_self).create(vals)
return res
@api.model
def search_position_partners(self, profile):
if profile:
position_partners = self.env["res.partner"].search(
[("contact_id", "=", self.id), ("partner_profile", "=", profile)]
)
else:
position_partners = self.env["res.partner"].search(
[("contact_id", "=", self.id)]
)
return position_partners
def _get_field_value(self, fname):
field = self._fields[fname]
if field.type == "many2one":
return self[fname].id
elif field.type == "one2many":
return None
elif field.type == "many2many":
return [(6, 0, self[fname].ids)]
else:
return self[fname]
def _get_public_profile_fields(self):
# Return the fields to copy in the public profile when it is created.
# The data copied depend on the partner's type: we consider the company data as public,
# whereas the personal data shouldn't be public by default.
if self.is_company:
fields = [
"name",
"function",
"phone",
"mobile",
"email",
"website",
"street",
"street2",
"city",
"country_id",
"zip",
"is_company",
"lang",
]
else:
fields = ["name"]
return fields
@api.multi
def create_public_profile(self):
profile = self.env.ref("partner_profiles.partner_profile_public")
for partner in self:
_logger.debug("Create public profile [%s] %s" % (partner.id, partner.name))
# Check if a public partner already exists
partner._compute_public_profile_id()
if not partner.public_profile_id:
values = {
"type": "other",
"contact_id": partner.id,
"partner_profile": profile.id,
"company_id": partner.company_id.id,
}
public_fields = partner._get_public_profile_fields()
for field_name in public_fields:
values[field_name] = partner._get_field_value(field_name)
partner.create(values)
partner._compute_public_profile_id()
def _contact_fields(self):
""" Returns the list of contact fields that are synced from the parent
when a partner is attached to him. """
return ['title']
##################################################################################
## Planned actions
##################################################################################
@api.model
def _cron_generate_missing_public_profiles(self):
partners = self.search(
[("is_main_profile", "=", True), ("public_profile_id", "=", False)]
)
for partner in partners:
partner.create_public_profile()
def _get_concerned_partners_search_values(
self,
id=False,
is_company=False,
active=True,
with_parent=False,
):
search_values = [
("is_company", "=", is_company),
("active", "=", active),
("partner_profile", "=", False)
]
if id:
search_values.append(("id", "=", id))
if with_parent and not is_company:
search_values.append(("parent_id", "!=", False))
elif not is_company:
search_values.append(("parent_id", "=", False))
return search_values
@api.model
def _migration_create_pro_profiles(self, limit=None, id=False):
partner_profile_main = self.env.ref("partner_profiles.partner_profile_main")
# Company migration
search_values = self._get_concerned_partners_search_values(
id,
is_company=True,
)
partners = self.env["res.partner"].search(search_values, limit=limit)
_logger.debug("Company migration count: %s" % len(partners))
if partners:
partners.write(
{
"partner_profile": partner_profile_main.id,
}
)
partners.create_public_profile()
_logger.debug("### End migration ###")
@api.model
def _migration_person_without_parent(self, limit=None, id=False):
partner_profile_main = self.env.ref("partner_profiles.partner_profile_main")
# Person migration without parent_id
search_values = self._get_concerned_partners_search_values(id)
partners = self.env["res.partner"].search(search_values, limit=limit)
_logger.debug("Person without parent migration count: %s" % len(partners))
if partners:
partners.write(
{
"partner_profile": partner_profile_main.id,
}
)
_logger.debug("Create public profiles")
partners.create_public_profile()
_logger.debug("### End migration ###")
def _get_main_partner_search_values(self, partner):
return [
("active", "=", True),
("is_main_profile", "=", True),
("is_company", "=", False),
"|",
("name", "=", partner.name),
"&",
("email", "!=", False),
("email", "=", partner.email),
]
@api.model
def _migration_person_with_parent_and_existing_main(
self, limit=None, id=False
):
partner_profile_position = self.env.ref("partner_profiles.partner_profile_position")
# Person migration with parent_id
search_values = self._get_concerned_partners_search_values(
id,
with_parent=True,
)
partners = self.env["res.partner"].search(search_values, limit=limit)
_logger.debug("Person migration with parent_id - migration count: %s" % len(partners))
count = 0
for partner in partners:
_logger.debug("count: [%s] : %s" % (count, partner.name))
existing_main_partner = self.env["res.partner"].search(
self._get_main_partner_search_values(partner),
limit=1,
)
if existing_main_partner:
_logger.debug("UPDATE Position")
partner.write(
{
"contact_id": existing_main_partner.id,
"partner_profile": partner_profile_position.id,
}
)
count += 1
_logger.debug("### End migration ###")
def _get_create_main_partner_values(self, partner):
partner_profile_main = self.env.ref("partner_profiles.partner_profile_main")
return {
"partner_profile": partner_profile_main.id,
"company_id": partner.company_id.id,
"parent_id": False,
"name": partner.name,
}
@api.model
def _migration_person_with_parent_not_existing_main(
self, limit=None, id=False
):
partners = self.env["res.partner"]
partner_profile_position = self.env.ref("partner_profiles.partner_profile_position")
# Person migration with parent_id
search_values = self._get_concerned_partners_search_values(
id,
with_parent=True,
)
partners = self.env["res.partner"].search(search_values, limit=limit)
_logger.debug("Person migration with parent_id - migration count: %s" % len(partners))
count = 0
for partner in partners:
_logger.debug("count: [%s] : %s" % (count, partner.name))
existing_main_partner = self.env["res.partner"].search(
self._get_main_partner_search_values(partner),
limit=1,
)
if not existing_main_partner:
default_values = self._get_create_main_partner_values(partner)
try:
main_partner = partner.copy(default=default_values)
except Exception as e:
_logger.debug("Email exist ! try with empty email")
default_values["email"] = ""
main_partner = partner.copy(default=default_values)
_logger.debug(
"count: [%s] %s -> [%s] %s "
% (partner.id, partner.name, main_partner.id, main_partner.name)
)
partner.write(
{
"partner_profile": partner_profile_position.id,
"contact_id": main_partner.id,
"type": "other",
}
)
count += 1
_logger.debug("Last clean")

View File

@@ -1,3 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_partner_profile_public,partner_profile_public,model_partner_profile,,1,0,0,0
access_partner_profile_admin,partner_profile_admin,model_partner_profile,base.group_partner_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_partner_profile_public partner_profile_public model_partner_profile 1 0 0 0
3 access_partner_profile_admin partner_profile_admin model_partner_profile base.group_partner_manager 1 1 1 1

View File

@@ -1,16 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="partner_profiles_calendar_event_form_view" model="ir.ui.view">
<field name="name">partner.profiles.calendar.event.view</field>
<field name="model">calendar.event</field>
<field name="inherit_id" ref="calendar.view_calendar_event_form" />
<field name="sequence">99</field>
<field name="arch" type="xml">
<field name="partner_ids" position="attributes">
<attribute name="domain">[('is_public_profile', '=', False)]</attribute>
</field>
</field>
</record>
</data>
</odoo>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="partner_profile_view_tree" model="ir.ui.view">
<field name="name">partner.profile.view.tree</field>
<field name="model">partner.profile</field>
<field name="arch" type="xml">
<tree string="Partner profiles">
<field name="name" />
<field name="ref" />
</tree>
</field>
</record>
<record id="partner_profile_action" model="ir.actions.act_window">
<field name="name">Partner Profiles</field>
<field name="res_model">partner.profile</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="menu_partner_profiles" action="partner_profile_action"
parent="contacts.res_partner_menu_config" sequence="1" name="Partner profiles"
groups="base.group_no_one" />
</odoo>

View File

@@ -1,98 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="partner_profiles_form_view" model="ir.ui.view">
<field name="name">Partner Profiles Form View</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="sequence">99</field>
<field name="arch" type="xml">
<!-- ################### -->
<!-- MAIN DISPLAY UPDATE -->
<!-- ################### -->
<xpath expr="//field[@name='name']" position="after">
<p class="oe_read_only" style="font-size:small; font-style:italic"
attrs="{'invisible': [('is_main_profile','=',False)]}">Main Profile</p>
<p class="oe_read_only" style="font-size:small; font-style:italic"
attrs="{'invisible': [('is_public_profile','=',False)]}">Public Profile</p>
<p class="oe_read_only" style="font-size:small; font-style:italic"
attrs="{'invisible': [('is_position_profile','=',False)]}">Position Profile</p>
</xpath>
<xpath expr="//field[@name='parent_id']" position="replace" />
<xpath expr="//field[@name='is_company']/.." position="after">
<group name="profile_data" class="bg-200">
<field name="partner_profile" readonly="1" invisible="1" />
<field name="is_main_profile" readonly="1" invisible="1" />
<field name="is_public_profile" readonly="1" invisible="1" />
<field name="is_position_profile" readonly="1" invisible="1" />
<group name="profile_status">
<field name="contact_id" widget="res_partner_many2one"
string="Main Profile" readonly="1"
attrs="{'invisible': [('is_main_profile','=',True)]}" />
<field name="parent_id" widget="res_partner_many2one"
placeholder="Company" domain="[('is_company', '=', True)]"
context="{'default_is_company': True, 'show_vat': True}"
attrs="{'invisible': ['|',('is_company', '=', True),'|',('contact_type','=','standalone'),('is_public_profile','=',True)]}"
readonly="1" />
<label for="public_profile_id"
attrs="{'invisible': [('is_main_profile','=',False)]}" />
<div class="o_row"
attrs="{'invisible': [('is_main_profile','=',False)]}">
<field name="public_profile_id" readonly="1" />
<button type="object" name="create_public_profile"
string="Create Public Profile"
attrs="{'invisible': [('public_profile_id','!=',False)]}" />
</div>
</group>
</group>
</xpath>
<!-- ################ -->
<!-- NOTEBOOK UPDATES -->
<!-- ################ -->
<!-- page Contacts & Adresses -->
<xpath expr="//field[@name='child_ids']/.." position="attributes">
<attribute name="attrs">{'invisible': [('is_company','=', False)]}</attribute>
</xpath>
<xpath
expr="//field[@name='child_ids']/form/sheet/group/group/field[@name='contact_type']"
position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='child_ids']/form/sheet/group/group/field[@name='name']"
position="before">
<field name="is_position_profile" readonly="1" invisible="1" />
<field name="partner_profile" string="Partner profile" invisible="1" />
</xpath>
<!-- page Other Positions -->
<xpath expr="//page[@name='other_position']" position="attributes">
<attribute name="attrs">{'invisible': ['|', ('contact_id','!=',False),
('is_company','=',True)]}</attribute>
</xpath>
<xpath expr="//page[@name='other_position']/field[@name='other_contact_ids']/kanban"
position="attributes">
<attribute name="create">true</attribute>
</xpath>
<xpath expr="//page[@name='other_position']/field[@name='other_contact_ids']"
position="attributes">
<attribute name="context">{'default_partner_profile': 3, 'default_contact_id':
active_id, 'default_name': name, 'default_street': street,
'default_street2': street2, 'default_city': city, 'default_state_id':
state_id, 'default_zip': zip, 'default_country_id': country_id,
'default_supplier': supplier}</attribute>
</xpath>
<xpath
expr="//field[@name='other_contact_ids']/form/sheet/group/group/field[@name='name']"
position="after">
<field name="is_position_profile" readonly="1" invisible="1" />
<field name="partner_profile" string="Partner profile" />
<field name="parent_id" widget="res_partner_many2one" placeholder="Company"
domain="[('is_company', '=', True),('is_main_profile','=', True)]"
context="{'default_partner_profile': 1, 'default_is_company': True, 'show_vat': True}" />
</xpath>
</field>
</record>
</data>
</odoo>

View File

@@ -1,2 +0,0 @@
*.*~
*pyc

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import models
from . import controllers

View File

@@ -1,42 +0,0 @@
# Copyright 2022 Stéphan Sainléger (Elabore)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "partner_profiles_portal",
"version": "12.0.1.0.2",
"author": "Elabore",
"website": "https://elabore.coop",
"maintainer": "Stéphan Sainléger",
"license": "AGPL-3",
"category": "Tools",
"summary": "Provide portal pages and forms to manage partner's profiles from portal home space.",
# any module necessary for this one to work correctly
"depends": [
"base",
"partner_contact_in_several_companies",
"partner_profiles",
"portal",
"website",
],
"qweb": [],
"external_dependencies": {
"python": [],
},
# always loaded
"data": [
"security/members_security.xml",
"views/portal_home_template.xml",
"views/portal_my_profiles_template.xml",
"views/portal_partner_profile_template.xml",
"views/res_partner_view.xml",
],
# only loaded in demonstration mode
"demo": [],
"js": [],
"css": [],
"installable": True,
# Install this module automatically if all dependency have been previously
# and independently installed. Used for synergetic or glue modules.
"auto_install": False,
"application": False,
}

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import portal_my_profiles
from . import portal_partner_profile

View File

@@ -1,91 +0,0 @@
# Copyright 2020 Lokavaluto ()
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import http, _
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
class CustomerPortalMyProfiles(CustomerPortal):
def _get_domain_my_profiles(self, user):
if user.partner_id.other_contact_ids:
main_profile_ids = user.partner_id.other_contact_ids.filtered(
"edit_structure_main_profile"
).mapped("parent_id")
public_profile_ids = user.partner_id.other_contact_ids.filtered(
"edit_structure_public_profile"
).mapped("parent_id.public_profile_id")
return [
"|",
"|",
("contact_id", "=", user.partner_id.id),
("id", "in", main_profile_ids.ids),
("id", "in", public_profile_ids.ids),
]
else:
return [("contact_id", "=", user.partner_id.id)]
def _prepare_portal_layout_values(self):
values = super(CustomerPortalMyProfiles, self)._prepare_portal_layout_values()
values["profile_count"] = request.env["res.partner"].search_count(
self._get_domain_my_profiles(request.env.user)
)
return values
@http.route(
["/my/profiles", "/my/profiles/page/<int:page>"],
type="http",
auth="user",
website=True,
)
def portal_my_profiles(
self, page=1, date_begin=None, date_end=None, sortby=None, **kw
):
values = self._prepare_portal_layout_values()
profile = request.env["res.partner"]
domain = self._get_domain_my_profiles(request.env.user)
searchbar_sortings = {
"name": {"label": _("Name"), "order": "name"},
"partner_profile": {"label": _("Profile Type"), "order": "partner_profile"},
"parent_id": {"label": _("Company"), "order": "parent_id"},
}
if not sortby:
sortby = "name"
order = searchbar_sortings[sortby]["order"]
# archive groups - Default Group By 'create_date'
archive_groups = self._get_archive_groups("res.partner", domain)
# profiles count
profile_count = profile.search_count(domain)
# pager
pager = portal_pager(
url="/my/profiles",
url_args={"sortby": sortby},
total=profile_count,
page=page,
step=self._items_per_page,
)
# content according to pager and archive selected
profiles = profile.search(
domain,
order=order,
limit=self._items_per_page,
offset=pager["offset"],
)
request.session["my_profiles_history"] = profiles.ids[:100]
values.update(
{
"profiles": profiles,
"page_name": "profile",
"archive_groups": archive_groups,
"default_url": "/my/profiles",
"pager": pager,
"searchbar_sortings": searchbar_sortings,
"sortby": sortby,
}
)
return request.render("partner_profiles_portal.portal_my_profiles", values)

View File

@@ -1,130 +0,0 @@
# Copyright 2020 Lokavaluto ()
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import http, tools, _
from odoo.exceptions import AccessError, MissingError
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal
class CustomerPortalPartnerProfile(CustomerPortal):
def _profile_get_page_view_values(self, profile, access_token, **kwargs):
values = {
"page_name": "profile",
"profile": profile,
}
return self._get_page_view_values(
profile, access_token, values, "my_profiles_history", False, **kwargs
)
def _details_profile_form_validate(self, data, profile_id):
error = dict()
error_message = []
# nickname uniqueness
if data.get("nickname") and request.env["res.partner"].sudo().search(
[
("name", "=", data.get("nickname")),
("partner_profile.ref", "=", "partner_profile_public"),
("id", "!=", profile_id),
]
):
error["nickname"] = "error"
error_message.append(
_("This nickname is already used, please find an other idea.")
)
# email validation
if data.get("email") and not tools.single_email_re.match(data.get("email")):
error["email"] = "error"
error_message.append(
_("Invalid Email! Please enter a valid email address.")
)
return error, error_message
def _get_profile_fields(self):
fields = [
"nickname",
"function",
"phone",
"mobile",
"email",
"website_url",
"street",
"street2",
"city",
"country_id",
"zipcode",
]
return fields
def _get_page_saving_values(self, profile, kw):
profile_fields = self._get_profile_fields()
values = {key: kw[key] for key in profile_fields if key in kw}
values.update(
{
"name": values.pop("nickname", profile.name),
"zip": values.pop("zipcode", ""),
"website": values.pop("website_url", ""),
}
)
return values
def _get_page_opening_values(self):
# Just retrieve the values to display for Selection fields
countries = request.env["res.country"].sudo().search([])
values = {
"countries": countries,
}
return values
@http.route(
["/my/profile/<int:profile_id>", "/my/profile/save"],
type="http",
auth="user",
website=True,
)
def portal_my_profile(
self, profile_id=None, access_token=None, redirect=None, **kw
):
# The following condition is to transform profile_id to an int, as it is sent as a string from the templace "portal_my_profile"
# TODO: find a better way to retrieve the profile_id at form submit step
if not isinstance(profile_id, int):
profile_id = int(profile_id)
# Check that the user has the right to see this profile
try:
profile_sudo = self._document_check_access(
"res.partner", profile_id, access_token
)
except (AccessError, MissingError):
return request.redirect("/my/profiles")
values = self._profile_get_page_view_values(profile_sudo, access_token, **kw)
values.update(
{
"error": {},
"error_message": [],
}
)
if kw and request.httprequest.method == "POST":
# the user has clicked in the Save button to save new data
error, error_message = self._details_profile_form_validate(kw, profile_id)
values.update({"error": error, "error_message": error_message})
values.update(kw)
if not error:
profile = request.env["res.partner"].browse(profile_id)
values = self._get_page_saving_values(profile, kw)
profile.sudo().write(values)
if redirect:
return request.redirect(redirect)
return request.redirect("/my/profiles")
# This is just the form page opening. We send all the data needed for the form fields
values.update(self._get_page_opening_values())
values.update(
{
"profile_id": profile_id, # Sent in order to retrieve it at submit time
"redirect": redirect
}
)
return request.render("partner_profiles_portal.portal_my_profile", values)

View File

@@ -1 +0,0 @@
This directory should contain the *.po for Odoo translation.

View File

@@ -1,239 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_profiles_portal
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-03 10:08+0000\n"
"PO-Revision-Date: 2023-01-03 10:08+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<b>Main profiles :</b>\n"
" internal and private profiles, used for membership management and internal communication.\n"
" <br/>\n"
" <b>Public profiles :</b>\n"
" profiles that might be available to tierce applications (annuary for instance)."
msgstr "<b>Profils Principaux :</b>\n"
" Profils internes et privés, utilisés pour la gestion des adhésions et la communication interne.\n"
" <br/>\n"
" <b>Profils Publics :</b>\n"
" Profils diffusés à des applications tierces (annuaire, porte-monnaie électronique ou cartographie par exemple)."
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<b>Public profile :</b>\n"
" profiles that might be available to tierce applications (annuary for instance).\n"
" <br/>\n"
" <b>Position profiles :</b>\n"
" profiles that indicate your belonging to an organization, and the role you have in."
msgstr "<b>Profils Publics :</b>\n"
" Profils diffusés à des applications tierces (annuaire, porte-monnaie électronique ou cartographie par exemple).\n"
" <br/>\n"
" <b>Profils Position :</b>\n"
" Profils qui indiquent votre appartenance à une organisation, et votre rôle dans cette dernière."
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "<br/>\n"
" Contact information"
msgstr "<br/>\n"
" Informations de contact"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "<br/>\n"
" Job position"
msgstr "<br/>\n"
" Poste occupé"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<br/>\n"
" My organizations' profiles"
msgstr "<br/>\n"
" Mes profils position"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<br/>\n"
" My profiles"
msgstr "<br/>\n"
" Mes profils"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<span class=\"d-none d-md-inline\">Profile name</span>"
msgstr "<span class=\"d-none d-md-inline\">Nom du Profile</span>"
#. module: partner_profiles_portal
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__can_edit_main_profile_ids
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__can_edit_main_profile_ids
msgid "Can edit main profile"
msgstr "Peut éditer le profil principal"
#. module: partner_profiles_portal
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__can_edit_public_profile_ids
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__can_edit_public_profile_ids
msgid "Can edit public profile"
msgstr "Peux éditer le profil public"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "City"
msgstr "Ville"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_my_profiles.py:51
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
#, python-format
msgid "Company"
msgstr "Société"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_home_profile_menu
msgid "Consult my profiles"
msgstr "Consulter mes profils"
#. module: partner_profiles_portal
#: model:ir.model,name:partner_profiles_portal.model_res_partner
msgid "Contact"
msgstr "Contact"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Country"
msgstr "Pays"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Country..."
msgstr "Pays..."
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Email"
msgstr "Courriel"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:40
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:46
#, python-format
msgid "Invalid Email! Please enter a valid email address."
msgstr "L'email n'est pas valide, merci de renseigner un email valide !"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/models/res_partner.py:14
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__edit_structure_main_profile
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__edit_structure_main_profile
#, python-format
msgid "Manage structure's main profile"
msgstr "Gère le profil principal de la structure"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/models/res_partner.py:17
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__edit_structure_public_profile
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__edit_structure_public_profile
#, python-format
msgid "Manage structure's public profile"
msgstr "Gère le profil public de la structure"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Mobile"
msgstr "Portable"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_home_profile_menu
msgid "Modify my account"
msgstr "Modifier mon compte"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_my_profiles.py:49
#, python-format
msgid "Name"
msgstr "Name"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Name / Nickname"
msgstr "Nom / Pseudo"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Phone"
msgstr "Téléphone"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "Position"
msgstr "Position"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_my_profiles.py:50
#, python-format
msgid "Profile Type"
msgstr "Type de profil"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "Profile type"
msgstr "Type de profil"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "Profiles"
msgstr "Profils"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Save\n"
" <span class=\"fa fa-long-arrow-right\"/>"
msgstr "Enregistrer\n"
" <span class=\"fa fa-long-arrow-right\"/>"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Street"
msgstr "Rue"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Street 2"
msgstr "Rue 2"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "There are no profiles."
msgstr "Il n'y a pas de profils"
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:33
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:39
#, python-format
msgid "This nickname is already used, please find an other idea."
msgstr "The Pseudo est déjà utilisé, merci d'en trouver un autre."
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Website"
msgstr "Site Web"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_home_profile_menu
msgid "Your Details"
msgstr "Vos détails"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Zip / Postal Code"
msgstr "Code postal"

View File

@@ -1,226 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_profiles_portal
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-03 10:07+0000\n"
"PO-Revision-Date: 2023-01-03 10:07+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<b>Main profiles :</b>\n"
" internal and private profiles, used for membership management and internal communication.\n"
" <br/>\n"
" <b>Public profiles :</b>\n"
" profiles that might be available to tierce applications (annuary for instance)."
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<b>Public profile :</b>\n"
" profiles that might be available to tierce applications (annuary for instance).\n"
" <br/>\n"
" <b>Position profiles :</b>\n"
" profiles that indicate your belonging to an organization, and the role you have in."
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "<br/>\n"
" Contact information"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "<br/>\n"
" Job position"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<br/>\n"
" My organizations' profiles"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<br/>\n"
" My profiles"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "<span class=\"d-none d-md-inline\">Profile name</span>"
msgstr ""
#. module: partner_profiles_portal
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__can_edit_main_profile_ids
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__can_edit_main_profile_ids
msgid "Can edit main profile"
msgstr ""
#. module: partner_profiles_portal
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__can_edit_public_profile_ids
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__can_edit_public_profile_ids
msgid "Can edit public profile"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "City"
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_my_profiles.py:51
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
#, python-format
msgid "Company"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_home_profile_menu
msgid "Consult my profiles"
msgstr ""
#. module: partner_profiles_portal
#: model:ir.model,name:partner_profiles_portal.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Country"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Country..."
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Email"
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:40
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:46
#, python-format
msgid "Invalid Email! Please enter a valid email address."
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/models/res_partner.py:14
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__edit_structure_main_profile
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__edit_structure_main_profile
#, python-format
msgid "Manage structure's main profile"
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/models/res_partner.py:17
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_partner__edit_structure_public_profile
#: model:ir.model.fields,field_description:partner_profiles_portal.field_res_users__edit_structure_public_profile
#, python-format
msgid "Manage structure's public profile"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Mobile"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_home_profile_menu
msgid "Modify my account"
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_my_profiles.py:49
#, python-format
msgid "Name"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Name / Nickname"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Phone"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "Position"
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_my_profiles.py:50
#, python-format
msgid "Profile Type"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "Profile type"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "Profiles"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Save\n"
" <span class=\"fa fa-long-arrow-right\"/>"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Street"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Street 2"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profiles
msgid "There are no profiles."
msgstr ""
#. module: partner_profiles_portal
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:33
#: code:addons/partner_profiles_portal/controllers/portal_partner_profile.py:39
#, python-format
msgid "This nickname is already used, please find an other idea."
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Website"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_home_profile_menu
msgid "Your Details"
msgstr ""
#. module: partner_profiles_portal
#: model_terms:ir.ui.view,arch_db:partner_profiles_portal.portal_my_profile
msgid "Zip / Postal Code"
msgstr ""

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import res_partner

View File

@@ -1,53 +0,0 @@
# Copyright 2022 Elabore (https://elabore.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
class res_partner(models.Model):
_inherit = "res.partner"
edit_structure_main_profile = fields.Boolean(
string=_("Manage structure's main profile")
)
edit_structure_public_profile = fields.Boolean(
string=_("Manage structure's public profile")
)
can_edit_main_profile_ids = fields.Many2many(
"res.partner",
relation="res_partner_main_profile_rel",
column1="partner_id",
column2="profile_id",
store=True,
compute="_compute_can_edit",
string="Can edit main profile",
)
can_edit_public_profile_ids = fields.Many2many(
"res.partner",
relation="res_partner_public_profile_rel",
column1="partner_id",
column2="profile_id",
store=True,
compute="_compute_can_edit",
string="Can edit public profile",
)
@api.depends(
"other_contact_ids",
"other_contact_ids.edit_structure_main_profile",
"other_contact_ids.edit_structure_public_profile",
"child_ids",
"child_ids.edit_structure_main_profile",
"child_ids.edit_structure_public_profile",
)
def _compute_can_edit(self):
for partner in self:
partner.can_edit_main_profile_ids = partner.child_ids.filtered(
"edit_structure_main_profile"
).mapped("contact_id")
partner.can_edit_public_profile_ids = partner.child_ids.filtered(
"edit_structure_public_profile"
).mapped("contact_id")

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.rule" id="res_partner_portal_members_rule">
<field name="name">res_partner: portal: read/write access on my profiles</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="domain_force">['|','|',('contact_id', '=', user.partner_id.id),
('can_edit_main_profile_ids', 'in', [user.partner_id.id]),
('contact_id.can_edit_public_profile_ids', 'in', [user.partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
<field name="perm_read" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_create" eval="False" />
<field name="perm_unlink" eval="False" />
</record>
</odoo>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_home_profile_menu" name="Portal My Home: Profile Menu" inherit_id="portal.portal_layout" priority="40">
<xpath expr="//div[hasclass('o_portal_my_details')]" position="replace">
<div class="o_portal_my_details">
<h4>Your Details </h4>
<hr class="mt-1 mb-0" />
<div class="mb8" t-field="user_id.partner_id" t-options="{&quot;widget&quot;: &quot;contact&quot;, &quot;fields&quot;: [&quot;email&quot;, &quot;phone&quot;, &quot;address&quot;, &quot;name&quot;]}" />
<div name="profiles_management">
<a t-attf-href="/my/account">
<button class="btn btn-primary mb8">
Modify my account
</button>
</a>
<a t-attf-href="/my/profiles">
<button class="btn btn-primary mb8">
Consult my profiles
</button>
</a>
</div>
</div>
</xpath>
</template>
</odoo>

View File

@@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_profiles" name="My Profiles">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True" />
<t t-call="portal.portal_searchbar">
<t t-set="title">Profiles</t>
</t>
<div class="oe_structure" id="oe_structure_portal_my_profiles_1" />
<t t-if="not profiles">
<div class="alert alert-warning mt8" role="alert">
There are no profiles.
</div>
</t>
<h3>
<br />
My profiles
</h3>
<t t-if="profiles" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>
<span class='d-none d-md-inline'>Profile name</span>
</th>
<th class="text-right">Profile type</th>
<th class="text-right">Position</th>
<th class="text-right">Company</th>
</tr>
</thead>
<tbody>
<tr t-foreach="profiles" t-as="profile">
<t t-if="not profile.is_company">
<td>
<a t-attf-href="/my/profile/#{profile.id}?{{ keep_query() }}">
<span t-field="profile.name" />
</a>
</td>
<td class="text-right">
<span t-field="profile.partner_profile" />
</td>
<td class="text-right">
<span t-field="profile.function" />
</td>
<td class="text-right">
<span t-field="profile.parent_id" />
</td>
</t>
</tr>
</tbody>
</t>
<p style="font-style:italic; font-size:smaller">
<b>Public profile :</b>
profiles that might be available to tierce applications (annuary for instance).
<br />
<b>Position profiles :</b>
profiles that indicate your belonging to an organization, and the role you have in.
</p>
<h3>
<br />
My organizations' profiles
</h3>
<t t-if="profiles" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>
<span class='d-none d-md-inline'>Profile name</span>
</th>
<th class="text-right">Profile type</th>
</tr>
</thead>
<tbody>
<tr t-foreach="profiles" t-as="profile">
<t t-if="profile.is_company">
<td>
<a t-attf-href="/my/profile/#{profile.id}?{{ keep_query() }}">
<span t-field="profile.name" />
</a>
</td>
<td class="text-right">
<span t-field="profile.partner_profile" />
</td>
</t>
</tr>
</tbody>
</t>
<p style="font-style:italic; font-size:smaller">
<b>Main profiles :</b>
internal and private profiles, used for membership management and internal communication.
<br />
<b>Public profiles :</b>
profiles that might be available to tierce applications (annuary for instance).
</p>
<div class="oe_structure" id="oe_structure_portal_my_profiles_2" />
</t>
</template>
</odoo>

View File

@@ -1,189 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_profile" name="My Profile">
<t t-call="portal.portal_layout">
<t t-set="o_portal_fullwidth_alert" groups="profile.group_profile_user">
<t t-call="portal.portal_back_in_edit_mode">
<t t-set="backend_url" t-value="'/web#return_label=Website&amp;model=res.partner&amp;id=%s&amp;view_type=form' % (profile.id)" />
</t>
</t>
<t t-call="portal.portal_record_layout">
<t t-set="card_header">
<h5 class="mb-0">
<strong>
<span t-field="profile.name" />
</strong>
<small class="text-muted">
-
<span t-field="profile.partner_profile" />
</small>
</h5>
<div t-if="profile.is_position_profile">
<h5 class="mb-0">
<span t-field="profile.parent_id" />
</h5>
<br />
<ul class="col-12 col-md-6 pb-2" style="list-style-type:none">
<li>
<span t-field="profile.street" />
</li>
<li>
<span t-field="profile.zip" />
</li>
<li>
<span t-field="profile.city" />
</li>
<li>
<span t-field="profile.country_id" />
</li>
</ul>
</div>
</t>
<t t-set="card_body">
<div class="oe_structure" id="oe_structure_portal_my_profile_1" />
<!-- Body for Position partner profiles-->
<div t-if="profile.is_position_profile">
<form action="/my/profile/save" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<div class="row o_portal_details">
<div class="col-lg-12">
<div class="col-lg-12">
<div t-if="error_message" class="alert alert-danger" role="alert">
<t t-foreach="error_message" t-as="err">
<t t-esc="err" />
<br />
</t>
</div>
</div>
<h3>
<br />
Job position
</h3>
<div class="row">
<div t-attf-class="form-group #{error.get('function') and 'o_has_error' or ''} col-xl-12">
<input type="text" name="function" t-attf-class="form-control #{error.get('function') and 'is-invalid' or ''}" t-att-value="function or profile.function" />
</div>
</div>
<h3>
<br />
Contact information
</h3>
<div class="row">
<div t-attf-class="form-group #{error.get('phone') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="phone">Phone</label>
<input type="tel" name="phone" t-attf-class="form-control #{error.get('phone') and 'is-invalid' or ''}" t-att-value="phone or profile.phone" />
</div>
<div t-attf-class="form-group #{error.get('mobile') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="mobile">Mobile</label>
<input type="tel" name="mobile" t-attf-class="form-control #{error.get('mobile') and 'is-invalid' or ''}" t-att-value="mobile or profile.mobile" />
</div>
<div t-attf-class="form-group #{error.get('email') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="email">Email</label>
<input type="email" name="email" t-attf-class="form-control #{error.get('email') and 'is-invalid' or ''}" t-att-value="email or profile.email" />
</div>
<div t-attf-class="form-group #{error.get('website_url') and 'o_has_error' or ''}col-xl-6">
<label class="col-form-label" for="website_url">Website</label>
<input type="text" name="website_url" t-attf-class="form-control #{error.get('website') and 'is-invalid' or ''}" t-att-value="website_url or profile.website" />
</div>
</div>
<input type="hidden" name="profile_id" t-att-value="profile_id" />
<input type="hidden" name="redirect" t-att-value="redirect" />
<div class="clearfix">
<button type="submit" class="btn btn-primary float-right mb32 ">
Save
<span class="fa fa-long-arrow-right" />
</button>
</div>
</div>
</div>
</form>
</div>
<!-- Body for Public partner profiles-->
<div t-if="profile.is_main_profile or profile.is_public_profile">
<form action="/my/profile/save" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<div class="row o_portal_details">
<div class="col-lg-12">
<div name="errors" class="col-lg-12">
<div t-if="error_message" class="alert alert-danger" role="alert">
<t t-foreach="error_message" t-as="err">
<t t-esc="err" />
<br />
</t>
</div>
</div>
<div name="nickname" class="row">
<div t-attf-class="form-group #{error.get('nickname') and 'o_has_error' or ''} col-xl-12">
<label class="col-form-label" for="nickname">Name / Nickname</label>
<input type="text" name="nickname" t-attf-class="form-control #{error.get('nickname') and 'is-invalid' or ''}" t-att-value="nickname or profile.name" />
</div>
</div>
<h3>
<br />
Contact information
</h3>
<div name="contact_info_1" class="row">
<div name="street" t-attf-class="form-group #{error.get('street') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="street">Street</label>
<input type="text" name="street" t-attf-class="form-control #{error.get('street') and 'is-invalid' or ''}" t-att-value="street or profile.street" />
</div>
<div name="street2" t-attf-class="form-group #{error.get('street2') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="street2">Street 2</label>
<input type="text" name="street2" t-attf-class="form-control #{error.get('street2') and 'is-invalid' or ''}" t-att-value="street2 or profile.street2" />
</div>
<div name="zip" t-attf-class="form-group #{error.get('zipcode') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="zipcode">Zip / Postal Code</label>
<input type="text" name="zipcode" t-attf-class="form-control #{error.get('zipcode') and 'is-invalid' or ''}" t-att-value="zipcode or profile.zip" />
</div>
<div name="city" t-attf-class="form-group #{error.get('city') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="city">City</label>
<input type="text" name="city" t-attf-class="form-control #{error.get('city') and 'is-invalid' or ''}" t-att-value="city or profile.city" />
</div>
<div name="country" t-attf-class="form-group #{error.get('country_id') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="country_id">Country</label>
<select name="country_id" t-attf-class="form-control">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == int(country_id) if country_id else country.id == profile.country_id.id">
<t t-esc="country.name" />
</option>
</t>
</select>
</div>
</div>
<div name="contact_info_2" class="row">
<div name="phone" t-attf-class="form-group #{error.get('phone') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="phone">Phone</label>
<input type="tel" name="phone" t-attf-class="form-control #{error.get('phone') and 'is-invalid' or ''}" t-att-value="phone or profile.phone" />
</div>
<div name="mobile" t-attf-class="form-group #{error.get('mobile') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="mobile">Mobile</label>
<input type="tel" name="mobile" t-attf-class="form-control #{error.get('mobile') and 'is-invalid' or ''}" t-att-value="mobile or profile.mobile" />
</div>
<div name="email" t-attf-class="form-group #{error.get('email') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="email">Email</label>
<input type="email" name="email" t-attf-class="form-control #{error.get('email') and 'is-invalid' or ''}" t-att-value="email or profile.email" />
</div>
<div name="website" t-attf-class="form-group #{error.get('website_url') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="website_url">Website</label>
<input type="text" name="website_url" t-attf-class="form-control #{error.get('website_url') and 'is-invalid' or ''}" t-att-value="website_url or profile.website" />
</div>
</div>
<input type="hidden" name="profile_id" t-att-value="profile_id" />
<input type="hidden" name="redirect" t-att-value="redirect" />
<div class="clearfix">
<button type="submit" class="btn btn-primary float-right mb32 ">
Save
<span class="fa fa-long-arrow-right" />
</button>
</div>
</div>
</div>
</form>
</div>
<div class="oe_structure" id="oe_structure_portal_my_profile_2" />
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="partner_profiles_form_view" model="ir.ui.view">
<field name="name">Partner Profiles Form View</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="sequence">99</field>
<field name="arch" type="xml">
<!-- Main display -->
<xpath expr="//group[@name='profile_status']" position="after">
<group name="structure_access_rights" attrs="{'invisible': ['|', ('is_position_profile','=',False), ('parent_id','=',False)]}">
<field name="edit_structure_main_profile" />
<field name="edit_structure_public_profile" />
</group>
</xpath>
<!-- page Contacts & Adresses -->
<xpath expr="//field[@name='child_ids']/form/sheet/group/group/field[@name='comment']" position="before">
<field name="edit_structure_main_profile" attrs="{'invisible': [('is_position_profile','=',False)]}" />
<field name="edit_structure_public_profile" attrs="{'invisible': [('is_position_profile','=',False)]}" />
</xpath>
<!-- page Other Positions -->
<xpath expr="//field[@name='other_contact_ids']/form/sheet/group/group/field[@name='parent_id']" position="after">
<field name="edit_structure_main_profile" attrs="{'invisible': [('is_position_profile','=',False)]}" />
<field name="edit_structure_public_profile" attrs="{'invisible': [('is_position_profile','=',False)]}" />
</xpath>
</field>
</record>
</data>
</odoo>