Skip to content

Créer son module pour Odoo

1. Configurer l'environnement de déploiement

Il nous faut ajouter certaines librairies python au projet.

Pour cela nous allons: - ajouter un fichier requirements.txt au dossier etc - ajouter un script entrypoint.sh qui sera lancé par le compose

1.1 Fichier etc/requirements.txt

requirements.txt
astor
python-stdnum>=1.18
requests_oauthlib
factur-x
unicodecsv

1.2 Fichier entrypoint.sh

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

2. Créer un script d'installation automatisée

Ce script python va permettre d'automatiser l'installation des modules de base

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 = [
    'account',
    'sale_management',
    'purchase',
    'hr',
    'contacts',
    'hr_expense',
    'project',
    'stock',
    'membership',
    'website',
    'mass_mailing',
    'partner_autocomplete',
    'hr_recruitment',
    'survey',
    'board',
    'mass_mailing_sms',
    'note',
    'website_forum',
    'hr_skills',
    'hr_holidays',
    'website_hr_recruitment',
    'hr_contract',
    'website_slides',
    'board',
    'base_automation',
    'delivery',
    'l10n_fr'
]

MODULES_TO_INSTALL = [
    {'url': 'https://github.com/odoomates/odooapps', 
    'apps': [
        {'name': 'accounting_pdf_reports'},
        {'name': 'om_account_asset'},
        {'name': 'om_account_bank_statement_import'},
        {'name': 'om_account_budget'},
        {'name': 'om_fiscal_year'},
        {'name': 'om_recurring_payments'},
        {'name': 'om_account_daily_reports'},
        {'name': 'om_account_followup'},
        {'name': 'om_account_accountant', 'dir': 'om_account_accountant'},
        {'name': 'om_hr_payroll'},
        {'name': 'om_hr_payroll_account'}
    ]},
    #{'url': 'https://github.com/CybroOdoo/CybroAddons',
    #'apps': [
    #    {'name': 'activity_reminder'},
    #]},
    {'url': 'https://github.com/OCA/server-tools',
    'apps': [  
        {'name': 'base_view_inheritance_extension'}    
    ]},  
    {'url': 'https://github.com/OCA/server-env',
    'apps': [
        {'name': 'server_environment'}
    ]},
    {'url': 'https://github.com/OCA/edi',
    'apps': [ 
        {'name': 'account_einvoice_generate'},
        {'name': 'account_invoice_facturx'},
        {'name': 'base_facturx'}
    ]},   
    {'url': 'https://github.com/OCA/account-invoicing',
    'apps': [  
        {'name': 'account_invoice_transmit_method'}    
    ]},  
    {'url': 'https://github.com/OCA/account-reconcile',
    'apps': [  
        {'name': 'account_statement_base'}    
    ]},  
    {'url': 'https://github.com/OCA/reporting-engine',
    'apps': [  
        {'name': 'report_xlsx'}    
    ]}, 
    {'url': 'https://github.com/OCA/mis-builder',
    'apps': [  
        {'name': 'mis_builder'}    
    ]},  
    {'url': 'https://github.com/OCA/bank-payment',
    'apps': [
        {'name': 'account_payment_mode'},
        {'name': 'account_payment_partner'}
    ]},
    {'url': 'https://github.com/OCA/bank-statement-import',
    'apps': [  
        {'name': 'account_statement_import_base'},
        {'name': 'account_statement_import_file'},
        {'name': 'account_statement_import_sheet_file'}
    ]}, 
    {'url': 'https://github.com/OCA/community-data-files',
    'apps': [
        {'name': 'base_unece'},
        {'name': 'uom_unece'},
        {'name': 'account_tax_unece'},
        {'name': 'account_payment_unece'}
    ]},
    {'url': 'https://github.com/OCA/server-ux',
        'apps': [
            {'name': 'date_range'}
        ]},     
    {'url': 'https://github.com/OCA/l10n-france',
    'apps': [
        {'name': 'l10n_fr_account_tax_unece'},
        {'name': 'l10n_fr_oca'},
        {'name': 'account_statement_impon Systems dashboards. Such style of reports presents KPI in rows and time periods in columns. Reports mainly fetch data from account moves, but can also combine data coming from arbitrary Odoo models. Reports can be exported to PDF, Excel and they can be added to Odoo drt_fr_cfonb'},
        {'name': 'l10n_fr_chorus_account'},
        {'name': 'l10n_fr_account_invoice_facturx'},
        {'name': 'l10n_fr_chorus_factur-x'},
        {'name': 'l10n_fr_fec_oca'},
        {'name': 'l10n_fr_mis_reports'},
        {'name': 'l10n_fr_siret'},
        {'name': 'l10n_fr_siret_lookup'}
    ]},
    {'url': 'https://github.com/OCA/web',
    'apps': [
        {'name': 'web_responsive'}
    ]},
    {'url': 'https://git.legaragenumerique.fr/odoo/gn_odoo',
    'apps': [
        {'name': 'gn_account_pcg_asso'}
    ]}
]

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()