feat(jupyter): refactor Jupyter integration to use kernel startup scripts and add papermill support
This commit is contained in:
8 files changed
+220
-253
No files matched your search
Executable
+144
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Initialize a Jupyter Lab directory with Odoo bootstrap files.
|
||||
|
||||
Creates:
|
||||
- <path>/.ipython/profile_default/startup/00-odoo.py
|
||||
- <path>/main.ipynb
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
STARTUP_TEMPLATE = r'''
|
||||
import os
|
||||
import atexit
|
||||
|
||||
import odoo
|
||||
from odoo import api
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.tools import config
|
||||
|
||||
|
||||
db_name = os.environ["DB_NAME"]
|
||||
config["db_name"] = db_name
|
||||
config["db_host"] = os.environ.get("PGHOST", "localhost")
|
||||
config["db_port"] = os.environ.get("PGPORT", "5432")
|
||||
config["db_user"] = os.environ.get("PGUSER", "odoo")
|
||||
config["db_password"] = os.environ.get("PGPASSWORD", "odoo")
|
||||
|
||||
registry = Registry(db_name)
|
||||
cr = registry.cursor()
|
||||
uid = 2
|
||||
ctx = api.Environment(cr, uid, {})["res.users"].context_get()
|
||||
env = api.Environment(cr, uid, ctx)
|
||||
self = env.user
|
||||
|
||||
ip = get_ipython()
|
||||
ip.push({
|
||||
"odoo": odoo,
|
||||
"env": env,
|
||||
"cr": cr,
|
||||
"uid": uid,
|
||||
"self": self,
|
||||
"api": api,
|
||||
})
|
||||
|
||||
|
||||
@atexit.register
|
||||
def _cleanup():
|
||||
try:
|
||||
cr.rollback()
|
||||
cr.close()
|
||||
except Exception:
|
||||
pass
|
||||
'''
|
||||
|
||||
|
||||
def create_notebook(path: Path) -> None:
|
||||
if path.exists():
|
||||
print(f"Notebook already exists, skipping: {path}")
|
||||
return
|
||||
|
||||
notebook = {
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Odoo Notebook\n",
|
||||
"\n",
|
||||
"Available automatically:\n",
|
||||
"\n",
|
||||
"- `env`\n",
|
||||
"- `cr`\n",
|
||||
"- `odoo`\n",
|
||||
"- `self`\n",
|
||||
"- `uid`\n",
|
||||
"- `api`\n",
|
||||
],
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": None,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["env.user.name"],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3",
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
},
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
}
|
||||
|
||||
path.write_text(json.dumps(notebook, indent=2))
|
||||
print(f"Created notebook: {path}")
|
||||
|
||||
|
||||
def create_startup_script(ipython_dir: Path) -> None:
|
||||
startup_dir = ipython_dir / "profile_default" / "startup"
|
||||
startup_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
startup_file = startup_dir / "00-odoo.py"
|
||||
startup_file.write_text(STARTUP_TEMPLATE)
|
||||
print(f"Created startup script: {startup_file}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Initialize a directory for Odoo Jupyter Lab."
|
||||
)
|
||||
parser.add_argument("path", help="Directory to initialize (e.g. tmp)")
|
||||
args = parser.parse_args()
|
||||
|
||||
notebook_dir = Path(args.path).resolve()
|
||||
notebook_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
ipython_dir = notebook_dir / ".ipython"
|
||||
|
||||
print()
|
||||
print("Initializing Odoo Jupyter directory")
|
||||
print(f"Path: {notebook_dir}")
|
||||
print()
|
||||
|
||||
create_startup_script(ipython_dir)
|
||||
create_notebook(notebook_dir / "main.ipynb")
|
||||
|
||||
print()
|
||||
print("Done. Run 'task start-odoo-jupyter <path> [database]' to launch.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -10,75 +10,6 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
STARTUP_TEMPLATE = r'''
|
||||
import os
|
||||
import atexit
|
||||
|
||||
import odoo
|
||||
from odoo import api
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.tools import config
|
||||
|
||||
|
||||
db_name = os.environ["DB_NAME"]
|
||||
|
||||
config["db_name"] = db_name
|
||||
config["db_host"] = os.environ.get("PGHOST", "localhost")
|
||||
config["db_port"] = os.environ.get("PGPORT", "5432")
|
||||
config["db_user"] = os.environ.get("PGUSER", "odoo")
|
||||
config["db_password"] = os.environ.get("PGPASSWORD", "odoo")
|
||||
|
||||
|
||||
registry = Registry(db_name)
|
||||
cr = registry.cursor()
|
||||
|
||||
uid = 2
|
||||
|
||||
ctx = api.Environment(cr, uid, {})["res.users"].context_get()
|
||||
|
||||
env = api.Environment(cr, uid, ctx)
|
||||
|
||||
self = env.user
|
||||
|
||||
|
||||
ip = get_ipython()
|
||||
|
||||
ip.push({
|
||||
"odoo": odoo,
|
||||
"env": env,
|
||||
"cr": cr,
|
||||
"uid": uid,
|
||||
"self": self,
|
||||
"api": api,
|
||||
})
|
||||
|
||||
|
||||
@atexit.register
|
||||
def _cleanup():
|
||||
try:
|
||||
cr.rollback()
|
||||
cr.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
print("=" * 60)
|
||||
print(f"Odoo ready: {db_name}")
|
||||
print(f"User: {env.user.name}")
|
||||
print(f"Models: {len(env.registry.models)}")
|
||||
print("=" * 60)
|
||||
'''
|
||||
|
||||
|
||||
def create_startup_script(ipython_dir: Path) -> None:
|
||||
startup_dir = ipython_dir / "profile_default" / "startup"
|
||||
startup_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
startup_file = startup_dir / "00-odoo.py"
|
||||
|
||||
startup_file.write_text(STARTUP_TEMPLATE)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Execute Jupyter notebook with papermill"
|
||||
@@ -113,17 +44,21 @@ def main() -> None:
|
||||
|
||||
ipython_dir = project_root / ".ipython"
|
||||
|
||||
create_startup_script(ipython_dir)
|
||||
startup_script = ipython_dir / "profile_default" / "startup" / "00-odoo.py"
|
||||
if not startup_script.exists():
|
||||
print(
|
||||
f"ERROR: Directory not initialized. Run 'task init-odoo-jupyter {project_root}' first.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
env = os.environ.copy()
|
||||
|
||||
env["DB_NAME"] = db_name
|
||||
|
||||
env.setdefault("PGHOST", "localhost")
|
||||
env.setdefault("PGPORT", "5432")
|
||||
env.setdefault("PGUSER", "odoo")
|
||||
env.setdefault("PGPASSWORD", "odoo")
|
||||
|
||||
env["IPYTHONDIR"] = str(ipython_dir)
|
||||
|
||||
output_path = notebook_path
|
||||
@@ -136,9 +71,7 @@ def main() -> None:
|
||||
]
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("Executing notebook")
|
||||
print("=" * 60)
|
||||
print(f"Notebook : {notebook_path}")
|
||||
print(f"Database : {db_name}")
|
||||
print()
|
||||
@@ -162,9 +95,7 @@ def main() -> None:
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("Notebook executed successfully")
|
||||
print("=" * 60)
|
||||
print(output_path)
|
||||
print()
|
||||
|
||||
|
||||
+23
-151
@@ -2,192 +2,64 @@
|
||||
"""
|
||||
Start Jupyter Lab with a preloaded Odoo environment.
|
||||
|
||||
The notebook itself contains NO bootstrap code.
|
||||
Everything is initialized in the kernel startup process.
|
||||
Expects the directory to already be initialized via init-odoo-jupyter.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
STARTUP_TEMPLATE = r'''
|
||||
import os
|
||||
import atexit
|
||||
|
||||
import odoo
|
||||
from odoo import api
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.tools import config
|
||||
|
||||
|
||||
db_name = os.environ["DB_NAME"]
|
||||
|
||||
config["db_name"] = db_name
|
||||
config["db_host"] = os.environ.get("PGHOST", "localhost")
|
||||
config["db_port"] = os.environ.get("PGPORT", "5432")
|
||||
config["db_user"] = os.environ.get("PGUSER", "odoo")
|
||||
config["db_password"] = os.environ.get("PGPASSWORD", "odoo")
|
||||
|
||||
|
||||
registry = Registry(db_name)
|
||||
cr = registry.cursor()
|
||||
|
||||
uid = 2
|
||||
|
||||
ctx = api.Environment(cr, uid, {})["res.users"].context_get()
|
||||
|
||||
env = api.Environment(cr, uid, ctx)
|
||||
|
||||
self = env.user
|
||||
|
||||
|
||||
ip = get_ipython()
|
||||
|
||||
ip.push({
|
||||
"odoo": odoo,
|
||||
"env": env,
|
||||
"cr": cr,
|
||||
"uid": uid,
|
||||
"self": self,
|
||||
"api": api,
|
||||
})
|
||||
|
||||
|
||||
@atexit.register
|
||||
def _cleanup():
|
||||
try:
|
||||
cr.rollback()
|
||||
cr.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
print("=" * 60)
|
||||
print(f"Odoo ready: {db_name}")
|
||||
print(f"User: {env.user.name}")
|
||||
print(f"Models: {len(env.registry.models)}")
|
||||
print("=" * 60)
|
||||
'''
|
||||
|
||||
|
||||
def create_notebook(path: Path) -> None:
|
||||
"""
|
||||
Create a clean notebook with zero bootstrap code.
|
||||
"""
|
||||
|
||||
if path.exists():
|
||||
return
|
||||
|
||||
notebook = {
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Odoo Notebook\n",
|
||||
"\n",
|
||||
"Available automatically:\n",
|
||||
"\n",
|
||||
"- `env`\n",
|
||||
"- `cr`\n",
|
||||
"- `odoo`\n",
|
||||
"- `self`\n",
|
||||
"- `uid`\n",
|
||||
"- `api`\n",
|
||||
],
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": None,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.user.name"
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3",
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
},
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
}
|
||||
|
||||
path.write_text(json.dumps(notebook, indent=2))
|
||||
|
||||
|
||||
def create_startup_script(ipython_dir: Path) -> None:
|
||||
"""
|
||||
Create IPython startup hook.
|
||||
"""
|
||||
|
||||
startup_dir = ipython_dir / "profile_default" / "startup"
|
||||
startup_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
startup_file = startup_dir / "00-odoo.py"
|
||||
|
||||
startup_file.write_text(STARTUP_TEMPLATE)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Start Jupyter Lab with Odoo kernel bootstrap."
|
||||
)
|
||||
parser.add_argument("path", help="Directory previously initialized by init-odoo-jupyter")
|
||||
parser.add_argument(
|
||||
"database",
|
||||
nargs="?",
|
||||
default=os.environ.get("DB_NAME", "odoo"),
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"token",
|
||||
nargs="?",
|
||||
default=None,
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
db_name = args.database
|
||||
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
project_root = script_dir.parent
|
||||
|
||||
notebook_dir = project_root / "tmp"
|
||||
notebook_dir.mkdir(exist_ok=True)
|
||||
|
||||
notebook_dir = Path(args.path).resolve()
|
||||
ipython_dir = notebook_dir / ".ipython"
|
||||
|
||||
env = os.environ.copy()
|
||||
if not (notebook_dir / "main.ipynb").exists():
|
||||
print(f"Error: {notebook_dir} does not look initialized.")
|
||||
print("Run 'task init-odoo-jupyter <path>' first.")
|
||||
raise SystemExit(1)
|
||||
|
||||
env["DB_NAME"] = db_name
|
||||
token = args.token or secrets.token_hex(16)
|
||||
|
||||
env = os.environ.copy()
|
||||
env["DB_NAME"] = args.database
|
||||
env.setdefault("PGHOST", "localhost")
|
||||
env.setdefault("PGPORT", "5432")
|
||||
env.setdefault("PGUSER", "odoo")
|
||||
env.setdefault("PGPASSWORD", "odoo")
|
||||
|
||||
env["IPYTHONDIR"] = str(ipython_dir)
|
||||
|
||||
create_startup_script(ipython_dir)
|
||||
|
||||
create_notebook(notebook_dir / "main.ipynb")
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("Starting Jupyter Lab with Odoo")
|
||||
print("=" * 60)
|
||||
print(f"Database : {db_name}")
|
||||
print(f"Database : {args.database}")
|
||||
print(f"Notebook : {notebook_dir}")
|
||||
print()
|
||||
|
||||
cmd = [
|
||||
"jupyter-lab",
|
||||
f"--ServerApp.root_dir={notebook_dir}",
|
||||
"--ServerApp.open_browser=True",
|
||||
f"--ServerApp.token={token}",
|
||||
"--ServerApp.open_browser=False",
|
||||
"--ServerApp.port=8888",
|
||||
]
|
||||
|
||||
|
||||
@@ -45,5 +45,4 @@ rl-renderPM
|
||||
|
||||
# Jupyter Notebook
|
||||
jupyter
|
||||
ipykernel
|
||||
papermill
|
||||
@@ -0,0 +1,5 @@
|
||||
<data priority="50">
|
||||
<list position="attributes">
|
||||
<attribute name="default_order">create_date asc, priority desc, sla_deadline, id</attribute>
|
||||
</list>
|
||||
</data>
|
||||
@@ -156,7 +156,6 @@ help-table() {
|
||||
rows+=("psql|[db]|Start interactive psql shell.")
|
||||
rows+=("restart|[name]|Restart container.")
|
||||
rows+=("run|[name][cmd]|Run container with command.")
|
||||
rows+=("run-jupyter-notebook|[path][db]|Run juypter notebook with papermill.")
|
||||
rows+=("shell|[db][code]|Start interactive odoo shell or run code.")
|
||||
rows+=("source||Source the Python virtual env.")
|
||||
rows+=("start|[name][db]|Start service. Use list to show services.")
|
||||
@@ -184,7 +183,11 @@ help-table() {
|
||||
rows+=("prepare-migration-brach|[path][module][version]|Create migration branch for a module.")
|
||||
rows+=("migrate-module|[path]|Migrate module code from to target Odoo version.")
|
||||
rows+=("upgrade-odoo|[env][step]|Run the Odoo upgrade for a target environment.")
|
||||
|
||||
rows+=("===JUPYTER===| | ")
|
||||
rows+=("init-odoo-jupyter|[path]|Init jypyter lab directory.")
|
||||
rows+=("start-odoo-jupyter|[path][db]|Start juypter lab in directory.")
|
||||
rows+=("run-jupyter-notebook|[path][db]|Run juypter notebook with papermill.")
|
||||
|
||||
for row in "${rows[@]}"; do
|
||||
IFS='|' read -r cmd opt desc <<< "$row"
|
||||
(( ${#cmd} > max_cmd )) && max_cmd=${#cmd}
|
||||
@@ -724,9 +727,6 @@ build-odoo() {
|
||||
local python_version="3.12"
|
||||
;;
|
||||
"19.0")
|
||||
local python_version="3.13"
|
||||
;;
|
||||
*)
|
||||
local python_version="3.12"
|
||||
;;
|
||||
esac
|
||||
@@ -1285,11 +1285,6 @@ start() {
|
||||
echo 'Open http://localhost:8080 url in your browser.'
|
||||
open-url-with-delay "http://localhost:8080" 2 & $COMPOSE_COMMAND up -d odoo
|
||||
fi
|
||||
|
||||
if [[ "$1" =~ "jupyter" ]]; then
|
||||
# jupyter lab
|
||||
./bin/start-odoo-jupyter "$database"
|
||||
fi
|
||||
}
|
||||
|
||||
debug() {
|
||||
@@ -1334,6 +1329,27 @@ run() {
|
||||
$COMPOSE_COMMAND run --rm "$1" "$2" "$3"
|
||||
}
|
||||
|
||||
init-odoo-jupyter() {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo '$1/path is empty.'
|
||||
exit
|
||||
fi
|
||||
./bin/init-odoo-jupyter "$1"
|
||||
}
|
||||
|
||||
start-odoo-jupyter() {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo '$1/path is empty.'
|
||||
exit
|
||||
fi
|
||||
local database="$2"
|
||||
if [[ -z "$database" ]]; then
|
||||
database="$DB_NAME"
|
||||
fi
|
||||
local token="odoo"
|
||||
./bin/start-odoo-jupyter "$1" "$database" "$token"
|
||||
}
|
||||
|
||||
run-jupyter-notebook() {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo '$1/path is empty.'
|
||||
|
||||
+14
-14
@@ -3,28 +3,28 @@
|
||||
url = git@github.com:odoo/odoo.git
|
||||
branch = 19.0
|
||||
shallow = true
|
||||
commit = 82124886fdb3485ef9dc089e5c33b7c803030d5e
|
||||
commit = 32301e8acba31140408bead9677c466baf0e0a45
|
||||
[submodule "enterprise"]
|
||||
path = enterprise
|
||||
url = git@github.com:odoo/enterprise.git
|
||||
branch = 19.0
|
||||
shallow = true
|
||||
commit = 64f813dab727d76286c1ff6c80c08cb6a6737b49
|
||||
commit = af3e13b2881c7647aed022f29a187149c95bb255
|
||||
[submodule "themes"]
|
||||
path = themes
|
||||
url = git@github.com:odoo/design-themes.git
|
||||
branch = 19.0
|
||||
commit = 7599a4bd2862e3fcd672de78397d05bcb135df70
|
||||
commit = 6e142b7abc66777bb9f6f5d124609b97ac93e7a5
|
||||
[submodule "addons/server_tools"]
|
||||
path = addons/server_tools
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Server-Tools.git
|
||||
branch = 19.0
|
||||
commit = 41841bf3c5508390676ababdf0cc7df8951ba589
|
||||
commit = 53e65405dd605804b75ca3a3dfc40ef4970718c1
|
||||
[submodule "oca/partner-contact"]
|
||||
path = oca/partner-contact
|
||||
url = git@github.com:OCA/partner-contact.git
|
||||
branch = 19.0
|
||||
commit = b6b6652548fb79c95c4f08d725a0e83356b34c99
|
||||
commit = b54008efb460beec76eb42347238f1618f6df32a
|
||||
[submodule "addons/management_system"]
|
||||
path = addons/management_system
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Management-System.git
|
||||
@@ -34,7 +34,7 @@
|
||||
path = addons/sale_workflow
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Sale-Workflow.git
|
||||
branch = 19.0
|
||||
commit = e4796bc9cd84628aac3616ba3e146a4d418a64be
|
||||
commit = 2baad67347f539fa9833be1f1ec2be94ccf603b0
|
||||
[submodule "addons/account_invoicing"]
|
||||
path = addons/account_invoicing
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Account-Invoicing.git
|
||||
@@ -44,22 +44,22 @@
|
||||
path = addons/purchase_workflow
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Purchase-Workflow.git
|
||||
branch = 19.0
|
||||
commit = 7bd3d7a02f3fadf71ae58ad34f2523188d2cf3f8
|
||||
commit = 8b4f075f6b0c606e05bf5bd3e9fbb7e560d50ba5
|
||||
[submodule "addons/stock_logistics_workflow"]
|
||||
path = addons/stock_logistics_workflow
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Stock-Logistics-Workflow.git
|
||||
branch = 19.0
|
||||
commit = b250302f012da0ca116855e7ba641c6eb75578ad
|
||||
commit = 6587b4a8e411ff350de822dc2a5e17484121214d
|
||||
[submodule "oca/sale-workflow"]
|
||||
path = oca/sale-workflow
|
||||
url = git@github.com:OCA/sale-workflow
|
||||
branch = 19.0
|
||||
commit = 87113dc142dab74f34d242904c739a14cfa05b3c
|
||||
commit = d2121f9419e7a1b87382ca06b278b4b0cf4befde
|
||||
[submodule "oca/server-tools"]
|
||||
path = oca/server-tools
|
||||
url = git@github.com:OCA/server-tools.git
|
||||
branch = 19.0
|
||||
commit = 793dd13b1fc60a43b091b7e156aea95c8bc2011d
|
||||
commit = 3f56112d5d507ba6e6cff73a52309e4368008f66
|
||||
[submodule "addons/spreadsheet"]
|
||||
path = addons/spreadsheet
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Spreadsheet.git
|
||||
@@ -69,17 +69,17 @@
|
||||
path = addons/product_attribute
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Product-Attribute.git
|
||||
branch = 19.0
|
||||
commit = 4cd5253da71c66d757ed292aa7fd18e64eef8375
|
||||
commit = 225d3bdffe175a969fa61dbcf4652a0f7c32cfc8
|
||||
[submodule "oca/mass-mailing"]
|
||||
path = oca/mass-mailing
|
||||
url = git@github.com:OCA/mass-mailing.git
|
||||
branch = 19.0
|
||||
commit = 4baf365254fd80be51e99dd446de2d27e601b981
|
||||
commit = 9d6b46cf3d7d0bae5b2b338d351b1d611a55d5c2
|
||||
[submodule "oca/account-analytic"]
|
||||
path = oca/account-analytic
|
||||
url = git@github.com:OCA/account-analytic.git
|
||||
branch = 19.0
|
||||
commit = dc6afca735a01ed0c616339969a03fba9cef6102
|
||||
commit = 4f78732271e81962c858f333e74b9b6690e6277c
|
||||
[submodule "addons/website"]
|
||||
path = addons/website
|
||||
url = git@github.com:Mint-System/Odoo-Apps-Website
|
||||
@@ -89,4 +89,4 @@
|
||||
path = oca/hr-attendance
|
||||
url = git@github.com:OCA/hr-attendance.git
|
||||
branch = 19.0
|
||||
commit = 729040b76e01f43dda5b3f171b581e5d87b6f590
|
||||
commit = 6af354e9e0f21ebec6c9c052c2789578d33d206a
|
||||
@@ -1 +1 @@
|
||||
3.13
|
||||
3.12
|
||||
Reference in new issue
Block a user