10 Commits

Author SHA1 Message Date
jscampucci
80600395ca [WIP] Test gitea actions
Some checks failed
pre-commit / pre-commit (pull_request) Failing after 5m25s
2025-09-15 15:14:16 +02:00
jscampucci
65171f3fb4 [CLN] global : lint line length corrections 2025-09-15 14:31:21 +02:00
jscampucci
d3b2cdd286 [CLN] global : clean lint errors 2025-09-15 14:13:26 +02:00
jscampucci
174aabfbbb [CLN] global : full pre-commit & ruff lint 2025-09-15 12:58:03 +02:00
jscampucci
b63c4b5335 [CLN] set hardcoded repo name 2025-09-15 12:03:15 +02:00
jscampucci
1d4364b048 [CLN] set repo name from env var 2025-09-15 12:00:10 +02:00
jscampucci
6b36376f6f [CLN] clean workflow folder name 2025-09-15 11:45:31 +02:00
jscampucci
39aef0d942 [ADD] global: add pre-commit process 2025-09-15 11:43:19 +02:00
Stéphan Sainléger
3d67b41a58 [IMP] event_generate_quotation_from_registration: block field edition
of event.registration.financier if the quotation is done.
2025-06-05 14:48:08 +02:00
Stéphan Sainléger
17e1f2f375 [IMP] event_generate_quotation_from_registration: prevent edition attempts of done sale orders 2025-06-05 14:48:08 +02:00
75 changed files with 1349 additions and 429 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

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

@@ -0,0 +1,146 @@
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
args: ["https://github.com/elabore-coop/event-tools"]
- id: oca-gen-addon-readme
args:
- --addons-dir=.
- --branch=16.0
- --org-name=OCA
- --repo-name=event-tools
- --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

42
.ruff.toml Normal file
View File

@@ -0,0 +1,42 @@
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 +1 @@
from . import models from . import models

View File

@@ -5,18 +5,18 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
'summary': 'Generate quotation from event registration', "summary": "Generate quotation from event registration",
'description': """ "description": """
Generate quotation from event registration : Generate quotation from event registration :
""", """,
"depends": ["event_sale"], "depends": ["event_sale"],
"data": [ "data": [
'security/ir.model.access.csv', "security/ir.model.access.csv",
'views/event_registration_views.xml', "views/event_registration_views.xml",
'views/sale_order_views.xml', "views/sale_order_views.xml",
'views/account_move_views.xml', "views/account_move_views.xml",
], ],
"installable": True, "installable": True,
} }

View File

@@ -1,4 +1,4 @@
from . import event_registration from . import event_registration
from . import event_registration_financier from . import event_registration_financier
from . import sale_order from . import sale_order
from . import account_move from . import account_move

View File

@@ -1,6 +1,7 @@
from odoo import _, api, Command, fields, models from odoo import fields, models
class AccountMove(models.Model): class AccountMove(models.Model):
_inherit = "account.move" _inherit = "account.move"
event_registration_id = fields.Many2one('event.registration', string="Stagiaire") event_registration_id = fields.Many2one("event.registration", string="Stagiaire")

View File

@@ -1,12 +1,17 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
import logging import logging
from odoo import api, fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventRegistration(models.Model): class EventRegistration(models.Model):
_inherit = "event.registration" _inherit = "event.registration"
financier_ids = fields.One2many('event.registration.financier', 'registration_id', string="Financements") financier_ids = fields.One2many(
"event.registration.financier", "registration_id", string="Financements"
)
def name_get(self): def name_get(self):
result = [] result = []
@@ -15,31 +20,35 @@ class EventRegistration(models.Model):
name = f"{registration.partner_id.name} ({registration.event_id.name})" name = f"{registration.partner_id.name} ({registration.event_id.name})"
result.append((registration.id, name)) result.append((registration.id, name))
return result return result
@api.depends("partner_id", "event_id") @api.depends("partner_id", "event_id")
def _compute_display_name(self): def _compute_display_name(self):
for registration in self: for registration in self:
if registration.partner_id and registration.event_id: if registration.partner_id and registration.event_id:
registration.display_name = f"{registration.partner_id.name} ({registration.event_id.name})" registration.display_name = (
f"{registration.partner_id.name} ({registration.event_id.name})"
)
else: else:
registration.display_name = super(EventRegistration, registration)._compute_display_name() registration.display_name = super(
EventRegistration, registration
)._compute_display_name()
def generate_quotation(self): def generate_quotation(self):
for registration in self: for registration in self:
for financier in registration.financier_ids: for financier in registration.financier_ids:
if not financier.quotation_id: if not financier.quotation_id:
so_values = financier.get_sale_order_values() so_values = financier.get_sale_order_values()
so_values['order_line'] = financier.get_sale_order_line_values() so_values["order_line"] = financier.get_sale_order_line_values()
sale_order = self.env['sale.order'].create(so_values) sale_order = self.env["sale.order"].create(so_values)
financier.quotation_id = sale_order financier.quotation_id = sale_order
else: else:
order_lines = self.env['sale.order.line'].search([ order_lines = self.env["sale.order.line"].search(
('order_id','=',financier.quotation_id.id), [
('product_id','=',financier.get_product_id()) ("order_id", "=", financier.quotation_id.id),
]) ("product_id", "=", financier.get_product_id()),
("state", "!=", "done"),
]
)
if order_lines: if order_lines:
order_lines[0].price_unit = financier.amount order_lines[0].price_unit = financier.amount
financier.quotation_id.write(financier.get_sale_order_values()) financier.quotation_id.write(financier.get_sale_order_values())

View File

@@ -1,40 +1,52 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
import logging import logging
from odoo import Command, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventRegistrationFinancier(models.Model): class EventRegistrationFinancier(models.Model):
_name = "event.registration.financier" _name = "event.registration.financier"
_rec_name = 'financier_id' _rec_name = "financier_id"
company_id = fields.Many2one("res.company") company_id = fields.Many2one("res.company")
company_currency_id = fields.Many2one('res.currency', related="company_id.currency_id") company_currency_id = fields.Many2one(
registration_id = fields.Many2one('event.registration') "res.currency", related="company_id.currency_id"
quotation_id = fields.Many2one('sale.order', string="Devis") )
financier_id = fields.Many2one('res.partner', string="Financeur", required=True) registration_id = fields.Many2one("event.registration")
terms = fields.Char('Modalités') quotation_id = fields.Many2one("sale.order", string="Devis")
amount = fields.Monetary('Montant', currency_field="company_currency_id") financier_id = fields.Many2one("res.partner", string="Financeur", required=True)
terms = fields.Char("Modalités")
amount = fields.Monetary("Montant", currency_field="company_currency_id")
state = fields.Selection(
related="quotation_id.state",
string="Order Status",
copy=False,
store=True,
precompute=True,
)
def get_product_id(self): def get_product_id(self):
if self.registration_id.event_ticket_id: if self.registration_id.event_ticket_id:
return self.registration_id.event_ticket_id.product_id.id return self.registration_id.event_ticket_id.product_id.id
elif self.registration_id.event_id.event_ticket_ids: elif self.registration_id.event_id.event_ticket_ids:
return self.registration_id.event_id.event_ticket_ids[0].product_id.id return self.registration_id.event_id.event_ticket_ids[0].product_id.id
raise UserError('Un ticket doit être défini dans la session de formation afin de générer le devis') raise UserError(
"Un ticket doit être défini dans la session de formation afin de générer le devis"
)
def get_sale_order_values(self): def get_sale_order_values(self):
return { return {
'event_registration_id':self.registration_id.id, "event_registration_id": self.registration_id.id,
'partner_id':self.financier_id.id, "partner_id": self.financier_id.id,
} }
def get_sale_order_line_values(self): def get_sale_order_line_values(self):
return [Command.create({ return [
"price_unit": self.amount, Command.create(
"product_id": self.get_product_id() {"price_unit": self.amount, "product_id": self.get_product_id()}
})] )
]

View File

@@ -1,39 +1,61 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
import logging import logging
from odoo import fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class SaleOrder(models.Model): class SaleOrder(models.Model):
_inherit = "sale.order" _inherit = "sale.order"
event_registration_id = fields.Many2one('event.registration', string="Stagiaire") event_registration_id = fields.Many2one("event.registration", string="Stagiaire")
def _prepare_invoice(self): def _prepare_invoice(self):
"""Copy event_registration_id to generated invoice
""" """
res = super(SaleOrder, self)._prepare_invoice() Copy event_registration_id to generated invoice.
"""
res = super()._prepare_invoice()
res["event_registration_id"] = self.event_registration_id.id res["event_registration_id"] = self.event_registration_id.id
return res return res
def linked_to_registration(self): def linked_to_registration(self):
return len(self.env['event.registration.financier'].search([('quotation_id','=',self.id)])) > 0 return (
len(
def action_confirm(self): self.env["event.registration.financier"].search(
res = super(SaleOrder, self).action_confirm() [("quotation_id", "=", self.id)]
)
)
> 0
)
#if sale order is linked to event.registration.financier, don't open wizard def action_confirm(self):
if isinstance(res, dict) and res.get('xml_id') == 'event_sale.action_sale_order_event_registration' and self.linked_to_registration(): res = super().action_confirm()
# if sale order is linked to event.registration.financier, don't open wizard
if (
isinstance(res, dict)
and res.get("xml_id") == "event_sale.action_sale_order_event_registration"
and self.linked_to_registration()
):
return True return True
return res return res
class SaleOrderLine(models.Model): class SaleOrderLine(models.Model):
_inherit = "sale.order.line" _inherit = "sale.order.line"
def _update_registrations(self, confirm=True, cancel_to_draft=False, registration_data=None, mark_as_paid=False): def _update_registrations(
self,
confirm=True,
cancel_to_draft=False,
registration_data=None,
mark_as_paid=False,
):
# bypass _update_registrations if order generated by event registration # bypass _update_registrations if order generated by event registration
if self.order_id.linked_to_registration(): if self.order_id.linked_to_registration():
return return
return super(SaleOrderLine, self)._update_registrations(confirm, cancel_to_draft, registration_data, mark_as_paid) return super()._update_registrations(
confirm, cancel_to_draft, registration_data, mark_as_paid
)

View File

@@ -1,2 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_registration_financier,access.event.registration.financier,model_event_registration_financier,sales_team.group_sale_salesman,1,1,1,1 access_event_registration_financier,access.event.registration.financier,model_event_registration_financier,sales_team.group_sale_salesman,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_event_registration_financier access.event.registration.financier model_event_registration_financier sales_team.group_sale_salesman 1 1 1 1

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="view_move_form" model="ir.ui.view"> <record id="view_move_form" model="ir.ui.view">
<field name="name">view.move.form.inherit.event.generate.quotation</field> <field name="name">view.move.form.inherit.event.generate.quotation</field>
@@ -12,7 +12,9 @@
</record> </record>
<record id="view_out_invoice_tree" model="ir.ui.view"> <record id="view_out_invoice_tree" model="ir.ui.view">
<field name="name">view.out.invoice.tree.inherit.event.generate.quotation</field> <field
name="name"
>view.out.invoice.tree.inherit.event.generate.quotation</field>
<field name="model">account.move</field> <field name="model">account.move</field>
<field name="inherit_id" ref="account.view_out_invoice_tree" /> <field name="inherit_id" ref="account.view_out_invoice_tree" />
<field name="arch" type="xml"> <field name="arch" type="xml">

View File

@@ -1,25 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record model="ir.ui.view" id="view_event_registration_form_event_generate_quotation_from_registration"> <record
<field name="name">view.event.registration.form.event.generate.quotation.from.registration</field> model="ir.ui.view"
<field name="model">event.registration</field> id="view_event_registration_form_event_generate_quotation_from_registration"
>
<field
name="name"
>view.event.registration.form.event.generate.quotation.from.registration</field>
<field name="model">event.registration</field>
<field name="inherit_id" ref="event_sale.event_registration_ticket_view_form" /> <field name="inherit_id" ref="event_sale.event_registration_ticket_view_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<sheet position="inside"> <sheet position="inside">
<group name="quotation" string="Financement" colspan="1"> <group name="quotation" string="Financement" colspan="1">
<field name="financier_ids" nolabel="1" colspan="2"> <field name="financier_ids" nolabel="1" colspan="2">
<tree editable="bottom"> <tree editable="bottom">
<field name="financier_id" /> <field name="state" invisible="1" />
<field name="amount" /> <field
<field name="terms" /> name="financier_id"
attrs="{'readonly': [('state', 'in', ['done', 'cancel'])]}"
/>
<field
name="amount"
attrs="{'readonly': [('state', 'in', ['done', 'cancel'])]}"
/>
<field name="terms" />
<field name="quotation_id" readonly="True" /> <field name="quotation_id" readonly="True" />
</tree> </tree>
</field> </field>
<button name="generate_quotation" type="object" string="Créer/adapter les devis" colspan="2" /> <button
name="generate_quotation"
type="object"
string="Créer/adapter les devis"
colspan="2"
/>
</group> </group>
</sheet> </sheet>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="sale_order_view_form" model="ir.ui.view"> <record id="sale_order_view_form" model="ir.ui.view">
<field name="name">sale.order.form.inherit.event.generate.quotation</field> <field name="name">sale.order.form.inherit.event.generate.quotation</field>

View File

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

View File

@@ -7,18 +7,15 @@
"version": "16.0.0.0.0", "version": "16.0.0.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
'summary': 'Event mail attachments', "summary": "Event mail attachments",
'description': """ "description": """
Event mail attachments Event mail attachments
---------------------------------------------------- ----------------------------------------------------
""", """,
"category": "", "category": "",
"depends": ["ctl_training_customization"], "depends": ["ctl_training_customization"],
"data": [ "data": ["views/mail_template_views.xml"],
'views/mail_template_views.xml'
],
"installable": True, "installable": True,
} }

View File

@@ -1 +1 @@
from . import mail_template from . import mail_template

View File

@@ -1,50 +1,66 @@
from odoo import _, api, Command, fields, models from odoo import fields, models
from lxml import etree, html
class MailTemplate(models.Model): class MailTemplate(models.Model):
_inherit = "mail.template" _inherit = "mail.template"
event_attachment_name_prefix = fields.Char('Attachment name prefix', help="If there is an attachment in event registration, or in event, with a name that starts with this name, it will be attached to the mail.") event_attachment_name_prefix = fields.Char(
"Attachment name prefix",
help="""
If there is an attachment in event registration, or in event,
with a name that starts with this name, it will be attached to the mail.
""",
)
def generate_email(self, res_ids, fields): def generate_email(self, res_ids, fields):
res = super(MailTemplate, self).generate_email(res_ids, fields) res = super().generate_email(res_ids, fields)
self.ensure_one() self.ensure_one()
multi_mode = True multi_mode = True
if isinstance(res_ids, int): if isinstance(res_ids, int):
res_ids = [res_ids] res_ids = [res_ids]
multi_mode = False multi_mode = False
for lang, (template, template_res_ids) in self._classify_per_lang(res_ids).items(): for _, (template, template_res_ids) in self._classify_per_lang(res_ids).items():
#add reports attached to event.registration or event.event from attachment name # add reports attached to event.registration or event.event from
# attachment name
if template.event_attachment_name_prefix: if template.event_attachment_name_prefix:
for res_id in template_res_ids: for res_id in template_res_ids:
event_registration = self.env['event.registration'].browse(res_id) event_registration = self.env["event.registration"].browse(res_id)
attachments = self.env['ir.attachment'] attachments = self.env["ir.attachment"]
for event_attachment_name_prefix in template.event_attachment_name_prefix.split(","): for (
attachments |= self.env['ir.attachment'].search([ event_attachment_name_prefix
('res_model','=','event.registration'), ) in template.event_attachment_name_prefix.split(","):
('res_id','=',res_id), attachments |= self.env["ir.attachment"].search(
('name','like',event_attachment_name_prefix)]) [
attachments |= self.env['ir.attachment'].search([ ("res_model", "=", "event.registration"),
('res_model','=','event.event'), ("res_id", "=", res_id),
('res_id','=',event_registration.event_id.id), ("name", "like", event_attachment_name_prefix),
('name','like',event_attachment_name_prefix)]) ]
)
attachments_res = [(attachment.name, attachment.datas) for attachment in attachments] attachments |= self.env["ir.attachment"].search(
[
("res_model", "=", "event.event"),
("res_id", "=", event_registration.event_id.id),
("name", "like", event_attachment_name_prefix),
]
)
attachments_res = [
(attachment.name, attachment.datas)
for attachment in attachments
]
if multi_mode: if multi_mode:
if res_id in res: if res_id in res:
if not 'attachments' in res[res_id]: if "attachments" not in res[res_id]:
res[res_id]['attachments'] = attachments_res res[res_id]["attachments"] = attachments_res
else: else:
res[res_id]['attachments'].extend(attachments_res) res[res_id]["attachments"].extend(attachments_res)
else: else:
if not 'attachments' in res: if "attachments" not in res:
res['attachments'] = attachments_res res["attachments"] = attachments_res
else: else:
res['attachments'].extend(attachments_res) res["attachments"].extend(attachments_res)
return res return res

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<data> <data>
<record model="ir.ui.view" id="email_template_form_event_mail_attachment"> <record model="ir.ui.view" id="email_template_form_event_mail_attachment">
@@ -19,7 +19,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="report_name" position="after"> <field name="report_name" position="after">
<field name="event_attachment_name_prefix" /> <field name="event_attachment_name_prefix" />
</field> </field>
</field> </field>
</record> </record>

View File

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

View File

@@ -5,18 +5,15 @@
"version": "16.0.0.0.0", "version": "16.0.0.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
'summary': 'Add manual send in event communication', "summary": "Add manual send in event communication",
'description': """ "description": """
Add manual send in event communication Add manual send in event communication
---------------------------------------------------- ----------------------------------------------------
""", """,
"category": "", "category": "",
"depends": ["event"], "depends": ["event"],
"data": [ "data": ["views/event_event_views.xml"],
'views/event_event_views.xml'
],
"installable": True, "installable": True,
} }

View File

@@ -1 +1 @@
from . import event_mail from . import event_mail

View File

@@ -1,54 +1,66 @@
from odoo import _, api, Command, fields, models
from lxml import etree, html
import logging import logging
from odoo.exceptions import MissingError, ValidationError
from odoo import api, fields, models
from odoo.exceptions import MissingError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventMail(models.Model): class EventMail(models.Model):
_inherit = "event.mail" _inherit = "event.mail"
notification_type = fields.Selection(selection_add=[('mail_manual', 'Mail (manual)')], ondelete={'mail_manual': 'set default'}) notification_type = fields.Selection(
selection_add=[("mail_manual", "Mail (manual)")],
ondelete={"mail_manual": "set default"},
)
def _selection_template_model_get_mapping(self): def _selection_template_model_get_mapping(self):
return {**super(EventMail, self)._selection_template_model_get_mapping(), 'mail_manual': 'mail.template'} return {
**super()._selection_template_model_get_mapping(),
"mail_manual": "mail.template",
}
@api.depends(
@api.depends('event_id.date_begin', 'event_id.date_end', 'interval_type', 'interval_unit', 'interval_nbr','notification_type') "event_id.date_begin",
"event_id.date_end",
"interval_type",
"interval_unit",
"interval_nbr",
"notification_type",
)
def _compute_scheduled_date(self): def _compute_scheduled_date(self):
res = super(EventMail, self)._compute_scheduled_date() res = super()._compute_scheduled_date()
for scheduler in self: for scheduler in self:
if scheduler.notification_type == 'mail_manual': if scheduler.notification_type == "mail_manual":
scheduler.scheduled_date = '2148-12-31' scheduler.scheduled_date = "2148-12-31"
scheduler.interval_type = 'after_sub' scheduler.interval_type = "after_sub"
return res return res
def send(self): def send(self):
self.execute() self.execute()
return return
class EventMailRegistration(models.Model): class EventMailRegistration(models.Model):
_inherit = 'event.mail.registration' _inherit = "event.mail.registration"
def execute(self): def execute(self):
"""Inherit execute to send mail from schedulers "mail_manual"
""" """
res = super(EventMailRegistration, self).execute() Inherit execute to send mail from schedulers "mail_manual".
"""
todo_manual = self.filtered(lambda reg_mail: res = super().execute()
not reg_mail.mail_sent and
reg_mail.registration_id.state in ['open', 'done'] and todo_manual = self.filtered(
reg_mail.scheduler_id.notification_type == 'mail_manual' lambda reg_mail: not reg_mail.mail_sent
and reg_mail.registration_id.state in ["open", "done"]
and reg_mail.scheduler_id.notification_type == "mail_manual"
) )
done = self.browse() done = self.browse()
for reg_mail in todo_manual: for reg_mail in todo_manual:
organizer = reg_mail.scheduler_id.event_id.organizer_id organizer = reg_mail.scheduler_id.event_id.organizer_id
company = self.env.company company = self.env.company
author = self.env.ref('base.user_root').partner_id author = self.env.ref("base.user_root").partner_id
if organizer.email: if organizer.email:
author = organizer author = organizer
elif company.email: elif company.email:
@@ -57,7 +69,7 @@ class EventMailRegistration(models.Model):
author = self.env.user.partner_id author = self.env.user.partner_id
email_values = { email_values = {
'author_id': author.id, "author_id": author.id,
} }
template = None template = None
try: try:
@@ -66,15 +78,20 @@ class EventMailRegistration(models.Model):
pass pass
if not template: if not template:
_logger.warning("Cannot process ticket %s, because Mail Scheduler %s has reference to non-existent template", reg_mail.registration_id, reg_mail.scheduler_id) _logger.warning(
"""
Cannot process ticket %s, because Mail Scheduler %s has
reference to non-existent template
""",
reg_mail.registration_id,
reg_mail.scheduler_id,
)
continue continue
if not template.email_from: if not template.email_from:
email_values['email_from'] = author.email_formatted email_values["email_from"] = author.email_formatted
template.send_mail(reg_mail.registration_id.id, email_values=email_values) template.send_mail(reg_mail.registration_id.id, email_values=email_values)
done |= reg_mail done |= reg_mail
done.write({'mail_sent': True}) done.write({"mail_sent": True})
return res return res

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<data> <data>
<record model="ir.ui.view" id="view_event_form_event_mail_manual"> <record model="ir.ui.view" id="view_event_form_event_mail_manual">
@@ -6,22 +6,41 @@
<field name="inherit_id" ref="event.view_event_form" /> <field name="inherit_id" ref="event.view_event_form" />
<field name="model">event.event</field> <field name="model">event.event</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='event_mail_ids']/tree/field[@name='mail_state']" position="after"> <xpath
<button expr="//field[@name='event_mail_ids']/tree/field[@name='mail_state']"
name="send" position="after"
type="object" >
icon="fa-bullhorn" <button
attrs="{'invisible':[('notification_type','!=','mail_manual')]}" name="send"
confirm="Send mail to all attendees ?" /> type="object"
icon="fa-bullhorn"
attrs="{'invisible':[('notification_type','!=','mail_manual')]}"
confirm="Send mail to all attendees ?"
/>
</xpath> </xpath>
<xpath expr="//field[@name='event_mail_ids']/tree/field[@name='interval_nbr']" position="attributes"> <xpath
<attribute name="attrs">{'readonly':['|',('interval_unit','=','now'),('notification_type','=','mail_manual')]}</attribute> expr="//field[@name='event_mail_ids']/tree/field[@name='interval_nbr']"
position="attributes"
>
<attribute
name="attrs"
>{'readonly':['|',('interval_unit','=','now'),('notification_type','=','mail_manual')]}</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='event_mail_ids']/tree/field[@name='interval_unit']" position="attributes"> <xpath
<attribute name="attrs">{'readonly':[('notification_type','=','mail_manual')]}</attribute> expr="//field[@name='event_mail_ids']/tree/field[@name='interval_unit']"
position="attributes"
>
<attribute
name="attrs"
>{'readonly':[('notification_type','=','mail_manual')]}</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='event_mail_ids']/tree/field[@name='interval_type']" position="attributes"> <xpath
<attribute name="attrs">{'readonly':[('notification_type','=','mail_manual')]}</attribute> expr="//field[@name='event_mail_ids']/tree/field[@name='interval_type']"
position="attributes"
>
<attribute
name="attrs"
>{'readonly':[('notification_type','=','mail_manual')]}</attribute>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

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

View File

@@ -7,16 +7,16 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
"depends": ["event", "website_event_track"], "depends": ["event", "website_event_track"],
"data": [ "data": [
'security/ir.model.access.csv', "security/ir.model.access.csv",
'views/event_sequence_views.xml', "views/event_sequence_views.xml",
'views/event_track_views.xml', "views/event_track_views.xml",
'views/event_event_views.xml', "views/event_event_views.xml",
'views/event_sequence_menu.xml', "views/event_sequence_menu.xml",
'data/event_sequence_data.xml', "data/event_sequence_data.xml",
], ],
"installable": True, "installable": True,
} }

View File

@@ -18,6 +18,7 @@ msgstr ""
#. module: event_sequence #. module: event_sequence
#: model:ir.model.fields,field_description:event_sequence.field_event_event__current_sequence_id #: model:ir.model.fields,field_description:event_sequence.field_event_event__current_sequence_id
#: model_terms:ir.ui.view,arch_db:event_sequence.view_event_form_event_sequence
msgid "Current sequence" msgid "Current sequence"
msgstr "Séquence en cours" msgstr "Séquence en cours"
@@ -45,12 +46,6 @@ msgstr "Séquence"
msgid "Sequences" msgid "Sequences"
msgstr "Séquences" msgstr "Séquences"
#. module: event_sequence
#: model_terms:ir.ui.view,arch_db:event_sequence.view_event_form_event_sequence
msgid "Current sequence"
msgstr "Séquence en cours"
#. module: event_sequence #. module: event_sequence
#: model_terms:ir.ui.view,arch_db:event_sequence.view_event_track_by_sequence_kanban #: model_terms:ir.ui.view,arch_db:event_sequence.view_event_track_by_sequence_kanban
msgid "hours" msgid "hours"

View File

@@ -1,3 +1,3 @@
from . import event_sequence from . import event_sequence
from . import event_track from . import event_track
from . import event_event from . import event_event

View File

@@ -1,9 +1,8 @@
from odoo import _, api, Command, fields, models from odoo import fields, models
from lxml import etree, html
from odoo.tools import format_time
class EventEvent(models.Model): class EventEvent(models.Model):
_inherit = "event.event" _inherit = "event.event"
sequence_number = fields.Integer('Number of sequences', default="5") sequence_number = fields.Integer("Number of sequences", default="5")
current_sequence_id = fields.Many2one('event.sequence', 'Current sequence') current_sequence_id = fields.Many2one("event.sequence", "Current sequence")

View File

@@ -5,5 +5,5 @@ from odoo import fields, models
class EventSequence(models.Model): class EventSequence(models.Model):
_name = "event.sequence" _name = "event.sequence"
name = fields.Char("name") name = fields.Char()
sequence = fields.Integer("Sequence") #for sorting sequence = fields.Integer() # for sorting

View File

@@ -1,21 +1,20 @@
from odoo import _, api, Command, fields, models from odoo import api, fields, models
from lxml import etree, html
from odoo.tools import format_time
class EventTrack(models.Model): class EventTrack(models.Model):
_inherit = "event.track" _inherit = "event.track"
sequence_id = fields.Many2one('event.sequence', 'Sequence', group_expand='_read_group_stage_ids') sequence_id = fields.Many2one(
sequence = fields.Integer('Sequence') #for sorting "event.sequence", "Sequence", group_expand="_read_group_stage_ids"
)
sequence = fields.Integer() # for sorting
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
if vals_list and 'sequence' not in vals_list[0]: if vals_list and "sequence" not in vals_list[0]:
vals_list[0]['sequence'] = 999 vals_list[0]["sequence"] = 999
tracks = super(EventTrack, self).create(vals_list) tracks = super().create(vals_list)
return tracks return tracks
@api.model @api.model
def _read_group_stage_ids(self, stages, domain, order): def _read_group_stage_ids(self, stages, domain, order):
@@ -25,8 +24,7 @@ class EventTrack(models.Model):
event_id = d[2] event_id = d[2]
if event_id: if event_id:
event = self.env['event.event'].browse(event_id) event = self.env["event.event"].browse(event_id)
return stages.search([], order="sequence", limit=event.sequence_number) return stages.search([], order="sequence", limit=event.sequence_number)
return stages.search([], order="sequence") return stages.search([], order="sequence")

View File

@@ -1,2 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_sequence,event.sequence,model_event_sequence,event.group_event_manager,1,1,1,1 access_event_sequence,event.sequence,model_event_sequence,event.group_event_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_event_sequence event.sequence model_event_sequence event.group_event_manager 1 1 1 1

View File

@@ -3,15 +3,19 @@
<record model="ir.ui.view" id="view_event_form_event_sequence"> <record model="ir.ui.view" id="view_event_form_event_sequence">
<field name="name">event.event.form.event.sequence</field> <field name="name">event.event.form.event.sequence</field>
<field name="model">event.event</field> <field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form" /> <field name="inherit_id" ref="event.view_event_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<label for="date_begin" position="before"> <label for="date_begin" position="before">
<field name="sequence_number" /> <field name="sequence_number" />
</label> </label>
<h1 position="after"> <h1 position="after">
<label for="current_sequence_id" string="Current sequence"/> <label for="current_sequence_id" string="Current sequence" />
<h4><field class="text-break" name="current_sequence_id" style="width:150px;" /></h4> <h4><field
class="text-break"
name="current_sequence_id"
style="width:150px;"
/></h4>
</h1> </h1>
</field> </field>
</record> </record>

View File

@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<menuitem id="event_sequence_menu" <menuitem
id="event_sequence_menu"
name="Sequences" name="Sequences"
action="event_sequence_action" action="event_sequence_action"
parent="event.menu_event_configuration" parent="event.menu_event_configuration"
sequence="31"/> sequence="31"
/>
</odoo> </odoo>

View File

@@ -2,7 +2,7 @@
<odoo> <odoo>
<record model="ir.ui.view" id="view_event_sequence_tree"> <record model="ir.ui.view" id="view_event_sequence_tree">
<field name="name">event.sequence</field> <field name="name">event.sequence</field>
<field name="model">event.sequence</field> <field name="model">event.sequence</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree editable="top"> <tree editable="top">
<field name="sequence" widget="handle" /> <field name="sequence" widget="handle" />
@@ -15,6 +15,6 @@
<field name="name">Sequences</field> <field name="name">Sequences</field>
<field name="res_model">event.sequence</field> <field name="res_model">event.sequence</field>
<field name="view_mode">tree</field> <field name="view_mode">tree</field>
<field name="view_id" ref="view_event_sequence_tree"/> <field name="view_id" ref="view_event_sequence_tree" />
</record> </record>
</odoo> </odoo>

View File

@@ -4,51 +4,108 @@
<field name="name">event.track.by.sequence.kanban</field> <field name="name">event.track.by.sequence.kanban</field>
<field name="model">event.track</field> <field name="model">event.track</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<kanban default_order="sequence" group_create="false" default_group_by="sequence_id" quick_create_view="website_event_track.event_track_view_form_quick_create"> <kanban
<field name="color"/> default_order="sequence"
<field name="partner_id"/> group_create="false"
default_group_by="sequence_id"
quick_create_view="website_event_track.event_track_view_form_quick_create"
>
<field name="color" />
<field name="partner_id" />
<field name="sequence_id" options="{'create':false}" /> <field name="sequence_id" options="{'create':false}" />
<field name="stage_id" options='{"group_by_tooltip": {"description": "Description"}}'/> <field
<field name="website_url"/> name="stage_id"
<field name="activity_ids"/> options='{"group_by_tooltip": {"description": "Description"}}'
<field name="activity_state"/> />
<field name="legend_blocked"/> <field name="website_url" />
<field name="legend_normal"/> <field name="activity_ids" />
<field name="legend_done"/> <field name="activity_state" />
<field name="legend_blocked" />
<field name="legend_normal" />
<field name="legend_done" />
<templates> <templates>
<progressbar field="kanban_state" colors='{"done": "success", "blocked": "danger"}'/> <progressbar
field="kanban_state"
colors='{"done": "success", "blocked": "danger"}'
/>
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click"> <div
<div class="o_dropdown_kanban dropdown" groups="base.group_user"> t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click"
>
<div
class="o_dropdown_kanban dropdown"
groups="base.group_user"
>
<a role="button" class="dropdown-toggle o-no-caret btn" data-bs-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu"> <a
<span class="fa fa-ellipsis-v"/> role="button"
class="dropdown-toggle o-no-caret btn"
data-bs-toggle="dropdown"
href="#"
aria-label="Dropdown menu"
title="Dropdown menu"
>
<span class="fa fa-ellipsis-v" />
</a> </a>
<div class="dropdown-menu" role="menu"> <div class="dropdown-menu" role="menu">
<a role="menuitem" t-att-href="record.website_url.value" class="dropdown-item">View Track</a> <a
<t t-if="widget.editable"><a role="menuitem" type="edit" class="dropdown-item">Edit Track</a></t> role="menuitem"
<t t-if="widget.deletable"><a role="menuitem" type="delete" class="dropdown-item">Delete</a></t> t-att-href="record.website_url.value"
<ul class="oe_kanban_colorpicker" data-field="color"/> class="dropdown-item"
>View Track</a>
<t t-if="widget.editable"><a
role="menuitem"
type="edit"
class="dropdown-item"
>Edit Track</a></t>
<t t-if="widget.deletable"><a
role="menuitem"
type="delete"
class="dropdown-item"
>Delete</a></t>
<ul
class="oe_kanban_colorpicker"
data-field="color"
/>
</div> </div>
</div> </div>
<div class="oe_kanban_content"> <div class="oe_kanban_content">
<div class="o_kanban_record_top"> <div class="o_kanban_record_top">
<h4 class="o_kanban_record_title"><field name="name"/></h4> <h4 class="o_kanban_record_title"><field
name="name"
/></h4>
</div> </div>
<div class="o_kanban_record_body"> <div class="o_kanban_record_body">
<t t-if="duration"><field name="duration" widget="float_time"/> hours</t> <t t-if="duration"><field
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/> name="duration"
widget="float_time"
/> hours</t>
<field
name="tag_ids"
widget="many2many_tags"
options="{'color_field': 'color'}"
/>
</div> </div>
<div class="o_kanban_record_bottom"> <div class="o_kanban_record_bottom">
<div class="oe_kanban_bottom_left"> <div class="oe_kanban_bottom_left">
<field name="priority" widget="priority"/> <field name="priority" widget="priority" />
<field name="activity_ids" widget="kanban_activity"/> <field
name="activity_ids"
widget="kanban_activity"
/>
</div> </div>
<div class="oe_kanban_bottom_right"> <div class="oe_kanban_bottom_right">
<field name="kanban_state" widget="state_selection" groups="base.group_user"/> <field
<img t-att-src="kanban_image('res.partner', 'avatar_128', record.partner_id.raw_value)" name="kanban_state"
t-att-title="record.partner_id.value" t-att-alt="record.partner_id.value" widget="state_selection"
class="oe_kanban_avatar"/> groups="base.group_user"
/>
<img
t-att-src="kanban_image('res.partner', 'avatar_128', record.partner_id.raw_value)"
t-att-title="record.partner_id.value"
t-att-alt="record.partner_id.value"
class="oe_kanban_avatar"
/>
</div> </div>
</div> </div>
</div> </div>
@@ -59,10 +116,19 @@
</field> </field>
</record> </record>
<record model="ir.actions.act_window.view" id="action_event_track_from_event_kanban"> <record
<field name="sequence" eval="1"/> model="ir.actions.act_window.view"
id="action_event_track_from_event_kanban"
>
<field name="sequence" eval="1" />
<field name="view_mode">kanban</field> <field name="view_mode">kanban</field>
<field name="act_window_id" ref="website_event_track.action_event_track_from_event"/> <field
<field name="view_id" ref="event_sequence.view_event_track_by_sequence_kanban"/> name="act_window_id"
ref="website_event_track.action_event_track_from_event"
/>
<field
name="view_id"
ref="event_sequence.view_event_track_by_sequence_kanban"
/>
</record> </record>
</odoo> </odoo>

View File

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

View File

@@ -5,12 +5,12 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
'summary': 'Not usefull anymore for CTL', "summary": "Not usefull anymore for CTL",
"category": "", "category": "",
"depends": ["website_event_track"], "depends": ["website_event_track"],
"data": [ "data": [
'views/event_track_views.xml', "views/event_track_views.xml",
], ],
"installable": True, "installable": True,
} }

View File

@@ -1,2 +1,2 @@
from . import event_track from . import event_track
#from . import event_event # from . import event_event

View File

@@ -6,5 +6,5 @@ class EventTrack(models.Model):
_inherit = "event.track" _inherit = "event.track"
speaker_ids = fields.Many2many( speaker_ids = fields.Many2many(
'res.partner', string="Speakers", domain="[('is_company','=',False)]" "res.partner", string="Speakers", domain="[('is_company','=',False)]"
) )

View File

@@ -3,9 +3,9 @@
<!-- Event form --> <!-- Event form -->
<record model="ir.ui.view" id="view_event_track_form_event_speaker"> <record model="ir.ui.view" id="view_event_track_form_event_speaker">
<field name="name">event.track.form.event.speaker</field> <field name="name">event.track.form.event.speaker</field>
<field name="model">event.track</field> <field name="model">event.track</field>
<field name="inherit_id" ref="website_event_track.view_event_track_form" /> <field name="inherit_id" ref="website_event_track.view_event_track_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<page name="speaker" position="inside"> <page name="speaker" position="inside">
<field name="speaker_ids" /> <field name="speaker_ids" />
</page> </page>

View File

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

View File

@@ -5,19 +5,17 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
'summary': 'Replace date of event track with list of calendar events', "summary": "Replace date of event track with list of calendar events",
'description': """ "description": """
Replace date of event track with list of calendar events Replace date of event track with list of calendar events
---------------------------------------------------- ----------------------------------------------------
* Create calendar events on event track form * Create calendar events on event track form
* Sync calendar event attendees with event track registration * Sync calendar event attendees with event track registration
""", """,
"depends": ["website_event_track","calendar"], "depends": ["website_event_track", "calendar"],
"data": [ "data": ["views/event_track_views.xml"],
"views/event_track_views.xml"
],
"installable": True, "installable": True,
} }

View File

@@ -1,4 +1,4 @@
from . import calendar_event from . import calendar_event
from . import event_track from . import event_track
from . import event_registration from . import event_registration
from . import event_event from . import event_event

View File

@@ -1,18 +1,16 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command from odoo import api, fields, models
class CalendarEvent(models.Model): class CalendarEvent(models.Model):
_inherit = 'calendar.event' _inherit = "calendar.event"
event_track_id = fields.Many2one('event.track', "Event track") event_track_id = fields.Many2one("event.track", "Event track")
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
res = super(CalendarEvent,self).create(vals_list) res = super().create(vals_list)
for event in res: for event in res:
if event.event_track_id: if event.event_track_id:
event.event_track_id.sync_calendar_event() event.event_track_id.sync_calendar_event()
return res return res

View File

@@ -1,14 +1,17 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
import logging import logging
from odoo import models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventEvent(models.Model): class EventEvent(models.Model):
_inherit = "event.event" _inherit = "event.event"
def write(self, vals): def write(self, vals):
res = super().write(vals) res = super().write(vals)
for event in self: for event in self:
for track in event.track_ids: for track in event.track_ids:
track.sync_calendar_event() track.sync_calendar_event()
return res return res

View File

@@ -1,22 +1,25 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
import logging import logging
from odoo import api, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventRegistration(models.Model): class EventRegistration(models.Model):
_inherit = "event.registration" _inherit = "event.registration"
def write(self, vals): def write(self, vals):
res = super(EventRegistration,self).write(vals) res = super().write(vals)
for registration in self: for registration in self:
for track in registration.event_id.track_ids: for track in registration.event_id.track_ids:
track.sync_calendar_event() track.sync_calendar_event()
return res return res
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
res = super(EventRegistration, self).create(vals_list) res = super().create(vals_list)
for registration in res: for registration in res:
for track in registration.event_id.track_ids: for track in registration.event_id.track_ids:
track.sync_calendar_event() track.sync_calendar_event()
return res return res

View File

@@ -1,84 +1,98 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
from datetime import timedelta
import logging import logging
from odoo import Command, api, fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventTrack(models.Model): class EventTrack(models.Model):
_inherit = "event.track" _inherit = "event.track"
calendar_event_ids = fields.One2many('calendar.event', 'event_track_id', 'Time slot', copy=True) calendar_event_ids = fields.One2many(
"calendar.event", "event_track_id", "Time slot", copy=True
)
date = fields.Datetime(compute="_compute_date") date = fields.Datetime(compute="_compute_date")
def _compute_date(self): def _compute_date(self):
"""Date become a field computed from first calendar event date """
Date become a field computed from first calendar event date.
""" """
for event_track in self: for event_track in self:
if event_track.calendar_event_ids: if event_track.calendar_event_ids:
event_track.date = event_track.calendar_event_ids.sorted(key=lambda r: r.start)[0].start event_track.date = event_track.calendar_event_ids.sorted(
key=lambda r: r.start
)[0].start
else: else:
event_track.date = None event_track.date = None
def get_calendar_event_values(self): def get_calendar_event_values(self):
"""return default values of calendar events """
Return default values of calendar events.
""" """
return { return {
# due to google calendar unexpected notifications, for the moment we disable attendees of calendar event # due to google calendar unexpected notifications, for the moment we
# disable attendees of calendar event
# uncomment following line to re-enable # uncomment following line to re-enable
#'partner_ids':[Command.set(self.get_calendar_event_partner_value())], #'partner_ids':[Command.set(self.get_calendar_event_partner_value())],
'partner_ids':[Command.set([])], "partner_ids": [Command.set([])],
'location':self.location_id.name if self.location_id else '', "location": self.location_id.name if self.location_id else "",
#'user_id':self.user_id.id, #'user_id':self.user_id.id,
'privacy':"confidential" "privacy": "confidential",
} }
def get_calendar_event_partner_value(self): def get_calendar_event_partner_value(self):
"""Compute list of partner ids for calendar event """
Compute list of partner ids for calendar event.
""" """
# compute list of attendees # compute list of attendees
partner_ids = [] partner_ids = []
# add event track contact # add event track contact
if self.partner_id: if self.partner_id:
partner_ids.append(self.partner_id.id) partner_ids.append(self.partner_id.id)
# add event registration attendees # add event registration attendees
partner_ids.extend([registration.partner_id.id for registration in self.event_id.registration_ids if registration.partner_id]) partner_ids.extend(
[
registration.partner_id.id
for registration in self.event_id.registration_ids
if registration.partner_id
]
)
return partner_ids return partner_ids
def sync_calendar_event(self): def sync_calendar_event(self):
"""synchronize calendar event values with event track data """
Synchronize calendar event values with event track data.
""" """
_logger.warning("sync_calendar_event...") _logger.warning("sync_calendar_event...")
for track in self: for track in self:
track.calendar_event_ids.with_context(no_mail_to_attendees=True).write(track.get_calendar_event_values()) track.calendar_event_ids.with_context(no_mail_to_attendees=True).write(
track.get_calendar_event_values()
)
_logger.warning("sync_calendar_event done !") _logger.warning("sync_calendar_event done !")
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
""" """
after creation of event track synchronise calendar event values After creation of event track synchronise calendar event values.
""" """
res = super(EventTrack, self).create(vals_list) res = super().create(vals_list)
res.sync_calendar_event() res.sync_calendar_event()
return res return res
def write(self, vals): def write(self, vals):
""" """
after modification of event track synchronise calendar event values After modification of event track synchronise calendar event values.
""" """
res = super().write(vals) res = super().write(vals)
self.sync_calendar_event() self.sync_calendar_event()
return res return res
def unlink(self): def unlink(self):
for track in self: for track in self:
for calendar_event in track.calendar_event_ids: for calendar_event in track.calendar_event_ids:
calendar_event.unlink() calendar_event.unlink()
return super(EventTrack, self).unlink() return super().unlink()

View File

@@ -2,7 +2,7 @@
<odoo> <odoo>
<record model="ir.ui.view" id="view_event_track_form_event_track_calendar_event"> <record model="ir.ui.view" id="view_event_track_form_event_track_calendar_event">
<field name="name">event.track.form.event.track.calendar.event</field> <field name="name">event.track.form.event.track.calendar.event</field>
<field name="inherit_id" ref="website_event_track.view_event_track_form" /> <field name="inherit_id" ref="website_event_track.view_event_track_form" />
<field name="model">event.track</field> <field name="model">event.track</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<!-- <!--
@@ -11,7 +11,11 @@
<!-- <field name="date" position="replace" /> --> <!-- <field name="date" position="replace" /> -->
<page name="speaker" position="before"> <page name="speaker" position="before">
<page name="calendar_events" string="Plages horaires"> <page name="calendar_events" string="Plages horaires">
<field name="calendar_event_ids" context="{'default_name':name}" colspan="2"> <field
name="calendar_event_ids"
context="{'default_name':name}"
colspan="2"
>
<tree default_order="start,stop" editable="bottom"> <tree default_order="start,stop" editable="bottom">
<field name="name" string="Name" invisible="1" /> <field name="name" string="Name" invisible="1" />
<field name="start" string="From" /> <field name="start" string="From" />

View File

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

View File

@@ -7,13 +7,11 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
'summary': 'Speaker management in calendar events of event tracks', "summary": "Speaker management in calendar events of event tracks",
"depends": ["event_track_calendar_event"], "depends": ["event_track_calendar_event"],
"data": [ "data": ["views/event_track_views.xml"],
"views/event_track_views.xml"
],
"installable": True, "installable": True,
"auto_install":True "auto_install": True,
} }

View File

@@ -1,2 +1,2 @@
from . import event_track from . import event_track
from . import calendar_event from . import calendar_event

View File

@@ -1,10 +1,15 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command from odoo import fields, models
class CalendarEvent(models.Model): class CalendarEvent(models.Model):
_inherit = 'calendar.event' _inherit = "calendar.event"
speaker_ids = fields.Many2many( speaker_ids = fields.Many2many(
'res.partner', "calendar_event_speaker_rel", "calendar_event_id", "speaker_id", string="Intervenants", domain="[('is_company','=',False)]" "res.partner",
"calendar_event_speaker_rel",
"calendar_event_id",
"speaker_id",
string="Intervenants",
domain="[('is_company','=',False)]",
) )

View File

@@ -1,28 +1,28 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command from odoo import fields, models
class EventTrack(models.Model): class EventTrack(models.Model):
_inherit = "event.track" _inherit = "event.track"
speaker_ids = fields.Many2many( speaker_ids = fields.Many2many(
'res.partner', string="Intervenants", compute="compute_speaker_ids" "res.partner", string="Intervenants", compute="_compute_speaker_ids"
) )
def compute_speaker_ids(self): def _compute_speaker_ids(self):
"""set speaker_ids as concat of all speakers of all events""" """
Set speaker_ids as concat of all speakers of all events.
"""
for track in self: for track in self:
speaker_ids = set() speaker_ids = set()
for event in track.calendar_event_ids: for event in track.calendar_event_ids:
speaker_ids.update(event.speaker_ids.ids) speaker_ids.update(event.speaker_ids.ids)
track.speaker_ids = list(speaker_ids) track.speaker_ids = list(speaker_ids)
def get_calendar_event_partner_value(self): def get_calendar_event_partner_value(self):
"""Add speaker ids to calendar event partners
""" """
res = super(EventTrack, self).get_calendar_event_partner_value() Add speaker ids to calendar event partners.
"""
res = super().get_calendar_event_partner_value()
res.extend(self.speaker_ids.ids) res.extend(self.speaker_ids.ids)
return res return res

View File

@@ -1,18 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record model="ir.ui.view" id="view_event_track_form_event_track_calendar_event_event_speaker"> <record
<field name="name">event.track.form.event.track.calendar.event.event.speaker</field> model="ir.ui.view"
<field name="inherit_id" ref="event_track_calendar_event.view_event_track_form_event_track_calendar_event" /> id="view_event_track_form_event_track_calendar_event_event_speaker"
>
<field
name="name"
>event.track.form.event.track.calendar.event.event.speaker</field>
<field
name="inherit_id"
ref="event_track_calendar_event.view_event_track_form_event_track_calendar_event"
/>
<field name="model">event.track</field> <field name="model">event.track</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='calendar_event_ids']/tree/field[@name='description']" position="after"> <xpath
<field name="speaker_ids" widget="many2many_tags"/> expr="//field[@name='calendar_event_ids']/tree/field[@name='description']"
position="after"
>
<field name="speaker_ids" widget="many2many_tags" />
</xpath> </xpath>
<!-- <xpath expr="//field[@name='calendar_event_ids']/form//field[@name='description']" position="after"> <!-- <xpath expr="//field[@name='calendar_event_ids']/form//field[@name='description']" position="after">
<field name="speaker_ids" /> <field name="speaker_ids" />
</xpath> --> </xpath> -->
</field> </field>
</record> </record>
</odoo> </odoo>

View File

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

View File

@@ -7,23 +7,21 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
'summary': 'Link event tracks locations to calendar event', "summary": "Link event tracks locations to calendar event",
'description': """ "description": """
Link event tracks locations to calendar event Link event tracks locations to calendar event
---------------------------------------------------- ----------------------------------------------------
* Add Partner field on event track location * Add Partner field on event track location
* Add partner "location" to calendar event * Add partner "location" to calendar event
* Update calendar event if event track location change (or partner in event track location) * Update calendar event if event track location change
(or partner in event track location)
* Alert if location is used * Alert if location is used
""", """,
"depends": ["website_event_track","calendar"], "depends": ["website_event_track", "calendar"],
"data": [ "data": ["views/event_track_location_views.xml", "views/event_track_views.xml"],
'views/event_track_location_views.xml',
'views/event_track_views.xml'
],
"installable": True, "installable": True,
} }

View File

@@ -1,2 +1,2 @@
from . import event_track from . import event_track
from . import event_track_location from . import event_track_location

View File

@@ -1,17 +1,19 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command, _ from odoo import api, fields, models
from datetime import timedelta
from odoo.tools import format_date from odoo.tools import format_date
class EventTrack(models.Model): class EventTrack(models.Model):
_inherit = "event.track" _inherit = "event.track"
location_already_in_use = fields.Boolean('Location already in use', compute='_compute_location_already_in_use') location_already_in_use = fields.Boolean(
location_already_in_use_message = fields.Text(compute='_compute_location_already_in_use') "Location already in use", compute="_compute_location_already_in_use"
)
location_already_in_use_message = fields.Text(
compute="_compute_location_already_in_use"
)
@api.depends('date', 'duration', 'location_id') @api.depends("date", "duration", "location_id")
def _compute_location_already_in_use(self): def _compute_location_already_in_use(self):
for track in self: for track in self:
location_already_in_use = False location_already_in_use = False
@@ -21,40 +23,59 @@ class EventTrack(models.Model):
for calendar_event in track.calendar_event_ids: for calendar_event in track.calendar_event_ids:
if track.location_id and calendar_event.start: if track.location_id and calendar_event.start:
# search if other calendar event exists for same day on
# same location
search_other_calendar_events = [
("event_track_id.location_id", "=", track.location_id.id),
("start", ">=", calendar_event.start.replace(hour=0, minute=0)),
(
"start",
"<=",
calendar_event.start.replace(hour=23, minute=59),
),
]
#search if other calendar event exists for same day on same location # search only on other event tracks
search_other_calendar_events = [('event_track_id.location_id','=',track.location_id.id),('start','>=',calendar_event.start.replace(hour=0,minute=0)),('start','<=',calendar_event.start.replace(hour=23,minute=59))]
#search only on other event tracks
if track.id or track.id.origin: if track.id or track.id.origin:
search_other_calendar_events.append(('event_track_id','!=',track.id or track.id.origin)) search_other_calendar_events.append(
("event_track_id", "!=", track.id or track.id.origin)
)
#search calendar events not already founded # search calendar events not already founded
if already_found_other_calendar_event_ids: if already_found_other_calendar_event_ids:
search_other_calendar_events.append(('id','not in',already_found_other_calendar_event_ids)) search_other_calendar_events.append(
("id", "not in", already_found_other_calendar_event_ids)
other_calendar_events = self.env["calendar.event"].search(search_other_calendar_events) )
already_found_other_calendar_event_ids.extend(other_calendar_events.ids)
other_calendar_events = self.env["calendar.event"].search(
search_other_calendar_events
)
already_found_other_calendar_event_ids.extend(
other_calendar_events.ids
)
if other_calendar_events: if other_calendar_events:
location_already_in_use = True location_already_in_use = True
for other_calendar_event in other_calendar_events: for other_calendar_event in other_calendar_events:
location_already_in_use_message += other_calendar_event.event_track_id.event_id.name+" - "+\ location_already_in_use_message += (
other_calendar_event.event_track_id.name+\ other_calendar_event.event_track_id.event_id.name
" ("+format_date(self.env, other_calendar_event.start)+")"+"\n" + " - "
+ other_calendar_event.event_track_id.name
+ " ("
+ format_date(self.env, other_calendar_event.start)
+ ")"
+ "\n"
)
track.location_already_in_use = location_already_in_use track.location_already_in_use = location_already_in_use
track.location_already_in_use_message = location_already_in_use_message track.location_already_in_use_message = location_already_in_use_message
def get_calendar_event_partner_value(self): def get_calendar_event_partner_value(self):
"""Add event track location partner to list of partner ids """
Add event track location partner to list of partner ids.
""" """
res = super(EventTrack, self).get_calendar_event_partner_value() res = super().get_calendar_event_partner_value()
if self.location_id and self.location_id.partner_id: if self.location_id and self.location_id.partner_id:
res.append(self.location_id.partner_id.id) res.append(self.location_id.partner_id.id)
return res return res

View File

@@ -1,17 +1,22 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api from odoo import fields, models
class EventTrackLocation(models.Model): class EventTrackLocation(models.Model):
_inherit = 'event.track.location' _inherit = "event.track.location"
partner_id = fields.Many2one(
"res.partner", "Address", domain="[('is_company','=',True)]"
)
partner_id = fields.Many2one('res.partner', 'Address', domain="[('is_company','=',True)]")
def write(self, vals): def write(self, vals):
"""update calendar events related to event tracks if partner change
""" """
res = super(EventTrackLocation, self).write(vals) Update calendar events related to event tracks if partner change.
if 'partner_id' in vals: """
event_tracks = self.env['event.track'].search([('location_id','in',self.ids)]) res = super().write(vals)
if "partner_id" in vals:
event_tracks = self.env["event.track"].search(
[("location_id", "in", self.ids)]
)
event_tracks.sync_calendar_event() event_tracks.sync_calendar_event()
return res return res

View File

@@ -1,9 +1,14 @@
<?xml version="1.0"?> <?xml version="1.0" ?>
<odoo> <odoo>
<!-- EVENTS/CONFIGURATION/EVENT locations --> <!-- EVENTS/CONFIGURATION/EVENT locations -->
<record model="ir.ui.view" id="view_event_location_form_inherit_event_track_location_calendar"> <record
<field name="name">Event Locations inherit for event track location calendar</field> model="ir.ui.view"
id="view_event_location_form_inherit_event_track_location_calendar"
>
<field
name="name"
>Event Locations inherit for event track location calendar</field>
<field name="model">event.track.location</field> <field name="model">event.track.location</field>
<field name="inherit_id" ref="website_event_track.view_event_location_form" /> <field name="inherit_id" ref="website_event_track.view_event_location_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
@@ -13,7 +18,10 @@
</field> </field>
</record> </record>
<record model="ir.ui.view" id="view_event_location_tree_inherit_event_track_location_calendar"> <record
model="ir.ui.view"
id="view_event_location_tree_inherit_event_track_location_calendar"
>
<field name="name">Event Location</field> <field name="name">Event Location</field>
<field name="model">event.track.location</field> <field name="model">event.track.location</field>
<field name="inherit_id" ref="website_event_track.view_event_location_tree" /> <field name="inherit_id" ref="website_event_track.view_event_location_tree" />

View File

@@ -1,16 +1,27 @@
<?xml version="1.0"?> <?xml version="1.0" ?>
<odoo> <odoo>
<record model="ir.ui.view" id="view_event_track_form_inherit_event_track_location_calendar"> <record
<field name="name">event.track.form inherit for event track location calendar</field> model="ir.ui.view"
id="view_event_track_form_inherit_event_track_location_calendar"
>
<field
name="name"
>event.track.form inherit for event track location calendar</field>
<field name="model">event.track</field> <field name="model">event.track</field>
<field name="inherit_id" ref="website_event_track.view_event_track_form" /> <field name="inherit_id" ref="website_event_track.view_event_track_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//header" position="after"> <xpath expr="//header" position="after">
<field name="location_already_in_use" invisible="1" /> <field name="location_already_in_use" invisible="1" />
<div attrs="{'invisible':[('location_already_in_use','=',False)]}" class="alert alert-warning mb-0" role="alert"> <div
<strong>Location already in use for this date !</strong><field name="location_already_in_use_message" /> attrs="{'invisible':[('location_already_in_use','=',False)]}"
class="alert alert-warning mb-0"
role="alert"
>
<strong>Location already in use for this date !</strong><field
name="location_already_in_use_message"
/>
</div> </div>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

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

View File

@@ -7,15 +7,13 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
'summary': 'Copy website event tracks when copy event', "summary": "Copy website event tracks when copy event",
'description': """Copy website event tracks when copy event "description": """Copy website event tracks when copy event
""", """,
"depends": ["website_event_track"], "depends": ["website_event_track"],
"data": [ "data": [],
],
"installable": True, "installable": True,
} }

View File

@@ -1,2 +1,2 @@
from . import event_track from . import event_track
from . import event_event from . import event_event

View File

@@ -1,9 +1,12 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
import logging import logging
from odoo import fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventEvent(models.Model): class EventEvent(models.Model):
_inherit = "event.event" _inherit = "event.event"
track_ids = fields.One2many(copy=True) #enable copy for event tracks track_ids = fields.One2many(copy=True) # enable copy for event tracks

View File

@@ -1,12 +1,14 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, Command
from datetime import timedelta
import logging import logging
from odoo import fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class EventTrack(models.Model): class EventTrack(models.Model):
_inherit = "event.track" _inherit = "event.track"
event_id = fields.Many2one(ondelete='cascade') #delete event tracks when delete event event_id = fields.Many2one(
ondelete="cascade"
) # delete event tracks when delete event

View File

View File

@@ -7,11 +7,11 @@
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Elabore", "author": "Elabore",
"website": "https://www.elabore.coop", "website": "https://github.com/elabore-coop/event-tools",
"category": "", "category": "",
"depends": ["event"], "depends": ["event"],
"data": [ "data": [
'views/event_type_views.xml', "views/event_type_views.xml",
], ],
"installable": True, "installable": True,
} }

View File

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<record id="event_type_form_view" model="ir.ui.view"> <record id="event_type_form_view" model="ir.ui.view">
<field name="name">event.type.form</field> <field name="name">event.type.form</field>
<field name="model">event.type</field> <field name="model">event.type</field>
<field eval="7" name="priority"/> <field eval="7" name="priority" />
<field name="inherit_id" ref="event.view_event_type_form"/> <field name="inherit_id" ref="event.view_event_type_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<div name="event_type_title" position="before"> <div name="event_type_title" position="before">
<div name="button_box" class="oe_button_box" /> <div name="button_box" class="oe_button_box" />
</div> </div>
</field> </field>
</record> </record>
</odoo> </odoo>