24 KiB
24 KiB
Créer son module pour Odoo
Configurer l'environnement de déploiement
Il nous faut ajouter certaines librairies python au projet.
Pour cela nous allons:
- ajouter un fichier
requirements.txtau dossieretc - ajouter un script
entrypoint.shqui sera lancé par le compose
Fichier etc/requirements.txt
??? note "requirements.txt"
astor python-stdnum>=1.18 python-magic requests_oauthlib factur-x unicodecsv email-validator py3o.template py3o.formats pypdf2 python-jose plotly==5.4.0
Fichier entrypoint.sh
??? note "entrypoint.sh" ``` #!/bin/bash
set -e
# set the postgres database host, port, user and password according to the environment
# and pass them as arguments to the odoo process if not present in the config file
: ${HOST:=${DB_PORT_5432_TCP_ADDR:='db'}}
: ${PORT:=${DB_PORT_5432_TCP_PORT:=5432}}
: ${USER:=${DB_ENV_POSTGRES_USER:=${POSTGRES_USER:='odoo'}}}
: ${PASSWORD:=${DB_ENV_POSTGRES_PASSWORD:=${POSTGRES_PASSWORD:='odoo'}}}
# install python packages
pip3 install pip --upgrade
pip3 install -r /etc/odoo/requirements.txt
# sed -i 's|raise werkzeug.exceptions.BadRequest(msg)|self.jsonrequest = {}|g' /usr/lib/python3/dist-packages/odoo/http.py
DB_ARGS=()
function check_config() {
param="$1"
value="$2"
if grep -q -E "^\s*\b${param}\b\s*=" "$ODOO_RC" ; then
value=$(grep -E "^\s*\b${param}\b\s*=" "$ODOO_RC" |cut -d " " -f3|sed 's/["\n\r]//g')
fi;
DB_ARGS+=("--${param}")
DB_ARGS+=("${value}")
}
check_config "db_host" "$HOST"
check_config "db_port" "$PORT"
check_config "db_user" "$USER"
check_config "db_password" "$PASSWORD"
case "$1" in
-- | odoo)
shift
if [[ "$1" == "scaffold" ]] ; then
exec odoo "$@"
else
wait-for-psql.py ${DB_ARGS[@]} --timeout=30
exec odoo "$@" "${DB_ARGS[@]}"
fi
;;
-*)
wait-for-psql.py ${DB_ARGS[@]} --timeout=30
exec odoo "$@" "${DB_ARGS[@]}"
;;
*)
exec "$@"
esac
exit 1
```
Créer un script d'installation automatisée
Ce script python va permettre d'automatiser l'installation des modules de base
??? note "init.py" ``` import odoorpc import subprocess import os import shutil import time
# Configuration
ODOO_URL = 'http://localhost:10014'
ODOO_DB = 'odoo'
ODOO_USERNAME = 'garagenum@gmail.com'
ODOO_PASSWORD = 'bellinux'
# Applications to install
APPS_TO_INSTALL = [
'sale_management',
'account',
'crm',
'website',
'stock',
'purchase',
'project',
'mass_mailing',
'hr_expense',
'hr_holidays',
'hr_recruitment',
'hr',
'website_slides',
'mail',
'contacts',
'calendar',
'survey',
'board',
'mass_mailing_sms',
'note',
'website_forum',
'hr_skills',
'website_hr_recruitment',
'hr_contract',
'stock_account',
'website_sms',
'purchase_stock',
'account_edi',
'account_edi_facturx',
'account_edi_ubl',
'account_payment',
'account_qr_code_sepa',
'analytic',
'attachment_indexation',
'auth_oauth',
'auth_signup',
'auth_totp',
'auth_totp_portal',
'barcodes',
'base',
'base_automation',
'base_iban',
'base_import',
'base_setup',
'base_vat',
'bus',
'calendar_sms',
'delivery',
'digest',
'fetchmail',
'google_recaptcha',
'hr_gamification',
'hr_org_chart',
'hr_skills_slides',
'hr_skills_survey',
'iap',
'iap_mail',
'l10n_fr',
'link_tracker',
'mail_bot',
'mail_bot_hr',
'mass_mailing_sale',
'mass_mailing_slides',
'payment',
'payment_fix_register_token',
'payment_transfer',
'portal_rating',
'procurement_jit',
'product',
'rating',
'resource',
'sale',
'sale_expense',
'sale_project',
'sale_purchase',
'sale_purchase_stock',
'sale_stock',
'sales_team',
'sms',
'snailmail',
'snailmail_account',
'social_media',
'stock_sms',
'uom',
'utm',
'web',
'web_editor',
'web_kanban_gauge',
'web_tour',
'web_unsplash',
'website_form',
'website_form_project',
'website_links',
'website_mail',
'website_mass_mailing',
'website_partner',
'website_profile',
'website_slides_forum',
'website_slides_survey',
'gamification',
'portal',
'http_routing',
'phone_validation',
'partner_autocomplete'
]
MODULES_TO_INSTALL = [
{ 'url': 'https://github.com/OCA/account-analytic',
'apps': [
{'name': 'account_move_update_analytic'},
{'name': '/analytic_distribution_widget_remove_save'},
]},
{ 'url': 'https://github.com/OCA/account-budgeting',
'apps': [
{'name': 'account_budget_oca'},
]},
{ 'url': 'https://github.com/OCA/account-closing',
'apps': [
{'name': 'account_cutoff_base'},
{'name': 'account_invoice_start_end_dates'},
{'name': 'account_cutoff_start_end_dates'},
{'name': 'account_cutoff_accrual_picking'},
{'name': 'account_cutoff_accrual_subscription'},
]},
{ 'url': 'https://github.com/OCA/account-financial-reporting',
'apps': [
{'name': 'account_financial_report'},
{'name': 'mis_builder_cash_flow'},
]},
{ 'url': 'https://github.com/OCA/account-financial-tools',
'apps': [
{'name': 'account_asset_management'},
{'name': 'account_cash_deposit'},
{'name': 'account_fiscal_year'},
{'name': 'account_move_budget'},
{'name': 'account_move_line_purchase_info'},
{'name': 'account_move_line_sale_info'},
{'name': 'account_move_template'},
{'name': 'account_netting'},
{'name': 'account_template_active'},
{'name': 'account_usability'},
]},
{ 'url': 'https://github.com/OCA/account-invoice-reporting',
'apps': [
{'name': 'account_comment_template'},
{'name': 'partner_time_to_pay'},
{'name': 'account_invoice_line_report'},
]},
{ 'url': 'https://github.com/OCA/account-invoicing',
'apps': [
{'name': 'account_invoice_fixed_discount'},
{'name': 'account_invoice_payment_term_date_due'},
{'name': 'account_invoice_refund_line_selection'},
{'name': 'account_invoice_refund_link'},
{'name': 'account_menu_invoice_refund'},
{'name': 'account_move_tier_validation'},
{'name': 'account_tax_group_widget_base_amount'},
{'name': 'partner_invoicing_mode'},
{'name': 'partner_invoicing_mode_monthly'},
]},
{ 'url': 'https://github.com/OCA/account-financial-reporting',
'apps': [
{'name': 'account_financial_report'},
{'name': 'mis_builder_cash_flow'},
]},
{ 'url': 'https://github.com/OCA/account-payment',
'apps': [
{'name': 'account_payment_notification'},
{'name': 'account_due_list'},
]},
{'url': 'https://github.com/OCA/account-reconcile',
'apps': [
{'name': 'account_reconciliation_widget'},
{'name': 'account_partner_reconcile'},
{'name': 'account_move_base_import'},
{'name': 'account_move_line_reconcile_manual'},
{'name': 'account_reconcile_oca'},
{'name': 'account_statement_base'},
]},
{'url': 'https://github.com/OCA/agreement',
'apps': [
{'name': 'agreement'},
{'name': 'agreement_legal'},
]},
{'url': 'https://github.com/OCA/bank-payment',
'apps': [
{'name': 'account_payment_mode'},
]},
{'url': 'https://github.com/OCA/bank-statement-import',
'apps': [
{'name': 'account_statement_import_base'},
{'name': 'account_statement_import_file'},
{'name': 'account_statement_import_online'},
{'name': 'account_statement_import_sheet_file'},
]},
{'url': 'https://github.com/OCA/community-data-files',
'apps': [
{'name': 'base_unece'},
{'name': 'account_payment_unece'},
{'name': 'account_tax_unece'},
{'name': 'base_currency_iso_4217'},
{'name': 'base_iso3166'},
{'name': 'company_sanitary_registry'},
{'name': 'uom_unece'},
]},
{'url': 'https://github.com/OCA/data-protection',
'apps': [
{'name': 'privacy'},
{'name': 'privacy_consent'},
]},
{'url': 'https://github.com/OCA/dms',
'apps': [
{'name': 'dms'},
]},
{'url': 'https://github.com/OCA/donation',
'apps': [
{'name': 'donation_base'},
{'name': 'donation'},
{'name': 'donation_bank_statement_oca'}
]},
{'url': 'https://github.com/OCA/edi',
'apps': [
{'name': 'account_einvoice_generate'},
{'name': 'account_invoice_facturx'},
{'name': 'account_invoice_facturx_py3o'},
{'name': 'base_business_document_import'},
{'name': 'base_edi'},
{'name': 'base_facturx'},
{'name': 'pdf_helper'},
]},
{'url': 'https://github.com/OCA/hr',
'apps': [
{'name': 'hr_course'},
{'name': 'hr_employee_age'},
{'name': 'hr_employee_birthday_mail'},
{'name': 'hr_employee_calendar_planning'},
{'name': 'hr_employee_document'},
{'name': 'hr_employee_firstname'},
{'name': 'hr_holidays_settings'},
{'name': 'hr_personal_equipment_request'},
]}
{'url': 'https://github.com/OCA/hr-expense',
'apps': [
{'name': 'hr_expense_cancel'},
{'name': 'hr_expense_invoice'},
{'name': 'hr_expense_payment'},
{'name': 'hr_expense_tier_validation'},
]},
{'url': 'https://github.com/OCA/hr-holidays',
'apps': [
{'name': 'hr_holidays_natural_period'},
{'name': 'hr_holidays_public'},
]},
{'url': 'https://github.com/OCA/knowledge',
'apps': [
{'name': 'document_knowledge'},
{'name': 'document_page'},
{'name': 'document_page_approval'},
{'name': 'document_page_group'},
{'name': 'document_page_reference'},
{'name': 'document_page_tag'},
{'name': 'document_url'}
]},
{ 'url': 'https://github.com/OCA/l10n-france',
'apps': [
{'name': 'l10n_fr_account_invoice_facturx'},
{'name': 'l10n_fr_account_tax_unece'},
{'name': 'l10n_fr_account_vat_return'},
{'name': 'l10n_fr_account_vat_return_teledec'},
{'name': 'l10n_fr_chorus_account'},
{'name': 'l10n_fr_chorus_facturx'},
{'name': 'l10n_fr_chorus_sale'},
{'name': 'l10n_fr_department'},
{'name': 'l10n_fr_department_oversea'},
{'name': 'l10n_fr_fec_oca'},
{'name': 'l10n_fr_hr_check_ssnid'},
{'name': 'l10n_fr_mis_reports'},
{'name': 'l10n_fr_oca},
{'name': 'l10n_fr_siret'},
{'name': 'l10n_fr_siret_lookup'},
]},
{ 'url': 'https://github.com/OCA/mis-builder',
'apps': [
{'name': 'mis_builder'},
{'name': 'mis_builder_budget'}
]},
{'url': 'https://github.com/OCA/partner-contact',
'apps': [
{'name': 'partner_address_street3'},
{'name': 'partner_address_two_lines'},
{'name': 'partner_company_type'},
{'name': 'partner_contact_access_link'},
{'name': 'partner_contact_address_default'},
{'name': 'partner_email_check'},
{'name': 'partner_email_duplicate_warn'},
{'name': 'partner_firstname'},
{'name': 'partner_mobile_duplicate_warn'},
{'name': 'partner_subject_to_vat'},
{'name': 'partner_vat_unique'},
]},
{'url': 'https://github.com/OCA/payroll',
'apps': [
{'name': 'payroll'},
{'name': 'payroll_account'}
]},
{'url': 'https://github.com/OCA/project',
'apps': [
{'name': 'project_department'},
{'name': 'project_duplicate_subtask'},
{'name': 'project_hr'},
{'name': 'project_list'},
{'name': 'project_parent'},
{'name': 'project_parent_task_filter'},
{'name': 'project_task_add_very_high'},
{'name': 'project_task_link'},
{'name': 'project_task_stage_mgmt'},
{'name': 'project_template'},
{'name': 'project_timeline'},
{'name': 'project_timeline_hr_timesheet'},
{'name': 'project_timesheet_time_control'},
]},
{'url': 'https://github.com/OCA/reporting-engine',
'apps': [
{'name': 'bi_view_editor'},
{'name': 'bi_view_editor_spreadsheet_dashboard'},
{'name': 'report_py3o'},
{'name': 'report_qweb_pdf_watermark'},
{'name': 'report_wkhtmltopdf_param'},
]},
{'url': 'https://github.com/OCA/sale-workflow',
'apps': [
{'name': 'partner_sale_pivot'},
{'name': 'product_form_sale_link'},
{'name': 'sale_advance_payment},
{'name': 'sale_cancel_reason'},
{'name': 'sale_delivery_state'},
{'name': 'sale_discount_display_amount'},
{'name': 'sale_fixed_discount'},
{'name': 'sale_force_invoiced'},
{'name': 'sale_order_general_discount'}
{'name': 'sale_order_invoice_amount'},
{'name': 'sale_order_line_menu'},
{'name': 'sale_order_line_tag'},
{'name': 'sale_order_revision'},
{'name': 'sale_start_end_dates'},
{'name': 'sale_substate'},
{'name': 'sale_tier_validation'},
]},
{'url': 'https://github.com/OCA/server-auth',
'apps': [
{'name': 'auth_oidc'},
]},
{'url': 'https://github.com/OCA/server-brand',
'apps': [
{'name': 'disable_odoo_online'},
{'name': 'hr_expense_remove_mobile_link'},
{'name': 'portal_odoo_debranding'},
{'name': 'remove_odoo_enterprise'},
]},
{'url': 'https://github.com/OCA/server-tools',
'apps': [
{'name': 'attachment_unindex_content'},
{'name': 'base_fontawesome'},
{'name': 'base_name_search_improved'},
{'name': 'base_view_inheritance_extension'},
{'name': 'iap_alternative_provider'},
{'name': 'module_auto_update'},
]},
{ 'url': 'https://github.com/OCA/server-ux',
'apps': [
{'name': 'base_cancel_confirm'},
{'name': 'base_custom_filter'},
{'name': 'base_menu_visibility_restriction'},
{'name': 'base_optional_quick_create'},
{'name': 'base_revision'},
{'name': 'base_search_custom_field_filter'},
{'name': 'base_substate'},
{'name': 'base_technical_features'},
{'name': 'base_tier_validation'},
{'name': 'date_range'},
{'name': 'date_range_account'},
{'name': 'filter_multi_user'},
{'name': 'multi_step_wizard'},
{'name': 'user_all_groups'}
]},
{'url': 'https://github.com/OCA/sign',
'apps': [
{'name': 'sign_oca'},
]}
{'url': 'https://github.com/OCA/social',
'apps': [
{'name': 'base_search_mail_content'},
{'name': 'email_template_qweb'},
{'name': 'mail_activity_board'},
{'name': 'mail_activity_done'},
{'name': 'mail_attach_existing_attachment'},
{'name': 'mail_composer_cc_bcc'},
{'name': 'mail_debrand'},
{'name': 'mail_layout_preview'},
{'name': 'mail_inline_css'},
{'name': 'mail_optional_follower_notification'},
{'name': 'mail_tracking'},
{'name': 'mail_tracking_mass_mailing'},
{'name': 'mass_mailing_list_dynamic'},
{'name': 'mass_mailing_partner'},
{'name': 'mass_mailing_resend'},
{'name': 'mass_mailing_unique'},
]},
{'url': 'https://github.com/OCA/spreadsheet',
'apps': [
{'name': 'spreadsheet_dashboard_oca'},
{'name': 'spreadsheet_oca'},
]},
{'url': 'https://github.com/OCA/survey',
'apps': [
{'name': 'survey_question_type_five_star'},
]},
{'url': 'https://github.com/OCA/timesheet',
'apps': [
{'name': 'hr_timesheet_begin_end'}
{'name': 'hr_timesheet_sheet'},
{'name': 'hr_timesheet_task_domain'},
{'name': 'hr_timesheet_time_type'},
{'name': '}
]}
{'url': 'https://github.com/OCA/vertical-association',
'apps': [
{'name: 'web_advanced_search'},
{'name': 'web_calendar_slot_duration'},
{'name': 'web_chatter_position'},
{'name': 'web_dark_mode'},
{'name': 'web_dialog_size'},
{'name': 'web_group_expand'},
{'name': 'web_help'},
{'name': 'web_ir_actions_act_window_page'},
{'name': 'web_listview_range_select'},
{'name': 'web_m2x_options'},
{'name': 'web_no_bubble'},
{'name': 'web_remember_tree_column_width'},
{'name': 'web_responsive'},
{'name': 'web_search_with_and'},
{'name': 'web_theme_classic'},
{'name': 'web_timeline'},
{'name': 'web_tree_many2one_clickable'},
{'name': 'web_widget_dropdown_dynamic'},
{'name': 'web_widget_numeric_step'},
{'name': 'web_widget_open_tab'},
{'name': 'web_widget_plotly_chart'}
]},
{'url': 'https://github.com/OCA/website',
'apps': [
{'name': 'website_odoo_debranding'},
]},
{'url': 'https://github.com/OCA/website-cms',
'apps': [
{'name': 'cms_form'},
{'name': 'cms_status_message'}
]}
# {'url': 'https://git.legaragenumerique.fr/odoo/gn_odoo',
# 'apps': [
# {'name': 'gn_discount'},
# {'name': 'gn_donations'}
# ]},
]
def configure_folders():
#os.makedirs('addons', exist_ok=True)
subprocess.run(["setfacl", "-m", "u:101:rwx", './addons'], check=True)
subprocess.run(["setfacl", "-d", "-m", "u:101:rwx", './addons'], check=True)
subprocess.run(["setfacl", "-m", "u:101:rwx", './etc'], check=True)
subprocess.run(["setfacl", "-d", "-m", "u:101:rwx", './etc'], check=True)
def merge_directories(src, dst):
for item in os.listdir(src):
if item != '.git':
s = os.path.join(src, item)
d = os.path.join(dst, item)
if os.path.isdir(s):
if not os.path.exists(d):
shutil.copytree(s, d)
else:
merge_directories(s, d)
else:
shutil.copy2(s, d)
def connect_odoo():
# Connect to the Odoo server
odoo = odoorpc.ODOO('localhost', port=10014)
odoo.login(ODOO_DB, ODOO_USERNAME, ODOO_PASSWORD)
return odoo
def install_app(odoo, odoo_app):
# Check if each module is installed or not
print(f"Checking {odoo_app} installation...")
module_id = odoo.env['ir.module.module'].search([('name', '=', odoo_app)])
if module_id:
module = odoo.env['ir.module.module'].browse(module_id)[0]
if module.state not in ['installed', 'to upgrade']:
time.sleep(0.3)
module.button_immediate_install()
print(f"Module {odoo_app} has been installed.")
else:
print(f"Module {odoo_app} is already installed.")
else:
print(f"Module {odoo_app} not found.")
def install_apps(odoo):
for odoo_app in APPS_TO_INSTALL:
install_app(odoo, odoo_app)
time.sleep(1)
def dl_modules(group):
repo_url = group['url'].rstrip('/')
addons_path = "addons"
sparse_checkout_lines = []
for app in group['apps']:
if app['name'] != None:
app_dir = app['dir'] if 'dir' in app else app['name']
sparse_checkout_lines.append(f"{app_dir}\n")
clone_path = 'tmp' if group['apps'][0]['name'] != None else os.path.join('tmp', group['url'].split('/')[-1])
clone_full_path = os.path.join(addons_path, clone_path)
git_dir_path = os.path.join(clone_full_path, '.git')
sparse_checkout_file_path = os.path.join(git_dir_path, 'info', 'sparse-checkout')
branch_name = "16.0"
print("starting git clone")
subprocess.run(["git", "clone", "--filter=blob:none", "--sparse", "--branch", branch_name, "--depth", "1", repo_url, clone_path], cwd=addons_path, check=True)
if not os.path.isdir(sparse_checkout_file_path):
subprocess.run(["git", "config", "core.sparseCheckout", "true"], cwd=clone_full_path, check=True)
with open(sparse_checkout_file_path, "w") as sparse_checkout_file:
sparse_checkout_file.writelines(sparse_checkout_lines)
print("starting git checkout")
subprocess.run(["git", "checkout", branch_name], cwd=clone_full_path, check=True)
src_path = os.path.join(addons_path, 'tmp')
merge_directories(src_path, addons_path)
shutil.rmtree(src_path)
print(f"Modules {', '.join(app['name'] if app['name'] else group['url'] for app in group['apps'])} has been downloaded")
def update_module_list(odoo):
ModuleUpdate = odoo.env['base.module.update']
module_update_id = ModuleUpdate.create({})
module_update = ModuleUpdate.browse(module_update_id)
module_update.update_module()
updated_modules = module_update.updated
added_modules = module_update.added
print(f"Updated modules: {updated_modules}, Added modules: {added_modules}")
def install_modules(odoo):
for group in MODULES_TO_INSTALL:
dl_modules(group)
time.sleep(1)
update_module_list(odoo)
time.sleep(1)
for group in MODULES_TO_INSTALL:
for app in group['apps']:
app_name = app['name'] if app['name'] != None else group['url'].split('/')[-1]
install_app(odoo, app_name)
def main():
configure_folders()
odoo = connect_odoo()
install_apps(odoo)
time.sleep(3)
install_modules(odoo)
print("Script execution finished!")
main()
```