From eb7f96efbbcedd0f840a7685599cf5344aff1e8b Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 21 May 2014 13:24:39 +0200 Subject: [PATCH 001/121] --addons-path not required anymore --- openerpcommand/common.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openerpcommand/common.py b/openerpcommand/common.py index 7572bb4efa6..48d1c16eae4 100644 --- a/openerpcommand/common.py +++ b/openerpcommand/common.py @@ -14,8 +14,7 @@ def add_addons_argument(parser): Add a common --addons argument to a parser. """ parser.add_argument('--addons', metavar='ADDONS', - **required_or_default('ADDONS', - 'colon-separated list of paths to addons')) + help='colon-separated list of paths to addons') def set_addons(args): """ Turn args.addons into a list instead of a column-separated strings. From df35de22b80df3a1e57dd38e44dc69de82ef4e50 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 21 May 2014 15:53:16 +0200 Subject: [PATCH 002/121] Disable logging during commands discovery --- openerp/cli/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/cli/__init__.py b/openerp/cli/__init__.py index 27428369cbc..574898b1e24 100644 --- a/openerp/cli/__init__.py +++ b/openerp/cli/__init__.py @@ -47,6 +47,7 @@ def main(): # Subcommand discovery if len(args) and not args[0].startswith("-"): + logging.disable(logging.CRITICAL) for m in module.get_modules(): m = 'openerp.addons.' + m __import__(m) @@ -54,6 +55,7 @@ def main(): #except Exception, e: # raise # print e + logging.disable(logging.NOTSET) command = args[0] args = args[1:] From f96a03247b371c4d2e9317a46d645a4b66e2f1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Closson?= Date: Thu, 22 May 2014 09:26:40 +0200 Subject: [PATCH 003/121] [FIX] stock: auto_validate move not set to done when multiple parent move set to done at the same time - opw 607970 --- addons/stock/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index d2d5ba3fab1..64a43852ad4 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2413,7 +2413,7 @@ class stock_move(osv.osv): # Downstream move should only be triggered if this move is the last pending upstream move other_upstream_move_ids = self.search(cr, uid, [('id','!=',move.id),('state','not in',['done','cancel']), ('move_dest_id','=',move.move_dest_id.id)], context=context) - if not other_upstream_move_ids: + if not set(other_upstream_move_ids) - set(move_ids): self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]}) if move.move_dest_id.state in ('waiting', 'confirmed'): self.force_assign(cr, uid, [move.move_dest_id.id], context=context) From 6b16b79e8d1b612718f6e85aebe176d97abdfabb Mon Sep 17 00:00:00 2001 From: Yogesh Parekh Date: Thu, 22 May 2014 15:47:45 +0530 Subject: [PATCH 004/121] Add div tag and oe_padding class to display the question --- addons/base_import/static/src/xml/import.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 953beca8d9f..0295828cb7f 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -73,7 +73,8 @@
- + +

Frequently Asked Questions

From 996abd3baf7c5ea9af5b31c7487ec4f397bc00c8 Mon Sep 17 00:00:00 2001 From: neps1192 Date: Tue, 27 May 2014 11:06:18 +0300 Subject: [PATCH 005/121] Before 2005 TRL http://en.wikipedia.org/wiki/Turkish_lira --- addons/l10n_tr/account_chart_template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/l10n_tr/account_chart_template.xml b/addons/l10n_tr/account_chart_template.xml index a15af467932..60853ff7127 100644 --- a/addons/l10n_tr/account_chart_template.xml +++ b/addons/l10n_tr/account_chart_template.xml @@ -12,7 +12,7 @@ - + From dec81728667c55df6189c36a2dfa3e748dfef89e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 27 May 2014 14:22:28 +0200 Subject: [PATCH 006/121] [ADD] odoo deploy --- .../bin/oe_module_deploy.py | 86 ----------------- openerp/cli/__init__.py | 1 + openerp/cli/deploy.py | 92 +++++++++++++++++++ 3 files changed, 93 insertions(+), 86 deletions(-) delete mode 100755 addons/base_import_module/bin/oe_module_deploy.py create mode 100644 openerp/cli/deploy.py diff --git a/addons/base_import_module/bin/oe_module_deploy.py b/addons/base_import_module/bin/oe_module_deploy.py deleted file mode 100755 index 2412382cba5..00000000000 --- a/addons/base_import_module/bin/oe_module_deploy.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -import argparse -import os -import sys -import tempfile -import zipfile - - -try: - import requests -except ImportError: - # no multipart encoding in stdlib and this script is temporary - sys.exit("This script requires the 'requests' module. ( pip install requests )") - -session = requests.session() - -def deploy_module(module_path, url, login, password, db=''): - url = url.rstrip('/') - authenticate(url, login, password, db) - module_file = zip_module(module_path) - try: - return upload_module(url, module_file) - finally: - os.remove(module_file) - -def upload_module(server, module_file): - print("Uploading module file...") - url = server + '/base_import_module/upload' - files = dict(mod_file=open(module_file, 'rb')) - res = session.post(url, files=files) - if res.status_code != 200: - raise Exception("Could not authenticate on server '%s'" % server) - return res.text - -def authenticate(server, login, password, db=''): - print("Authenticating on server '%s' ..." % server) - - # Fixate session with a given db if any - session.get(server + '/web/login', params=dict(db=db)) - - args = dict(login=login, password=password, db=db) - res = session.post(server + '/base_import_module/login', args) - if res.status_code == 404: - raise Exception("The server '%s' does not have the 'base_import_module' installed." % server) - elif res.status_code != 200: - raise Exception(res.text) - -def zip_module(path): - path = os.path.abspath(path) - if not os.path.isdir(path): - raise Exception("Could not find module directory '%s'" % path) - container, module_name = os.path.split(path) - temp = tempfile.mktemp(suffix='.zip') - try: - print("Zipping module directory...") - with zipfile.ZipFile(temp, 'w') as zfile: - for root, dirs, files in os.walk(path): - for file in files: - file_path = os.path.join(root, file) - zfile.write(file_path, file_path.split(container).pop()) - return temp - except Exception: - os.remove(temp) - raise - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Deploy a module on an OpenERP server.') - parser.add_argument('path', help="Path of the module to deploy") - parser.add_argument('--url', dest='url', help='Url of the server (default=http://localhost:8069)', default="http://localhost:8069") - parser.add_argument('--db', dest='db', help='Database to use if server does not use db-filter.') - parser.add_argument('--login', dest='login', default="admin", help='Login (default=admin)') - parser.add_argument('--password', dest='password', default="admin", help='Password (default=admin)') - parser.add_argument('--no-ssl-check', dest='no_ssl_check', action='store_true', help='Do not check ssl cert') - if len(sys.argv) == 1: - sys.exit(parser.print_help()) - - args = parser.parse_args() - - if args.no_ssl_check: - session.verify = False - - try: - result = deploy_module(args.path, args.url, args.login, args.password, args.db) - print(result) - except Exception, e: - sys.exit("ERROR: %s" % e) diff --git a/openerp/cli/__init__.py b/openerp/cli/__init__.py index 574898b1e24..71e2ae88b6c 100644 --- a/openerp/cli/__init__.py +++ b/openerp/cli/__init__.py @@ -31,6 +31,7 @@ class Help(Command): print " %s" % k import server +import deploy def main(): args = sys.argv[1:] diff --git a/openerp/cli/deploy.py b/openerp/cli/deploy.py new file mode 100644 index 00000000000..079099a406f --- /dev/null +++ b/openerp/cli/deploy.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import argparse +import os +import requests +import sys +import tempfile +import zipfile + +from . import Command + +class Deploy(Command): + """Deploy a module on an Odoo instance""" + def __init__(self): + super(Deploy, self).__init__() + self.session = requests.session() + + def deploy_module(self, module_path, url, login, password, db=''): + url = url.rstrip('/') + self.authenticate(url, login, password, db) + module_file = self.zip_module(module_path) + try: + return self.upload_module(url, module_file) + finally: + os.remove(module_file) + + def upload_module(self, server, module_file): + print("Uploading module file...") + url = server + '/base_import_module/upload' + files = dict(mod_file=open(module_file, 'rb')) + res = self.session.post(url, files=files) + if res.status_code != 200: + raise Exception("Could not authenticate on server '%s'" % server) + return res.text + + def authenticate(self, server, login, password, db=''): + print("Authenticating on server '%s' ..." % server) + + # Fixate session with a given db if any + self.session.get(server + '/web/login', params=dict(db=db)) + + args = dict(login=login, password=password, db=db) + res = self.session.post(server + '/base_import_module/login', args) + if res.status_code == 404: + raise Exception("The server '%s' does not have the 'base_import_module' installed." % server) + elif res.status_code != 200: + raise Exception(res.text) + + def zip_module(self, path): + path = os.path.abspath(path) + if not os.path.isdir(path): + raise Exception("Could not find module directory '%s'" % path) + container, module_name = os.path.split(path) + temp = tempfile.mktemp(suffix='.zip') + try: + print("Zipping module directory...") + with zipfile.ZipFile(temp, 'w') as zfile: + for root, dirs, files in os.walk(path): + for file in files: + file_path = os.path.join(root, file) + zfile.write(file_path, file_path.split(container).pop()) + return temp + except Exception: + os.remove(temp) + raise + + def run(self, args): + parser = argparse.ArgumentParser( + prog="%s deploy" % sys.argv[0].split(os.path.sep)[-1], + description='Deploy a module on an Odoo server.' + ) + parser.add_argument('path', help="Path of the module to deploy") + parser.add_argument('url', nargs='?', help='Url of the server (default=http://localhost:8069)', default="http://localhost:8069") + parser.add_argument('--db', dest='db', help='Database to use if server does not use db-filter.') + parser.add_argument('--login', dest='login', default="admin", help='Login (default=admin)') + parser.add_argument('--password', dest='password', default="admin", help='Password (default=admin)') + parser.add_argument('--no-ssl-check', dest='no_ssl_check', action='store_true', help='Do not check ssl cert') + if not args: + sys.exit(parser.print_help()) + + args = parser.parse_args(args=args) + + if args.no_ssl_check: + self.session.verify = False + + try: + if not args.url.startswith('http://'): + args.url = 'https://%s' % args.url + result = self.deploy_module(args.path, args.url, args.login, args.password, args.db) + print(result) + except Exception, e: + sys.exit("ERROR: %s" % e) From 3458eb3ef7f65d8977589fbe68c9581e9b5a847d Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 27 May 2014 17:07:40 +0200 Subject: [PATCH 007/121] Add docstring to help command --- openerp/cli/__init__.py | 6 +++++- openerp/cli/server.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/openerp/cli/__init__.py b/openerp/cli/__init__.py index 71e2ae88b6c..2f9caad3ba6 100644 --- a/openerp/cli/__init__.py +++ b/openerp/cli/__init__.py @@ -1,5 +1,6 @@ import logging import sys +import os import openerp from openerp import tools @@ -25,10 +26,13 @@ class Command(object): pass class Help(Command): + """Display the list of available commands""" def run(self, args): print "Available commands:\n" + padding = max([len(k) for k in commands.keys()]) + 2 for k, v in commands.items(): - print " %s" % k + print " %s%s" % (k.ljust(padding, ' '), v.__doc__ or '') + print "\nUse '%s --help' for individual command help." % sys.argv[0].split(os.path.sep)[-1] import server import deploy diff --git a/openerp/cli/server.py b/openerp/cli/server.py index 5d731a9ad41..70602634efc 100644 --- a/openerp/cli/server.py +++ b/openerp/cli/server.py @@ -169,6 +169,7 @@ def main(args): sys.exit(rc) class Server(Command): + """Start the odoo server (default command)""" def run(self, args): main(args) From 41c5ceb8ebb95c1b4e98d8dd1f12b8e547a24b1d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 27 May 2014 17:56:30 +0200 Subject: [PATCH 008/121] [FIX] stock: clean previous commit --- addons/stock/stock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 64a43852ad4..4c45de266d7 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2411,9 +2411,9 @@ class stock_move(osv.osv): picking_ids.append(move.picking_id.id) if move.move_dest_id.id and (move.state != 'done'): # Downstream move should only be triggered if this move is the last pending upstream move - other_upstream_move_ids = self.search(cr, uid, [('id','!=',move.id),('state','not in',['done','cancel']), + other_upstream_move_ids = self.search(cr, uid, [('id','not in',move_ids),('state','not in',['done','cancel']), ('move_dest_id','=',move.move_dest_id.id)], context=context) - if not set(other_upstream_move_ids) - set(move_ids): + if not other_upstream_move_ids: self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]}) if move.move_dest_id.state in ('waiting', 'confirmed'): self.force_assign(cr, uid, [move.move_dest_id.id], context=context) From 397784cef0dc481cb75c122e693755f87a82423c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 09:25:31 +0200 Subject: [PATCH 009/121] reuse cls.__doc__ for deploy command --- openerp/cli/deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/cli/deploy.py b/openerp/cli/deploy.py index 079099a406f..fddfcf7ec4d 100644 --- a/openerp/cli/deploy.py +++ b/openerp/cli/deploy.py @@ -67,7 +67,7 @@ class Deploy(Command): def run(self, args): parser = argparse.ArgumentParser( prog="%s deploy" % sys.argv[0].split(os.path.sep)[-1], - description='Deploy a module on an Odoo server.' + description=self.__doc__ ) parser.add_argument('path', help="Path of the module to deploy") parser.add_argument('url', nargs='?', help='Url of the server (default=http://localhost:8069)', default="http://localhost:8069") From ac0b9d066caeee2737d29415b852d27cf7fff0a0 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 11:29:54 +0200 Subject: [PATCH 010/121] Added odoo.py command --- odoo.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 odoo.py diff --git a/odoo.py b/odoo.py new file mode 100755 index 00000000000..b9ff496c293 --- /dev/null +++ b/odoo.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python +import openerp + +if __name__ == "__main__": + openerp.cli.main() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From ba85b80f32700c8367528a12f8923f7045916818 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 11:31:00 +0200 Subject: [PATCH 011/121] Basic scaffolding --- openerp/cli/__init__.py | 1 + openerp/cli/scaffold.py | 106 ++++++++++++++++++++ openerp/cli/scaffold/__init__.jinja2 | 4 + openerp/cli/scaffold/__openerp__.jinja2 | 26 +++++ openerp/cli/scaffold/controllers.jinja2 | 9 ++ openerp/cli/scaffold/ir.model.access.jinja2 | 6 ++ openerp/cli/scaffold/models.jinja2 | 9 ++ 7 files changed, 161 insertions(+) create mode 100644 openerp/cli/scaffold.py create mode 100644 openerp/cli/scaffold/__init__.jinja2 create mode 100644 openerp/cli/scaffold/__openerp__.jinja2 create mode 100644 openerp/cli/scaffold/controllers.jinja2 create mode 100644 openerp/cli/scaffold/ir.model.access.jinja2 create mode 100644 openerp/cli/scaffold/models.jinja2 diff --git a/openerp/cli/__init__.py b/openerp/cli/__init__.py index 2f9caad3ba6..44141625121 100644 --- a/openerp/cli/__init__.py +++ b/openerp/cli/__init__.py @@ -36,6 +36,7 @@ class Help(Command): import server import deploy +import scaffold def main(): args = sys.argv[1:] diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py new file mode 100644 index 00000000000..4d9304c6e9e --- /dev/null +++ b/openerp/cli/scaffold.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import argparse +import functools +import keyword +import os +import re +import sys + +import jinja2 + +from . import Command + +class Scaffold(Command): + "Generate an Odoo module skeleton." + + def __init__(self): + super(Scaffold, self).__init__() + env = jinja2.Environment(loader=jinja2.PackageLoader( + 'openerp.cli', 'scaffold')) + env.filters['snake'] = snake + self.env = env + + def scaffold(self, args): + # TODO: make this function callable even if the module already + # exists. (update mode for scaffolding) + from pudb import set_trace;set_trace() ############################## Breakpoint ############################## + args.dependency = 'base' + if args.web: + args.dependency = 'web' + elif args.theme: + args.dependency = 'website' + dest = os.path.abspath(os.path.expanduser(args.dest)) + + module_name = snake(args.module) + module = functools.partial(os.path.join, dest, module_name) + + if os.path.exists(module()): + message = "The path `%s` already exists." % module() + die(message) + + self.dump('__openerp__.jinja2', module('__openerp__.py'), config=args) + self.dump('__init__.jinja2', module('__init__.py'), modules=[ + args.controller and 'controllers', + args.model and 'models' + ]) + self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args) + + + def dump(self, template, dest, **kwargs): + outdir = os.path.dirname(dest) + if not os.path.exists(outdir): + os.makedirs(outdir) + self.env.get_template(template).stream(**kwargs).dump(dest) + # add trailing newline which jinja removes + with open(dest, 'a') as f: + f.write('\n') + + def run(self, args): + parser = argparse.ArgumentParser( + prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1], + description=self.__doc__ + ) + parser.add_argument('module', help="Name of the module to generate") + parser.add_argument('dest', nargs='?', help='Directory where the module should be created (default to current directory)', default=".") + + + if not args: + sys.exit(parser.print_help()) + + args = parser.parse_args(args=args) + + self.scaffold(args) + +def snake(s): + """ snake cases ``s`` + + :param str s: + :return: str + """ + # insert a space before each uppercase character preceded by a + # non-uppercase letter + s = re.sub(r'(?<=[^A-Z])\B([A-Z])', r' \1', s) + # lowercase everything, split on whitespace and join + return '_'.join(s.lower().split()) + +def identifier(s): + if keyword.iskeyword(s): + die("%s is a Python keyword and can not be used as a name" % s) + if not re.match('[A-Za-z_][A-Za-z0-9_]*', s): + die("%s is not a valid Python identifier" % s) + return s + +def directory(p): + expanded = os.path.abspath( + os.path.expanduser( + os.path.expandvars(p))) + if not os.path.exists(expanded): + os.makedirs(expanded) + if not os.path.isdir(expanded): + die("%s exists but is not a directory" % p) + return expanded + +def die(message, code=1): + print >>sys.stderr, message + sys.exit(code) diff --git a/openerp/cli/scaffold/__init__.jinja2 b/openerp/cli/scaffold/__init__.jinja2 new file mode 100644 index 00000000000..0124cdd2d93 --- /dev/null +++ b/openerp/cli/scaffold/__init__.jinja2 @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +{% for module in modules if module -%} +import {{ module }} +{% endfor %} diff --git a/openerp/cli/scaffold/__openerp__.jinja2 b/openerp/cli/scaffold/__openerp__.jinja2 new file mode 100644 index 00000000000..0dbd6f83fbc --- /dev/null +++ b/openerp/cli/scaffold/__openerp__.jinja2 @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +{ + 'name': "{{ config.module }}", + # short description, used as subtitles on modules listings + 'summary': """ + Short (1 phrase/line) summary of the module's purpose, used as + subtitle on modules listing or apps.openerp.com""", + # long description of module purpose + 'description': """ + """, + # Who you are + 'author': "Acme Corp.", + 'website': "http://www.example.com", + + # categories can be used to filter modules in modules listing + 'category': 'Uncategorized', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['{{ config.dependency }}'], + 'data': [ + {{- "'security/ir.model.access.csv'" if config.model -}} + ], + 'tests': [ + ], +} diff --git a/openerp/cli/scaffold/controllers.jinja2 b/openerp/cli/scaffold/controllers.jinja2 new file mode 100644 index 00000000000..3cc47365d40 --- /dev/null +++ b/openerp/cli/scaffold/controllers.jinja2 @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- + +from openerp import http +from openerp.addons.web.controllers import main + +class {{ config.controller }}(main.Home): + @http.route('/', auth='none') + def index(self): + return "Hello, world!" diff --git a/openerp/cli/scaffold/ir.model.access.jinja2 b/openerp/cli/scaffold/ir.model.access.jinja2 new file mode 100644 index 00000000000..e5e2fb35fe7 --- /dev/null +++ b/openerp/cli/scaffold/ir.model.access.jinja2 @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +{% if config.model -%} +access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}} +access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}} +model_{{ config.module|snake }}_{{ config.model|snake }},,1,0,0,0 +{%- endif %} diff --git a/openerp/cli/scaffold/models.jinja2 b/openerp/cli/scaffold/models.jinja2 new file mode 100644 index 00000000000..878bf9be4f6 --- /dev/null +++ b/openerp/cli/scaffold/models.jinja2 @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +from openerp.osv import orm, fields + +class {{ config.model }}(orm.Model): + _name = "{{ config.module|snake }}.{{ config.model|snake }}" + + _columns = { + 'name': fields.char(), + } From ce764477e660dd49b1de1737ac0faa5c95bdc117 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 17:10:56 +0200 Subject: [PATCH 012/121] [WIP] models and controllers for scaffolding --- openerp/cli/scaffold.py | 92 ++++++++++++++++++------- openerp/cli/scaffold/__init__.jinja2 | 3 +- openerp/cli/scaffold/__openerp__.jinja2 | 26 ++++--- openerp/cli/scaffold/controllers.jinja2 | 8 ++- 4 files changed, 92 insertions(+), 37 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 4d9304c6e9e..9e24156b792 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -20,32 +20,69 @@ class Scaffold(Command): 'openerp.cli', 'scaffold')) env.filters['snake'] = snake self.env = env + self.manifest = '__openerp__' def scaffold(self, args): - # TODO: make this function callable even if the module already - # exists. (update mode for scaffolding) - from pudb import set_trace;set_trace() ############################## Breakpoint ############################## args.dependency = 'base' - if args.web: - args.dependency = 'web' - elif args.theme: - args.dependency = 'website' - dest = os.path.abspath(os.path.expanduser(args.dest)) + # TODO: update dependencies according to --web and --theme + # if args.web: + # args.dependency = 'web' + # elif args.theme: + # args.dependency = 'website' - module_name = snake(args.module) - module = functools.partial(os.path.join, dest, module_name) + dest = directory(args.dest) + if args.init: + module_name = snake(args.init) + module = functools.partial(os.path.join, dest, module_name) + if os.path.exists(module()): + die("Can't initialize module in `%s`: Directory already exists." % module()) + else: + module_name = dest.split(os.path.sep)[-1] + # find the module's root directory + while not os.path.exists(os.path.join(dest, '%s.py' % self.manifest)): + new_dest = os.path.abspath(os.path.join(dest, os.pardir)) + if dest == new_dest: + die("Can't find module directory. Please `cd` to it's path or use --dest") + module_name = dest.split(os.path.sep)[-1] + dest = new_dest + module = functools.partial(os.path.join, dest) + args.module = module_name - if os.path.exists(module()): - message = "The path `%s` already exists." % module() - die(message) + if args.init: + self.dump('%s.jinja2' % self.manifest, module('%s.py' % self.manifest), config=args) - self.dump('__openerp__.jinja2', module('__openerp__.py'), config=args) - self.dump('__init__.jinja2', module('__init__.py'), modules=[ - args.controller and 'controllers', - args.model and 'models' - ]) - self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args) + if args.model: + model_module = snake(args.model) + model_file = module('models', '%s.py' % model_module) + if os.path.exists(model_file): + die("Model `%s` already exists !" % model_file) + self.add_init_import(module('__init__.py'), 'models') + self.add_init_import(module('models', '__init__.py'), model_module) + self.dump('models.jinja2', model_file, config=args) + if args.controller: + controller_module = snake(args.controller) + controller_file = module('controllers', '%s.py' % controller_module) + if os.path.exists(controller_file): + die("Controller `%s` already exists !" % controller_file) + self.add_init_import(module('__init__.py'), 'controllers') + self.add_init_import(module('controllers', '__init__.py'), controller_module) + self.dump('controllers.jinja2', module('controllers', controller_file), config=args) + + # self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args) + return + + def add_init_import(self, path, module): + if not os.path.exists(path): + self.dump('__init__.jinja2', path, modules=[module]) + else: + with open(path, "r") as f: + lines = f.readlines() + # TODO: regex + if ('import %s' % module) in lines: + return + with open(path, "a") as f: + f.write('\nimport %s' % module) def dump(self, template, dest, **kwargs): outdir = os.path.dirname(dest) @@ -61,15 +98,24 @@ class Scaffold(Command): prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1], description=self.__doc__ ) - parser.add_argument('module', help="Name of the module to generate") - parser.add_argument('dest', nargs='?', help='Directory where the module should be created (default to current directory)', default=".") + parser.add_argument('--init', type=identifier, help='Initialize a new Odoo module') + parser.add_argument('--dest', default=".", + help='Directory where the module should be created/updated (default to current directory)') + + parser.add_argument('--model', type=identifier, help="Name of the model to add") + + parser.add_argument('--controller', type=identifier, help="Name of the controller to add") + + parser.add_argument('--web', action='store_true', default=False, + help="Generate structure for a webclient module") + + parser.add_argument('--theme', action='store_true', default=False, + help="Generate structure for a Website theme") if not args: sys.exit(parser.print_help()) - args = parser.parse_args(args=args) - self.scaffold(args) def snake(s): diff --git a/openerp/cli/scaffold/__init__.jinja2 b/openerp/cli/scaffold/__init__.jinja2 index 0124cdd2d93..7a45c970f2c 100644 --- a/openerp/cli/scaffold/__init__.jinja2 +++ b/openerp/cli/scaffold/__init__.jinja2 @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- {% for module in modules if module -%} -import {{ module }} -{% endfor %} +import {{ module }}{% endfor %} diff --git a/openerp/cli/scaffold/__openerp__.jinja2 b/openerp/cli/scaffold/__openerp__.jinja2 index 0dbd6f83fbc..c8bd331d063 100644 --- a/openerp/cli/scaffold/__openerp__.jinja2 +++ b/openerp/cli/scaffold/__openerp__.jinja2 @@ -1,26 +1,32 @@ # -*- coding: utf-8 -*- { 'name': "{{ config.module }}", - # short description, used as subtitles on modules listings + 'summary': """ Short (1 phrase/line) summary of the module's purpose, used as subtitle on modules listing or apps.openerp.com""", - # long description of module purpose - 'description': """ - """, - # Who you are - 'author': "Acme Corp.", - 'website': "http://www.example.com", - # categories can be used to filter modules in modules listing + 'description': """ + Long description of module's purpose + """, + + 'author': "Your Company", + 'website': "http://www.yourcompany.com", + + # Categories can be used to filter modules in modules listing + # Check /addons/base/module/module_data.xml of the full list 'category': 'Uncategorized', 'version': '0.1', # any module necessary for this one to work correctly - 'depends': ['{{ config.dependency }}'], + 'depends': ['base'], 'data': [ - {{- "'security/ir.model.access.csv'" if config.model -}} + # {{- "'security/ir.model.access.csv'" if config.model -}} ], + + 'demo': [ + ], + 'tests': [ ], } diff --git a/openerp/cli/scaffold/controllers.jinja2 b/openerp/cli/scaffold/controllers.jinja2 index 3cc47365d40..db08e62c375 100644 --- a/openerp/cli/scaffold/controllers.jinja2 +++ b/openerp/cli/scaffold/controllers.jinja2 @@ -1,9 +1,13 @@ # -*- coding: utf-8 -*- - from openerp import http from openerp.addons.web.controllers import main class {{ config.controller }}(main.Home): - @http.route('/', auth='none') + @http.route('/{{ config.module }}/{{ config.controller }}', auth='public') def index(self): return "Hello, world!" +{% if config.model %} + @http.route('/{{ config.module }}/{{ config.controller }}/{{ config.model }}/'], type='http', auth='public') + def {{ config.model }}(self, {{ config.model }}, **kw): + return "Hello, %r!" % {{ config.model }} +{% endif %} From 65d7cc524d9f3a5dc833cb483ccaaf86fab4819d Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 28 May 2014 18:00:11 +0200 Subject: [PATCH 013/121] [FIX] purchase: Do not allow to delete a purchase order line which is validated This restriction behavior copied from the sale.order model Moreover, the purchase.order lines state were not set to cancel when the purchase order was cancelled. This is now the case, this behavior is also coped from the sale.order model When the purchase order is reset to draft, we also reset the order lines state to draft --- addons/purchase/purchase.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 6767f9185ac..d258eee7431 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -499,6 +499,8 @@ class purchase_order(osv.osv): if not len(ids): return False self.write(cr, uid, ids, {'state':'draft','shipped':0}) + for purchase in self.browse(cr, uid, ids, context=context): + self.pool['purchase.order.line'].write(cr, uid, [l.id for l in purchase.order_line], {'state': 'draft'}) wf_service = netsvc.LocalService("workflow") for p_id in ids: # Deleting the existing instance of workflow for PO @@ -596,6 +598,8 @@ class purchase_order(osv.osv): _('You must first cancel all receptions related to this purchase order.')) if inv: wf_service.trg_validate(uid, 'account.invoice', inv.id, 'invoice_cancel', cr) + self.pool['purchase.order.line'].write(cr, uid, [l.id for l in purchase.order_line], + {'state': 'cancel'}) self.write(cr,uid,ids,{'state':'cancel'}) for (id, name) in self.name_get(cr, uid, ids): @@ -901,6 +905,8 @@ class purchase_order_line(osv.osv): def unlink(self, cr, uid, ids, context=None): procurement_ids_to_cancel = [] for line in self.browse(cr, uid, ids, context=context): + if line.state not in ['draft', 'cancel']: + raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a purchase order line which is in state \'%s\'.') %(line.state,)) if line.move_dest_id: procurement_ids_to_cancel.extend(procurement.id for procurement in line.move_dest_id.procurements) if procurement_ids_to_cancel: From 3f6f43214ff363e3f39160828ca4e6dfa80128dd Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 28 May 2014 18:17:33 +0200 Subject: [PATCH 014/121] [FIX] replace .bzrignore by .gitignore, as we are now working with git --- .bzrignore | 21 --------------------- .gitignore | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 21 deletions(-) delete mode 100644 .bzrignore create mode 100644 .gitignore diff --git a/.bzrignore b/.bzrignore deleted file mode 100644 index e7618c7b0ce..00000000000 --- a/.bzrignore +++ /dev/null @@ -1,21 +0,0 @@ -.*.swp -.bzrignore -.idea -.project -.pydevproject -.ropeproject -.settings -.DS_Store -openerp/addons/* -openerp/filestore* -.Python -*.pyc -*.pyo -bin/* -build/ -include/ -lib/ -share/ -doc/_build/* -win32/*.bat -win32/meta.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..7828a605ef0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# sphinx build directories +_build/ + +# dotfiles +.* +!.gitignore +# compiled python files +*.py[co] +# setup.py egg_info +*.egg-info +# emacs backup files +*~ +# hg stuff +*.orig +status +# odoo filestore +openerp/filestore +# generated for windows installer? +install/win32/*.bat +install/win32/meta.py + +# various virtualenv +/bin/ +/build/ +/dist/ +/include/ +/lib/ +/man/ +/share/ +/src/ From 6b678f376e322eaa4368231021acd49df2f64d4f Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 18:49:16 +0200 Subject: [PATCH 015/121] Use ast module against __init__.py's for import discovery --- odoo.py | 2 -- openerp/cli/scaffold.py | 32 ++++++++++----------- openerp/cli/scaffold/__init__.jinja2 | 6 ++-- openerp/cli/scaffold/ir.model.access.jinja2 | 2 +- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/odoo.py b/odoo.py index b9ff496c293..0a33d5e7d42 100755 --- a/odoo.py +++ b/odoo.py @@ -3,5 +3,3 @@ import openerp if __name__ == "__main__": openerp.cli.main() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 9e24156b792..4fdd5a32137 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import argparse +import ast import functools import keyword import os @@ -59,6 +60,7 @@ class Scaffold(Command): self.add_init_import(module('__init__.py'), 'models') self.add_init_import(module('models', '__init__.py'), model_module) self.dump('models.jinja2', model_file, config=args) + self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args) if args.controller: controller_module = snake(args.controller) @@ -69,31 +71,29 @@ class Scaffold(Command): self.add_init_import(module('controllers', '__init__.py'), controller_module) self.dump('controllers.jinja2', module('controllers', controller_file), config=args) - # self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args) - return + def has_import(self, initfile, module): + with open(initfile, 'r') as f: + for imp in ast.parse(f.read()).body: + if isinstance(imp, ast.Import): + if module in [mod.name for mod in imp.names]: + return True + return False - def add_init_import(self, path, module): - if not os.path.exists(path): - self.dump('__init__.jinja2', path, modules=[module]) - else: - with open(path, "r") as f: - lines = f.readlines() - # TODO: regex - if ('import %s' % module) in lines: - return - with open(path, "a") as f: - f.write('\nimport %s' % module) + def add_init_import(self, initfile, module): + if not(os.path.exists(initfile) and self.has_import(initfile, module)): + self.dump('__init__.jinja2', initfile, modules=[module]) def dump(self, template, dest, **kwargs): outdir = os.path.dirname(dest) + kwargs['create'] = not os.path.exists(dest) if not os.path.exists(outdir): os.makedirs(outdir) - self.env.get_template(template).stream(**kwargs).dump(dest) - # add trailing newline which jinja removes + content = self.env.get_template(template).render(**kwargs) with open(dest, 'a') as f: - f.write('\n') + f.write(content) def run(self, args): + # TODO: bash completion file parser = argparse.ArgumentParser( prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1], description=self.__doc__ diff --git a/openerp/cli/scaffold/__init__.jinja2 b/openerp/cli/scaffold/__init__.jinja2 index 7a45c970f2c..b3cd02662e0 100644 --- a/openerp/cli/scaffold/__init__.jinja2 +++ b/openerp/cli/scaffold/__init__.jinja2 @@ -1,3 +1,3 @@ -# -*- coding: utf-8 -*- -{% for module in modules if module -%} -import {{ module }}{% endfor %} +{% if create -%}# -*- coding: utf-8 -*-{%- endif %} +{% for module in modules if module -%}import {{ module }} +{%- endfor %} diff --git a/openerp/cli/scaffold/ir.model.access.jinja2 b/openerp/cli/scaffold/ir.model.access.jinja2 index e5e2fb35fe7..e047031a15a 100644 --- a/openerp/cli/scaffold/ir.model.access.jinja2 +++ b/openerp/cli/scaffold/ir.model.access.jinja2 @@ -1,4 +1,4 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +{% if create -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %} {% if config.model -%} access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}} access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}} From 09dd6e3da6022e5a2b12bbb5f48f810c5161f6e6 Mon Sep 17 00:00:00 2001 From: Pariket Trivedi Date: Wed, 28 May 2014 19:05:11 +0200 Subject: [PATCH 016/121] [IMP] event_sale: extra QWeb report for printing event badges, with HTML fields for custom content --- addons/event_sale/__openerp__.py | 2 + addons/event_sale/event_demo.xml | 97 +++++++++++++++++++ addons/event_sale/event_sale.py | 3 + addons/event_sale/event_sale_report.xml | 33 +++++++ addons/event_sale/event_sale_view.xml | 40 ++++++++ .../views/report_registrationbadge.xml | 75 ++++++++++++++ 6 files changed, 250 insertions(+) create mode 100644 addons/event_sale/event_sale_report.xml create mode 100644 addons/event_sale/views/report_registrationbadge.xml diff --git a/addons/event_sale/__openerp__.py b/addons/event_sale/__openerp__.py index 35d2f51aacc..08eec29c51d 100644 --- a/addons/event_sale/__openerp__.py +++ b/addons/event_sale/__openerp__.py @@ -42,6 +42,8 @@ this event. 'data': [ 'event_sale_view.xml', 'event_sale_data.xml', + 'event_sale_report.xml', + 'views/report_registrationbadge.xml', 'security/ir.model.access.csv', ], 'demo': ['event_demo.xml'], diff --git a/addons/event_sale/event_demo.xml b/addons/event_sale/event_demo.xml index ca55b66717d..8a55172cd85 100644 --- a/addons/event_sale/event_demo.xml +++ b/addons/event_sale/event_demo.xml @@ -123,5 +123,102 @@ 5 + + + Program +
Registrations are from 8:30 am, except on Friday from 9:00 am
+
+ Lunch is served between 1:00 pm and 2:00 pm. +
+

Special Events

+
+ + + + + + + + + + +
4/619h00Barbecue Beer Event
5/618h30Odoo Awards Ceremony
+
+
+
+

+ #OpenDays +

+
+
+
Wifi network: opendays
+
Wifi password: odoo2014
+
+
+
+ sponsored by +
+ + + +
+
+ ]]> + Premium Tickets + + + + + + + + + + + + + + + + + + + + +
Full
Catering
BBQ &
Beer Event
Awards &
Walking
Dinner
Every DayJune 4thJune 5th
+

+

Free Tickets

+ + + + + + + + + + + + + + + + + + +
Drinks
Premium
Ticket
onsite
Every Day60 €/day
30 €/Friday
+ ]]>
+ +

Exhibition Hall

+ +
+ Picture of the exhibition hall +
+ ]]>
+ + diff --git a/addons/event_sale/event_sale.py b/addons/event_sale/event_sale.py index b4f42673aba..8c679996c22 100644 --- a/addons/event_sale/event_sale.py +++ b/addons/event_sale/event_sale.py @@ -165,6 +165,9 @@ class event_event(osv.osv): ['seats_max', 'registration_ids'], 20), 'event.event.ticket': (_get_ticket_events, ['seats_max'], 10), }), + 'badge_back': fields.html('Badge Back', readonly=False, translate=True, states={'done': [('readonly', True)]}), + 'badge_innerleft': fields.html('Badge Innner Left', readonly=False, translate=True, states={'done': [('readonly', True)]}), + 'badge_innerright': fields.html('Badge Inner Right', readonly=False, translate=True, states={'done': [('readonly', True)]}), } _defaults = { 'event_ticket_ids': _get_tickets diff --git a/addons/event_sale/event_sale_report.xml b/addons/event_sale/event_sale_report.xml new file mode 100644 index 00000000000..1d9e21bc742 --- /dev/null +++ b/addons/event_sale/event_sale_report.xml @@ -0,0 +1,33 @@ + + + + + + European A4 low margin + + A4 + 0 + 0 + Portrait + 5 + 5 + 5 + 5 + + 0 + 80 + + + + + + + + \ No newline at end of file diff --git a/addons/event_sale/event_sale_view.xml b/addons/event_sale/event_sale_view.xml index 93f9bd8ffb4..d1baab9a7be 100644 --- a/addons/event_sale/event_sale_view.xml +++ b/addons/event_sale/event_sale_view.xml @@ -112,5 +112,45 @@ + + + view_event_form + event.event + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+
+
+
diff --git a/addons/event_sale/views/report_registrationbadge.xml b/addons/event_sale/views/report_registrationbadge.xml new file mode 100644 index 00000000000..f9f33c9b2b9 --- /dev/null +++ b/addons/event_sale/views/report_registrationbadge.xml @@ -0,0 +1,75 @@ + + + + + + From a9eba4dc405a0d1f76e04ce0ba2d26fe5057fa80 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 19:16:50 +0200 Subject: [PATCH 017/121] Detect if controller name correspond to a model name --- openerp/cli/scaffold.py | 2 ++ openerp/cli/scaffold/controllers.jinja2 | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 4fdd5a32137..8d580eba0b4 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -68,6 +68,8 @@ class Scaffold(Command): if os.path.exists(controller_file): die("Controller `%s` already exists !" % controller_file) self.add_init_import(module('__init__.py'), 'controllers') + # Check if the controller name correspond to a model and expose result to templates + args.has_model = self.has_import(module('models', '__init__.py'), controller_module) self.add_init_import(module('controllers', '__init__.py'), controller_module) self.dump('controllers.jinja2', module('controllers', controller_file), config=args) diff --git a/openerp/cli/scaffold/controllers.jinja2 b/openerp/cli/scaffold/controllers.jinja2 index db08e62c375..78099b1f939 100644 --- a/openerp/cli/scaffold/controllers.jinja2 +++ b/openerp/cli/scaffold/controllers.jinja2 @@ -6,8 +6,8 @@ class {{ config.controller }}(main.Home): @http.route('/{{ config.module }}/{{ config.controller }}', auth='public') def index(self): return "Hello, world!" -{% if config.model %} - @http.route('/{{ config.module }}/{{ config.controller }}/{{ config.model }}/'], type='http', auth='public') - def {{ config.model }}(self, {{ config.model }}, **kw): - return "Hello, %r!" % {{ config.model }} +{% if config.has_model %} + @http.route('/{{ config.module }}/{{ config.controller }}/'], type='http', auth='public') + def {{ config.controller }}(self, {{ config.controller }}, **kw): + return "Hello, %r!" % {{ config.controller }} {% endif %} From 4b8814fa9ef56dfe287c661de9f2156ce81fb33c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 28 May 2014 19:32:55 +0200 Subject: [PATCH 018/121] Prevent scaffold --init to be executed in another module --- openerp/cli/scaffold.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 8d580eba0b4..4ea1fbd0200 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -33,21 +33,16 @@ class Scaffold(Command): dest = directory(args.dest) if args.init: - module_name = snake(args.init) - module = functools.partial(os.path.join, dest, module_name) + args.module = snake(args.init) + module = functools.partial(os.path.join, dest, args.module) if os.path.exists(module()): die("Can't initialize module in `%s`: Directory already exists." % module()) + if self.get_module_root(dest): + die("Can't init a new module in another module, you probably want to run this " + "command from your project's root") else: - module_name = dest.split(os.path.sep)[-1] - # find the module's root directory - while not os.path.exists(os.path.join(dest, '%s.py' % self.manifest)): - new_dest = os.path.abspath(os.path.join(dest, os.pardir)) - if dest == new_dest: - die("Can't find module directory. Please `cd` to it's path or use --dest") - module_name = dest.split(os.path.sep)[-1] - dest = new_dest + args.module, dest = self.get_module_root(dest) module = functools.partial(os.path.join, dest) - args.module = module_name if args.init: self.dump('%s.jinja2' % self.manifest, module('%s.py' % self.manifest), config=args) @@ -73,6 +68,17 @@ class Scaffold(Command): self.add_init_import(module('controllers', '__init__.py'), controller_module) self.dump('controllers.jinja2', module('controllers', controller_file), config=args) + def get_module_root(self, path): + module_name = path.split(os.path.sep)[-1] + # find the module's root directory + while not os.path.exists(os.path.join(path, '%s.py' % self.manifest)): + new_path = os.path.abspath(os.path.join(path, os.pardir)) + if path == new_path: + return None + module_name = path.split(os.path.sep)[-1] + path = new_path + return (module_name, path) + def has_import(self, initfile, module): with open(initfile, 'r') as f: for imp in ast.parse(f.read()).body: From 130c8893480a977d68d1faabce96a3ba3c1e01d7 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 29 May 2014 15:02:27 +0200 Subject: [PATCH 019/121] [FIX] ir.attachment mess, restore list view --- addons/mail/mail_message_view.xml | 2 +- openerp/addons/base/ir/ir_attachment_view.xml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 1c4a7f55c10..81b47db819a 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -115,7 +115,7 @@ - kanban,form + kanban,list,form diff --git a/openerp/addons/base/ir/ir_attachment_view.xml b/openerp/addons/base/ir/ir_attachment_view.xml index 02ccfe73a25..c203fe0fd59 100644 --- a/openerp/addons/base/ir/ir_attachment_view.xml +++ b/openerp/addons/base/ir/ir_attachment_view.xml @@ -45,7 +45,9 @@ - + + + From 6c89284ec6a938ac9c9ba44daeceb4d2305b4968 Mon Sep 17 00:00:00 2001 From: sve-odoo Date: Thu, 29 May 2014 15:48:10 +0200 Subject: [PATCH 020/121] [ADD] "Model" Column in base_action_rule tree view. --- addons/base_action_rule/base_action_rule_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml index a4341d403ca..52a7d30d7f5 100644 --- a/addons/base_action_rule/base_action_rule_view.xml +++ b/addons/base_action_rule/base_action_rule_view.xml @@ -87,6 +87,7 @@ + From 14f7d31a5f3d37f051b26d329eefd470ce010d5c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 29 May 2014 16:25:30 +0200 Subject: [PATCH 021/121] Refactor scaffolding engine so it can be used from outside --- openerp/cli/scaffold.py | 204 +++++++++++--------- openerp/cli/scaffold/__init__.jinja2 | 2 +- openerp/cli/scaffold/__openerp__.jinja2 | 3 +- openerp/cli/scaffold/controllers.jinja2 | 12 +- openerp/cli/scaffold/ir.model.access.jinja2 | 10 +- openerp/cli/scaffold/models.jinja2 | 4 +- 6 files changed, 130 insertions(+), 105 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 4ea1fbd0200..930d454e831 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -12,94 +12,11 @@ import jinja2 from . import Command +MANIFEST = '__openerp__' + class Scaffold(Command): "Generate an Odoo module skeleton." - def __init__(self): - super(Scaffold, self).__init__() - env = jinja2.Environment(loader=jinja2.PackageLoader( - 'openerp.cli', 'scaffold')) - env.filters['snake'] = snake - self.env = env - self.manifest = '__openerp__' - - def scaffold(self, args): - args.dependency = 'base' - # TODO: update dependencies according to --web and --theme - # if args.web: - # args.dependency = 'web' - # elif args.theme: - # args.dependency = 'website' - - dest = directory(args.dest) - if args.init: - args.module = snake(args.init) - module = functools.partial(os.path.join, dest, args.module) - if os.path.exists(module()): - die("Can't initialize module in `%s`: Directory already exists." % module()) - if self.get_module_root(dest): - die("Can't init a new module in another module, you probably want to run this " - "command from your project's root") - else: - args.module, dest = self.get_module_root(dest) - module = functools.partial(os.path.join, dest) - - if args.init: - self.dump('%s.jinja2' % self.manifest, module('%s.py' % self.manifest), config=args) - - if args.model: - model_module = snake(args.model) - model_file = module('models', '%s.py' % model_module) - if os.path.exists(model_file): - die("Model `%s` already exists !" % model_file) - self.add_init_import(module('__init__.py'), 'models') - self.add_init_import(module('models', '__init__.py'), model_module) - self.dump('models.jinja2', model_file, config=args) - self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args) - - if args.controller: - controller_module = snake(args.controller) - controller_file = module('controllers', '%s.py' % controller_module) - if os.path.exists(controller_file): - die("Controller `%s` already exists !" % controller_file) - self.add_init_import(module('__init__.py'), 'controllers') - # Check if the controller name correspond to a model and expose result to templates - args.has_model = self.has_import(module('models', '__init__.py'), controller_module) - self.add_init_import(module('controllers', '__init__.py'), controller_module) - self.dump('controllers.jinja2', module('controllers', controller_file), config=args) - - def get_module_root(self, path): - module_name = path.split(os.path.sep)[-1] - # find the module's root directory - while not os.path.exists(os.path.join(path, '%s.py' % self.manifest)): - new_path = os.path.abspath(os.path.join(path, os.pardir)) - if path == new_path: - return None - module_name = path.split(os.path.sep)[-1] - path = new_path - return (module_name, path) - - def has_import(self, initfile, module): - with open(initfile, 'r') as f: - for imp in ast.parse(f.read()).body: - if isinstance(imp, ast.Import): - if module in [mod.name for mod in imp.names]: - return True - return False - - def add_init_import(self, initfile, module): - if not(os.path.exists(initfile) and self.has_import(initfile, module)): - self.dump('__init__.jinja2', initfile, modules=[module]) - - def dump(self, template, dest, **kwargs): - outdir = os.path.dirname(dest) - kwargs['create'] = not os.path.exists(dest) - if not os.path.exists(outdir): - os.makedirs(outdir) - content = self.env.get_template(template).render(**kwargs) - with open(dest, 'a') as f: - f.write(content) - def run(self, args): # TODO: bash completion file parser = argparse.ArgumentParser( @@ -124,7 +41,99 @@ class Scaffold(Command): if not args: sys.exit(parser.print_help()) args = parser.parse_args(args=args) - self.scaffold(args) + + dest = directory(args.dest) + if args.init: + dest = os.path.join(dest, args.init) + if os.path.exists(dest): + die("Can't initialize module in `%s`: Directory already exists." % dest) + if get_module_root(dest): + die("Can't init a new module in another Odoo module, you probably want to run this " + "command from your project's root") + else: + mroot = get_module_root(dest) + if not mroot: + die("The path `%s` provided does not point to an existing Odoo module. " + "Forgot to `--init` ?" % dest) + dest = mroot + + scaffold = ScaffoldModule(dest) + if args.model: + scaffold.add_model(args.model) + if args.controller: + scaffold.add_controller(args.controller) + +class ScaffoldModule(object): + """ + Object for scaffolding existing or new Odoo modules + + @param path: Path of an existing module or path of module to create + """ + def __init__(self, path): + env = jinja2.Environment(loader=jinja2.PackageLoader( + 'openerp.cli', 'scaffold')) + env.filters['snake'] = snake + self.env = env + self.path = functools.partial(os.path.join, directory(path)) + self.created = not os.path.exists(self.path()) + directory(path, create=True) + if self.created: + self.module_name = self.path().split(os.path.sep)[-1] + self.dump('%s.jinja2' % MANIFEST, self.path('%s.py' % MANIFEST)) + else: + # TODO: get this information from manifest + self.module_name = self.path().split(os.path.sep)[-1] + + def add_model(self, model): + model_module = snake(model) + model_file = self.path('models', '%s.py' % model_module) + if os.path.exists(model_file): + die("Model `%s` already exists !" % model_file) + self.add_init_import(self.path('__init__.py'), 'models') + self.add_init_import(self.path('models', '__init__.py'), model_module) + self.dump('models.jinja2', model_file, model=model) + self.dump('ir.model.access.jinja2', self.path('security', 'ir.model.access.csv'), model=model) + + def add_controller(self, controller): + controller_module = snake(controller) + controller_file = self.path('controllers', '%s.py' % controller_module) + if os.path.exists(controller_file): + die("Controller `%s` already exists !" % controller_file) + self.add_init_import(self.path('__init__.py'), 'controllers') + # Check if the controller name correspond to a model and expose result to templates + has_model = self.has_import(self.path('models', '__init__.py'), controller_module) + self.add_init_import(self.path('controllers', '__init__.py'), controller_module) + self.dump('controllers.jinja2', self.path('controllers', controller_file), + controller=controller, has_model=has_model) + + def has_import(self, initfile, module): + with open(initfile, 'r') as f: + for imp in ast.parse(f.read()).body: + if isinstance(imp, ast.Import): + if module in [mod.name for mod in imp.names]: + return True + return False + + def ensure_dependency_to(self, module): + # TODO: update dependencies according to --web and --theme + # if args.web: + # args.dependency = 'web' + # elif args.theme: + # args.dependency = 'website' + pass + + def add_init_import(self, initfile, module): + if not(os.path.exists(initfile) and self.has_import(initfile, module)): + self.dump('__init__.jinja2', initfile, modules=[module]) + + def dump(self, template, dest, **kwargs): + outdir = os.path.dirname(dest) + kwargs['file_created'] = not os.path.exists(dest) + if not os.path.exists(outdir): + os.makedirs(outdir) + content = self.env.get_template(template).render(module_name=self.module_name, **kwargs) + with open(dest, 'a') as f: + f.write(content) def snake(s): """ snake cases ``s`` @@ -145,16 +154,33 @@ def identifier(s): die("%s is not a valid Python identifier" % s) return s -def directory(p): +def directory(p, create=False): expanded = os.path.abspath( os.path.expanduser( os.path.expandvars(p))) - if not os.path.exists(expanded): + if create and not os.path.exists(expanded): os.makedirs(expanded) - if not os.path.isdir(expanded): + if create and not os.path.isdir(expanded): die("%s exists but is not a directory" % p) return expanded +def get_module_root(path): + """ + Get closest module's root begining from path + + @param path: Path from which the lookup should start + + @return: Module root path + """ + # find the module's root directory + while not os.path.exists(os.path.join(path, '%s.py' % MANIFEST)): + new_path = os.path.abspath(os.path.join(path, os.pardir)) + if path == new_path: + return None + path = new_path + return path + + def die(message, code=1): print >>sys.stderr, message sys.exit(code) diff --git a/openerp/cli/scaffold/__init__.jinja2 b/openerp/cli/scaffold/__init__.jinja2 index b3cd02662e0..e8b1efb3fc7 100644 --- a/openerp/cli/scaffold/__init__.jinja2 +++ b/openerp/cli/scaffold/__init__.jinja2 @@ -1,3 +1,3 @@ -{% if create -%}# -*- coding: utf-8 -*-{%- endif %} +{% if file_created -%}# -*- coding: utf-8 -*-{%- endif %} {% for module in modules if module -%}import {{ module }} {%- endfor %} diff --git a/openerp/cli/scaffold/__openerp__.jinja2 b/openerp/cli/scaffold/__openerp__.jinja2 index c8bd331d063..38f60d5241b 100644 --- a/openerp/cli/scaffold/__openerp__.jinja2 +++ b/openerp/cli/scaffold/__openerp__.jinja2 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- { - 'name': "{{ config.module }}", + 'name': "{{ module_name }}", 'summary': """ Short (1 phrase/line) summary of the module's purpose, used as @@ -21,7 +21,6 @@ # any module necessary for this one to work correctly 'depends': ['base'], 'data': [ - # {{- "'security/ir.model.access.csv'" if config.model -}} ], 'demo': [ diff --git a/openerp/cli/scaffold/controllers.jinja2 b/openerp/cli/scaffold/controllers.jinja2 index 78099b1f939..d8756e76524 100644 --- a/openerp/cli/scaffold/controllers.jinja2 +++ b/openerp/cli/scaffold/controllers.jinja2 @@ -2,12 +2,12 @@ from openerp import http from openerp.addons.web.controllers import main -class {{ config.controller }}(main.Home): - @http.route('/{{ config.module }}/{{ config.controller }}', auth='public') +class {{ controller }}(main.Home): + @http.route('/{{ module_name }}/{{ controller }}', auth='public') def index(self): return "Hello, world!" -{% if config.has_model %} - @http.route('/{{ config.module }}/{{ config.controller }}/'], type='http', auth='public') - def {{ config.controller }}(self, {{ config.controller }}, **kw): - return "Hello, %r!" % {{ config.controller }} +{% if has_model %} + @http.route('/{{ module_name }}/{{ controller }}/'], type='http', auth='public') + def {{ controller }}(self, {{ controller }}, **kw): + return "Hello, %r!" % {{ controller }} {% endif %} diff --git a/openerp/cli/scaffold/ir.model.access.jinja2 b/openerp/cli/scaffold/ir.model.access.jinja2 index e047031a15a..96bec7ba9f2 100644 --- a/openerp/cli/scaffold/ir.model.access.jinja2 +++ b/openerp/cli/scaffold/ir.model.access.jinja2 @@ -1,6 +1,6 @@ -{% if create -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %} -{% if config.model -%} -access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}} -access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}} -model_{{ config.module|snake }}_{{ config.model|snake }},,1,0,0,0 +{% if file_created -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %} +{% if model -%} +access_{{ module_name|snake }}_{{ model|snake }},{{- '' -}} +access_{{ module_name|snake }}_{{ model|snake }},{{- '' -}} +model_{{ module_name|snake }}_{{ model|snake }},,1,0,0,0 {%- endif %} diff --git a/openerp/cli/scaffold/models.jinja2 b/openerp/cli/scaffold/models.jinja2 index 878bf9be4f6..6fe3aceadd3 100644 --- a/openerp/cli/scaffold/models.jinja2 +++ b/openerp/cli/scaffold/models.jinja2 @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from openerp.osv import orm, fields -class {{ config.model }}(orm.Model): - _name = "{{ config.module|snake }}.{{ config.model|snake }}" +class {{ model }}(orm.Model): + _name = "{{ module_name|snake }}.{{ model|snake }}" _columns = { 'name': fields.char(), From 5f717cfdd2b638887fa11f5ed81ac24985c4fbcc Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 29 May 2014 18:01:43 +0200 Subject: [PATCH 022/121] Added basic scaffolding for webclient module --- openerp/cli/scaffold.py | 36 ++++++++++++++++------- openerp/cli/scaffold/webclient_css.jinja2 | 4 +++ openerp/cli/scaffold/webclient_js.jinja2 | 9 ++++++ openerp/cli/scaffold/webclient_xml.jinja2 | 7 +++++ 4 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 openerp/cli/scaffold/webclient_css.jinja2 create mode 100644 openerp/cli/scaffold/webclient_js.jinja2 create mode 100644 openerp/cli/scaffold/webclient_xml.jinja2 diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 930d454e831..700ffbbd212 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -62,6 +62,8 @@ class Scaffold(Command): scaffold.add_model(args.model) if args.controller: scaffold.add_controller(args.controller) + if args.web: + scaffold.add_webclient_structure() class ScaffoldModule(object): """ @@ -79,7 +81,7 @@ class ScaffoldModule(object): directory(path, create=True) if self.created: self.module_name = self.path().split(os.path.sep)[-1] - self.dump('%s.jinja2' % MANIFEST, self.path('%s.py' % MANIFEST)) + self.render_file('%s.jinja2' % MANIFEST, self.path('%s.py' % MANIFEST)) else: # TODO: get this information from manifest self.module_name = self.path().split(os.path.sep)[-1] @@ -91,8 +93,9 @@ class ScaffoldModule(object): die("Model `%s` already exists !" % model_file) self.add_init_import(self.path('__init__.py'), 'models') self.add_init_import(self.path('models', '__init__.py'), model_module) - self.dump('models.jinja2', model_file, model=model) - self.dump('ir.model.access.jinja2', self.path('security', 'ir.model.access.csv'), model=model) + self.render_file('models.jinja2', model_file, model=model) + self.render_file('ir.model.access.jinja2', self.path('security', 'ir.model.access.csv'), + if_exists='append', model=model) def add_controller(self, controller): controller_module = snake(controller) @@ -103,8 +106,14 @@ class ScaffoldModule(object): # Check if the controller name correspond to a model and expose result to templates has_model = self.has_import(self.path('models', '__init__.py'), controller_module) self.add_init_import(self.path('controllers', '__init__.py'), controller_module) - self.dump('controllers.jinja2', self.path('controllers', controller_file), - controller=controller, has_model=has_model) + self.render_file('controllers.jinja2', controller_file, controller=controller, + has_model=has_model) + + def add_webclient_structure(self): + prefix = '%s.%%s' % self.module_name + for ext in ('js', 'css', 'xml'): + self.render_file('webclient_%s.jinja2' % ext, + self.path('static', 'src', ext, prefix % ext)) def has_import(self, initfile, module): with open(initfile, 'r') as f: @@ -124,15 +133,23 @@ class ScaffoldModule(object): def add_init_import(self, initfile, module): if not(os.path.exists(initfile) and self.has_import(initfile, module)): - self.dump('__init__.jinja2', initfile, modules=[module]) + self.render_file('__init__.jinja2', initfile, if_exists='append', modules=[module]) - def dump(self, template, dest, **kwargs): + def render_file(self, template, dest, if_exists='skip', **kwargs): + mode = 'a' + if os.path.exists(dest): + if if_exists == 'replace': + mode = 'w' + elif if_exists != 'append': + print "File `%s` already exists. Skipping it..." % dest + return + else: + kwargs['file_created'] = True outdir = os.path.dirname(dest) - kwargs['file_created'] = not os.path.exists(dest) if not os.path.exists(outdir): os.makedirs(outdir) content = self.env.get_template(template).render(module_name=self.module_name, **kwargs) - with open(dest, 'a') as f: + with open(dest, mode) as f: f.write(content) def snake(s): @@ -180,7 +197,6 @@ def get_module_root(path): path = new_path return path - def die(message, code=1): print >>sys.stderr, message sys.exit(code) diff --git a/openerp/cli/scaffold/webclient_css.jinja2 b/openerp/cli/scaffold/webclient_css.jinja2 new file mode 100644 index 00000000000..b4955fa33ce --- /dev/null +++ b/openerp/cli/scaffold/webclient_css.jinja2 @@ -0,0 +1,4 @@ +@charset "utf-8"; +.openerp .oe_{{ module_name|snake }} { + background: white; +} diff --git a/openerp/cli/scaffold/webclient_js.jinja2 b/openerp/cli/scaffold/webclient_js.jinja2 new file mode 100644 index 00000000000..2ee203baeb4 --- /dev/null +++ b/openerp/cli/scaffold/webclient_js.jinja2 @@ -0,0 +1,9 @@ +openerp.{{ module_name|snake }} = function (instance) { + +var _t = instance.web._t, + _lt = instance.web._lt; +var QWeb = instance.web.qweb; + +instance.{{ module_name|snake }}.MyClientAction = null; // TODO: scaffold client action + +}; diff --git a/openerp/cli/scaffold/webclient_xml.jinja2 b/openerp/cli/scaffold/webclient_xml.jinja2 new file mode 100644 index 00000000000..8ae117ce494 --- /dev/null +++ b/openerp/cli/scaffold/webclient_xml.jinja2 @@ -0,0 +1,7 @@ + From 0e01164842459a14ba76e6e4703a91d57ce90650 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 29 May 2014 18:23:48 +0200 Subject: [PATCH 023/121] Moved get_module_root in openerp.modules.module --- openerp/cli/scaffold.py | 17 +---------------- openerp/modules/module.py | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 700ffbbd212..7268bbc9cb7 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -11,6 +11,7 @@ import sys import jinja2 from . import Command +from openerp.modules.module import get_module_root MANIFEST = '__openerp__' @@ -181,22 +182,6 @@ def directory(p, create=False): die("%s exists but is not a directory" % p) return expanded -def get_module_root(path): - """ - Get closest module's root begining from path - - @param path: Path from which the lookup should start - - @return: Module root path - """ - # find the module's root directory - while not os.path.exists(os.path.join(path, '%s.py' % MANIFEST)): - new_path = os.path.abspath(os.path.join(path, os.pardir)) - if path == new_path: - return None - path = new_path - return path - def die(message, code=1): print >>sys.stderr, message sys.exit(code) diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 0ccb2865796..0691c98768b 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -37,6 +37,8 @@ import openerp.tools as tools import openerp.release as release from openerp.tools.safe_eval import safe_eval as eval +MANIFEST = '__openerp__.py' + _logger = logging.getLogger(__name__) # addons path as a list @@ -169,6 +171,33 @@ def get_module_icon(module): return ('/' + module + '/') + '/'.join(iconpath) return '/base/' + '/'.join(iconpath) +def get_module_root(path): + """ + Get closest module's root begining from path + + # Given: + # /foo/bar/module_dir/static/src/... + + get_module_root('/foo/bar/module_dir/static/') + # returns '/foo/bar/module_dir' + + get_module_root('/foo/bar/module_dir/') + # returns '/foo/bar/module_dir' + + get_module_root('/foo/bar') + # returns None + + @param path: Path from which the lookup should start + + @return: Module root path or None if not found + """ + while not os.path.exists(os.path.join(path, MANIFEST)): + new_path = os.path.abspath(os.path.join(path, os.pardir)) + if path == new_path: + return None + path = new_path + return path + def load_information_from_description_file(module, mod_path=None): """ :param module: The name of the module (sale, purchase, ...) @@ -177,7 +206,7 @@ def load_information_from_description_file(module, mod_path=None): if not mod_path: mod_path = get_module_path(module) - terp_file = mod_path and opj(mod_path, '__openerp__.py') or False + terp_file = mod_path and opj(mod_path, MANIFEST) or False if terp_file: info = {} if os.path.isfile(terp_file): @@ -219,7 +248,7 @@ def load_information_from_description_file(module, mod_path=None): #TODO: refactor the logger in this file to follow the logging guidelines # for 6.0 - _logger.debug('module %s: no __openerp__.py file found.', module) + _logger.debug('module %s: no %s file found.', module, MANIFEST) return {} def init_module_models(cr, module_name, obj_list): @@ -291,7 +320,7 @@ def get_modules(): return name def is_really_module(name): - manifest_name = opj(dir, name, '__openerp__.py') + manifest_name = opj(dir, name, MANIFEST) zipfile_name = opj(dir, name) return os.path.isfile(manifest_name) return map(clean, filter(is_really_module, os.listdir(dir))) From 36485190acb2f68ebdda906aee6b250ffef68dc5 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 29 May 2014 20:02:30 +0200 Subject: [PATCH 024/121] Update manifest for dependencies --- openerp/cli/scaffold.py | 57 ++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 7268bbc9cb7..c882e33c0c3 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -4,16 +4,19 @@ import argparse import ast import functools import keyword +import logging import os import re +import simplejson import sys import jinja2 from . import Command -from openerp.modules.module import get_module_root -MANIFEST = '__openerp__' +from openerp.modules.module import (get_module_root, MANIFEST, + load_information_from_description_file as load_manifest) + class Scaffold(Command): "Generate an Odoo module skeleton." @@ -58,6 +61,7 @@ class Scaffold(Command): "Forgot to `--init` ?" % dest) dest = mroot + logging.disable(logging.CRITICAL) scaffold = ScaffoldModule(dest) if args.model: scaffold.add_model(args.model) @@ -80,12 +84,10 @@ class ScaffoldModule(object): self.path = functools.partial(os.path.join, directory(path)) self.created = not os.path.exists(self.path()) directory(path, create=True) + self.module_name = self.path().split(os.path.sep)[-1] if self.created: - self.module_name = self.path().split(os.path.sep)[-1] - self.render_file('%s.jinja2' % MANIFEST, self.path('%s.py' % MANIFEST)) - else: - # TODO: get this information from manifest - self.module_name = self.path().split(os.path.sep)[-1] + manifest_base = os.path.splitext(MANIFEST)[0] + self.render_file('%s.jinja2' % manifest_base, self.path('%s.py' % manifest_base)) def add_model(self, model): model_module = snake(model) @@ -111,6 +113,7 @@ class ScaffoldModule(object): has_model=has_model) def add_webclient_structure(self): + self.append_manifest_list('depends', 'web') prefix = '%s.%%s' % self.module_name for ext in ('js', 'css', 'xml'): self.render_file('webclient_%s.jinja2' % ext, @@ -124,13 +127,32 @@ class ScaffoldModule(object): return True return False - def ensure_dependency_to(self, module): - # TODO: update dependencies according to --web and --theme - # if args.web: - # args.dependency = 'web' - # elif args.theme: - # args.dependency = 'website' - pass + def get_manifest(self, key=None, default=None): + manifest = load_manifest(self.module_name, self.path()) + if key: + return manifest.get(key, default) + else: + return manifest + + def append_manifest_list(self, key, value, unique=True): + vals = self.get_manifest(key, []) + if unique and value in vals: + return + vals.append(value) + self.change_manifest_key(key, vals) + + def change_manifest_key(self, key, value): + value = simplejson.dumps(value) + with open(self.path(MANIFEST), 'r') as f: + data = f.read() + sdata = re.split('["\']%s["\']\s?:\s?\[[^\]]*\]' % key, data) + add = "'%s': %s" % (key, value) + if len(sdata) != 2: + warn("Could not update `%s` key in manifest. You should add this by yourself:" + "\n\n%s\n" % (key, add)) + else: + with open(self.path(MANIFEST), 'w') as f: + f.write(add.join(sdata)) def add_init_import(self, initfile, module): if not(os.path.exists(initfile) and self.has_import(initfile, module)): @@ -142,7 +164,7 @@ class ScaffoldModule(object): if if_exists == 'replace': mode = 'w' elif if_exists != 'append': - print "File `%s` already exists. Skipping it..." % dest + warn("File `%s` already exists. Skipping it..." % dest) return else: kwargs['file_created'] = True @@ -185,3 +207,8 @@ def directory(p, create=False): def die(message, code=1): print >>sys.stderr, message sys.exit(code) + +def warn(message): + # ASK: shall we use logger ? + print "WARNING: " + message + From 7f984dd6ef78d650046bdabf35fa314590b31ffd Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Fri, 30 May 2014 10:45:57 +0200 Subject: [PATCH 025/121] Added ir.model.access in manifest --- openerp/cli/scaffold.py | 4 +++- openerp/cli/scaffold/ir.model.access.jinja2 | 6 +++--- openerp/cli/scaffold/models.jinja2 | 2 +- openerp/cli/scaffold/webclient_css.jinja2 | 2 +- openerp/cli/scaffold/webclient_js.jinja2 | 9 +++++++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index c882e33c0c3..58d63aed365 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -64,7 +64,7 @@ class Scaffold(Command): logging.disable(logging.CRITICAL) scaffold = ScaffoldModule(dest) if args.model: - scaffold.add_model(args.model) + scaffold.add_model(snake(args.model)) if args.controller: scaffold.add_controller(args.controller) if args.web: @@ -99,6 +99,7 @@ class ScaffoldModule(object): self.render_file('models.jinja2', model_file, model=model) self.render_file('ir.model.access.jinja2', self.path('security', 'ir.model.access.csv'), if_exists='append', model=model) + self.append_manifest_list('data', 'security/ir.model.access.csv') def add_controller(self, controller): controller_module = snake(controller) @@ -135,6 +136,7 @@ class ScaffoldModule(object): return manifest def append_manifest_list(self, key, value, unique=True): + # TODO: append value without altering serialized formatting vals = self.get_manifest(key, []) if unique and value in vals: return diff --git a/openerp/cli/scaffold/ir.model.access.jinja2 b/openerp/cli/scaffold/ir.model.access.jinja2 index 96bec7ba9f2..bf00ba51972 100644 --- a/openerp/cli/scaffold/ir.model.access.jinja2 +++ b/openerp/cli/scaffold/ir.model.access.jinja2 @@ -1,6 +1,6 @@ {% if file_created -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %} {% if model -%} -access_{{ module_name|snake }}_{{ model|snake }},{{- '' -}} -access_{{ module_name|snake }}_{{ model|snake }},{{- '' -}} -model_{{ module_name|snake }}_{{ model|snake }},,1,0,0,0 +access_{{ module_name }}_{{ model }},{{- '' -}} +access_{{ module_name }}_{{ model }},{{- '' -}} +model_{{ module_name }}_{{ model }},,1,0,0,0 {%- endif %} diff --git a/openerp/cli/scaffold/models.jinja2 b/openerp/cli/scaffold/models.jinja2 index 6fe3aceadd3..d5c82cfa7c6 100644 --- a/openerp/cli/scaffold/models.jinja2 +++ b/openerp/cli/scaffold/models.jinja2 @@ -2,7 +2,7 @@ from openerp.osv import orm, fields class {{ model }}(orm.Model): - _name = "{{ module_name|snake }}.{{ model|snake }}" + _name = "{{ module_name }}.{{ model }}" _columns = { 'name': fields.char(), diff --git a/openerp/cli/scaffold/webclient_css.jinja2 b/openerp/cli/scaffold/webclient_css.jinja2 index b4955fa33ce..b1d4da5c22b 100644 --- a/openerp/cli/scaffold/webclient_css.jinja2 +++ b/openerp/cli/scaffold/webclient_css.jinja2 @@ -1,4 +1,4 @@ @charset "utf-8"; -.openerp .oe_{{ module_name|snake }} { +.openerp .oe_{{ module_name }} { background: white; } diff --git a/openerp/cli/scaffold/webclient_js.jinja2 b/openerp/cli/scaffold/webclient_js.jinja2 index 2ee203baeb4..34a168961ae 100644 --- a/openerp/cli/scaffold/webclient_js.jinja2 +++ b/openerp/cli/scaffold/webclient_js.jinja2 @@ -1,9 +1,14 @@ -openerp.{{ module_name|snake }} = function (instance) { +openerp.{{ module_name }} = function (instance) { var _t = instance.web._t, _lt = instance.web._lt; var QWeb = instance.web.qweb; -instance.{{ module_name|snake }}.MyClientAction = null; // TODO: scaffold client action +instance.web.WebClient.include({ + show_application: function () { + console.log("Show application"); + return this._super.apply(this, arguments); + }; +}); }; From 10fb6525e90313691bb1f5e769b05b0ed974ae93 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Fri, 30 May 2014 11:35:28 +0200 Subject: [PATCH 026/121] Basic support for xml data files --- openerp/cli/scaffold.py | 29 ++++++++++++++++++--- openerp/cli/scaffold/__openerp__.jinja2 | 2 +- openerp/cli/scaffold/controllers.jinja2 | 4 +-- openerp/cli/scaffold/ir.model.access.jinja2 | 6 ++--- openerp/cli/scaffold/models.jinja2 | 2 +- openerp/cli/scaffold/record.jinja2 | 4 +++ openerp/cli/scaffold/webclient_css.jinja2 | 2 +- openerp/cli/scaffold/webclient_js.jinja2 | 2 +- openerp/cli/scaffold/webclient_xml.jinja2 | 4 +-- openerp/cli/scaffold/xmldata.jinja2 | 5 ++++ 10 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 openerp/cli/scaffold/record.jinja2 create mode 100644 openerp/cli/scaffold/xmldata.jinja2 diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py index 58d63aed365..d7b28740355 100644 --- a/openerp/cli/scaffold.py +++ b/openerp/cli/scaffold.py @@ -84,7 +84,7 @@ class ScaffoldModule(object): self.path = functools.partial(os.path.join, directory(path)) self.created = not os.path.exists(self.path()) directory(path, create=True) - self.module_name = self.path().split(os.path.sep)[-1] + self.module = self.path().split(os.path.sep)[-1] if self.created: manifest_base = os.path.splitext(MANIFEST)[0] self.render_file('%s.jinja2' % manifest_base, self.path('%s.py' % manifest_base)) @@ -96,11 +96,17 @@ class ScaffoldModule(object): die("Model `%s` already exists !" % model_file) self.add_init_import(self.path('__init__.py'), 'models') self.add_init_import(self.path('models', '__init__.py'), model_module) + self.render_file('models.jinja2', model_file, model=model) self.render_file('ir.model.access.jinja2', self.path('security', 'ir.model.access.csv'), if_exists='append', model=model) self.append_manifest_list('data', 'security/ir.model.access.csv') + demo_file = '%s_demo.xml' % self.module + self.append_xml_data('record.jinja2', self.path(demo_file), + model=model) + self.append_manifest_list('demo', demo_file) + def add_controller(self, controller): controller_module = snake(controller) controller_file = self.path('controllers', '%s.py' % controller_module) @@ -115,7 +121,7 @@ class ScaffoldModule(object): def add_webclient_structure(self): self.append_manifest_list('depends', 'web') - prefix = '%s.%%s' % self.module_name + prefix = '%s.%%s' % self.module for ext in ('js', 'css', 'xml'): self.render_file('webclient_%s.jinja2' % ext, self.path('static', 'src', ext, prefix % ext)) @@ -129,7 +135,7 @@ class ScaffoldModule(object): return False def get_manifest(self, key=None, default=None): - manifest = load_manifest(self.module_name, self.path()) + manifest = load_manifest(self.module, self.path()) if key: return manifest.get(key, default) else: @@ -173,10 +179,25 @@ class ScaffoldModule(object): outdir = os.path.dirname(dest) if not os.path.exists(outdir): os.makedirs(outdir) - content = self.env.get_template(template).render(module_name=self.module_name, **kwargs) + content = self.env.get_template(template).render(module=self.module, **kwargs) with open(dest, mode) as f: f.write(content) + def append_xml_data(self, template, dest, **kwargs): + if not os.path.exists(dest): + self.render_file('xmldata.jinja2', dest, **kwargs) + with open(dest, 'r') as f: + data = f.read() + m = re.search('(^\s*)?', data, re.MULTILINE) + content = self.env.get_template(template).render(module=self.module, **kwargs) + if not m: + warn("Could not add data in `%s`. You should add this by yourself:" + "\n\n%s\n" % (dest, content)) + else: + data = data[:m.start()] + content + m.group() + data[m.end():] + with open(self.path(dest), 'w') as f: + f.write(data) + def snake(s): """ snake cases ``s`` diff --git a/openerp/cli/scaffold/__openerp__.jinja2 b/openerp/cli/scaffold/__openerp__.jinja2 index 38f60d5241b..43559042818 100644 --- a/openerp/cli/scaffold/__openerp__.jinja2 +++ b/openerp/cli/scaffold/__openerp__.jinja2 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- { - 'name': "{{ module_name }}", + 'name': "{{ module }}", 'summary': """ Short (1 phrase/line) summary of the module's purpose, used as diff --git a/openerp/cli/scaffold/controllers.jinja2 b/openerp/cli/scaffold/controllers.jinja2 index d8756e76524..dfed6fb9bc0 100644 --- a/openerp/cli/scaffold/controllers.jinja2 +++ b/openerp/cli/scaffold/controllers.jinja2 @@ -3,11 +3,11 @@ from openerp import http from openerp.addons.web.controllers import main class {{ controller }}(main.Home): - @http.route('/{{ module_name }}/{{ controller }}', auth='public') + @http.route('/{{ module }}/{{ controller }}', auth='public') def index(self): return "Hello, world!" {% if has_model %} - @http.route('/{{ module_name }}/{{ controller }}/'], type='http', auth='public') + @http.route('/{{ module }}/{{ controller }}/'], type='http', auth='public') def {{ controller }}(self, {{ controller }}, **kw): return "Hello, %r!" % {{ controller }} {% endif %} diff --git a/openerp/cli/scaffold/ir.model.access.jinja2 b/openerp/cli/scaffold/ir.model.access.jinja2 index bf00ba51972..af558a3b625 100644 --- a/openerp/cli/scaffold/ir.model.access.jinja2 +++ b/openerp/cli/scaffold/ir.model.access.jinja2 @@ -1,6 +1,6 @@ {% if file_created -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %} {% if model -%} -access_{{ module_name }}_{{ model }},{{- '' -}} -access_{{ module_name }}_{{ model }},{{- '' -}} -model_{{ module_name }}_{{ model }},,1,0,0,0 +access_{{ module }}_{{ model }},{{- '' -}} +access_{{ module }}_{{ model }},{{- '' -}} +model_{{ module }}_{{ model }},,1,0,0,0 {%- endif %} diff --git a/openerp/cli/scaffold/models.jinja2 b/openerp/cli/scaffold/models.jinja2 index d5c82cfa7c6..36155a2566d 100644 --- a/openerp/cli/scaffold/models.jinja2 +++ b/openerp/cli/scaffold/models.jinja2 @@ -2,7 +2,7 @@ from openerp.osv import orm, fields class {{ model }}(orm.Model): - _name = "{{ module_name }}.{{ model }}" + _name = "{{ module }}.{{ model }}" _columns = { 'name': fields.char(), diff --git a/openerp/cli/scaffold/record.jinja2 b/openerp/cli/scaffold/record.jinja2 new file mode 100644 index 00000000000..53e4ff22383 --- /dev/null +++ b/openerp/cli/scaffold/record.jinja2 @@ -0,0 +1,4 @@ + + My first record for model '{{ module }}.{{ model }}' + + diff --git a/openerp/cli/scaffold/webclient_css.jinja2 b/openerp/cli/scaffold/webclient_css.jinja2 index b1d4da5c22b..dadce53503b 100644 --- a/openerp/cli/scaffold/webclient_css.jinja2 +++ b/openerp/cli/scaffold/webclient_css.jinja2 @@ -1,4 +1,4 @@ @charset "utf-8"; -.openerp .oe_{{ module_name }} { +.openerp .oe_{{ module }} { background: white; } diff --git a/openerp/cli/scaffold/webclient_js.jinja2 b/openerp/cli/scaffold/webclient_js.jinja2 index 34a168961ae..9845e6f0662 100644 --- a/openerp/cli/scaffold/webclient_js.jinja2 +++ b/openerp/cli/scaffold/webclient_js.jinja2 @@ -1,4 +1,4 @@ -openerp.{{ module_name }} = function (instance) { +openerp.{{ module }} = function (instance) { var _t = instance.web._t, _lt = instance.web._lt; diff --git a/openerp/cli/scaffold/webclient_xml.jinja2 b/openerp/cli/scaffold/webclient_xml.jinja2 index 8ae117ce494..98da7f73133 100644 --- a/openerp/cli/scaffold/webclient_xml.jinja2 +++ b/openerp/cli/scaffold/webclient_xml.jinja2 @@ -1,6 +1,6 @@ diff --git a/addons/account/wizard/__init__.py b/addons/account/wizard/__init__.py index 839e490ca66..45038ee1554 100644 --- a/addons/account/wizard/__init__.py +++ b/addons/account/wizard/__init__.py @@ -63,8 +63,6 @@ import account_report_account_balance import account_change_currency -import pos_box; - +import pos_box +import account_statement_from_invoice # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - - diff --git a/addons/account/wizard/pos_box.py b/addons/account/wizard/pos_box.py index 4b7e63585d8..ba9b3bd2980 100644 --- a/addons/account/wizard/pos_box.py +++ b/addons/account/wizard/pos_box.py @@ -56,7 +56,6 @@ class CashBoxIn(CashBox): return { 'statement_id' : record.id, 'journal_id' : record.journal_id.id, - 'account_id' : record.journal_id.internal_account_id.id, 'amount' : box.amount or 0.0, 'ref' : '%s' % (box.ref or ''), 'name' : box.name, @@ -73,7 +72,6 @@ class CashBoxOut(CashBox): return { 'statement_id' : record.id, 'journal_id' : record.journal_id.id, - 'account_id' : record.journal_id.internal_account_id.id, 'amount' : -amount if amount > 0.0 else amount, 'name' : box.name, } diff --git a/addons/account_analytic_plans/__openerp__.py b/addons/account_analytic_plans/__openerp__.py index 7ca7c00e6c0..19f3788910d 100644 --- a/addons/account_analytic_plans/__openerp__.py +++ b/addons/account_analytic_plans/__openerp__.py @@ -74,6 +74,7 @@ The analytic plan validates the minimum and maximum percentage at the time of cr 'wizard/analytic_plan_create_model_view.xml', 'wizard/account_crossovered_analytic_view.xml', 'views/report_crossoveredanalyticplans.xml', + 'views/account_analytic_plans.xml', ], 'demo': [], 'test': ['test/acount_analytic_plans_report.yml'], diff --git a/addons/account_analytic_plans/account_analytic_plans_view.xml b/addons/account_analytic_plans/account_analytic_plans_view.xml index 69646faf8a0..f9a257c6fc7 100644 --- a/addons/account_analytic_plans/account_analytic_plans_view.xml +++ b/addons/account_analytic_plans/account_analytic_plans_view.xml @@ -233,57 +233,25 @@ - - account.analytic.default.form.plans - account.analytic.default - - - - - + + account.analytic.default.form.plans + account.analytic.default + + + + - - - account.analytic.default.tree.plans - account.analytic.default - - - - 1 - - - - - - - - - account.bank.statement.form.inherit - account.bank.statement - - - - - - - - - - - - - account.bank.statement.form.inherit - account.bank.statement - - - - - - - - - - - + + + + account.analytic.default.tree.plans + account.analytic.default + + + + + + + diff --git a/addons/account_bank_statement_extensions/account_bank_statement_view.xml b/addons/account_bank_statement_extensions/account_bank_statement_view.xml index d64eb68bc99..70bf0292800 100644 --- a/addons/account_bank_statement_extensions/account_bank_statement_view.xml +++ b/addons/account_bank_statement_extensions/account_bank_statement_view.xml @@ -74,10 +74,7 @@ - - - - + @@ -98,10 +95,7 @@ - - - - + @@ -129,7 +123,6 @@ - @@ -138,7 +131,6 @@ - diff --git a/addons/account_payment/wizard/account_payment_populate_statement.py b/addons/account_payment/wizard/account_payment_populate_statement.py index 92b1b1452f5..ef068a55b2c 100644 --- a/addons/account_payment/wizard/account_payment_populate_statement.py +++ b/addons/account_payment/wizard/account_payment_populate_statement.py @@ -107,12 +107,9 @@ class account_payment_populate_statement(osv.osv_memory): st_line_id = statement_line_obj.create(cr, uid, { 'name': line.order_id.reference or '?', 'amount': - amount, - 'type': 'supplier', 'partner_id': line.partner_id.id, - 'account_id': line.move_line_id.account_id.id, 'statement_id': statement.id, 'ref': line.communication, - 'voucher_id': voucher_id, }, context=context) line_obj.write(cr, uid, [line.id], {'bank_statement_line_id': st_line_id}) diff --git a/addons/account_voucher/__init__.py b/addons/account_voucher/__init__.py index 2b1478d9fa0..0acbb258b4f 100644 --- a/addons/account_voucher/__init__.py +++ b/addons/account_voucher/__init__.py @@ -22,6 +22,5 @@ import account_voucher import invoice import report -import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account_voucher/__openerp__.py b/addons/account_voucher/__openerp__.py index dc8102d6647..073128c14d3 100644 --- a/addons/account_voucher/__openerp__.py +++ b/addons/account_voucher/__openerp__.py @@ -49,7 +49,6 @@ This module manages: 'security/ir.model.access.csv', 'account_voucher_sequence.xml', 'account_voucher_workflow.xml', - 'wizard/account_statement_from_invoice_view.xml', 'account_voucher_view.xml', 'voucher_payment_receipt_view.xml', 'voucher_sales_purchase_view.xml', diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index c1424079542..6adae402e0c 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -327,7 +327,6 @@ class account_voucher(osv.osv): } _columns = { - 'active': fields.boolean('Active', help="By default, reconciliation vouchers made on draft bank statements are set as inactive, which allow to hide the customer/supplier payment while the bank statement isn't confirmed."), 'type':fields.selection([ ('sale','Sale'), ('purchase','Purchase'), @@ -389,7 +388,6 @@ class account_voucher(osv.osv): 'currency_help_label': fields.function(_fnct_currency_help_label, type='text', string="Helping Sentence", help="This sentence helps you to know how to specify the payment rate by giving you the direct effect it has"), } _defaults = { - 'active': True, 'period_id': _get_period, 'partner_id': _get_partner, 'journal_id':_get_journal, @@ -1583,114 +1581,6 @@ class account_voucher_line(osv.osv): }) return values -class account_bank_statement(osv.osv): - _inherit = 'account.bank.statement' - - def button_confirm_bank(self, cr, uid, ids, context=None): - voucher_obj = self.pool.get('account.voucher') - voucher_ids = [] - for statement in self.browse(cr, uid, ids, context=context): - voucher_ids += [line.voucher_id.id for line in statement.line_ids if line.voucher_id] - if voucher_ids: - voucher_obj.write(cr, uid, voucher_ids, {'active': True}, context=context) - return super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context) - - def button_cancel(self, cr, uid, ids, context=None): - voucher_obj = self.pool.get('account.voucher') - for st in self.browse(cr, uid, ids, context=context): - voucher_ids = [] - for line in st.line_ids: - if line.voucher_id: - voucher_ids.append(line.voucher_id.id) - voucher_obj.cancel_voucher(cr, uid, voucher_ids, context) - return super(account_bank_statement, self).button_cancel(cr, uid, ids, context=context) - - def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, next_number, context=None): - voucher_obj = self.pool.get('account.voucher') - move_line_obj = self.pool.get('account.move.line') - bank_st_line_obj = self.pool.get('account.bank.statement.line') - st_line = bank_st_line_obj.browse(cr, uid, st_line_id, context=context) - if st_line.voucher_id: - voucher_obj.write(cr, uid, [st_line.voucher_id.id], - {'number': next_number, - 'date': st_line.date, - 'period_id': st_line.statement_id.period_id.id}, - context=context) - if st_line.voucher_id.state == 'cancel': - voucher_obj.action_cancel_draft(cr, uid, [st_line.voucher_id.id], context=context) - voucher_obj.signal_proforma_voucher(cr, uid, [st_line.voucher_id.id]) - - v = voucher_obj.browse(cr, uid, st_line.voucher_id.id, context=context) - bank_st_line_obj.write(cr, uid, [st_line_id], { - 'move_ids': [(4, v.move_id.id, False)] - }) - - return move_line_obj.write(cr, uid, [x.id for x in v.move_ids], {'statement_id': st_line.statement_id.id}, context=context) - return super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line.id, company_currency_id, next_number, context=context) - - def write(self, cr, uid, ids, vals, context=None): - # Restrict to modify the journal if we already have some voucher of reconciliation created/generated. - # Because the voucher keeps in memory the journal it was created with. - for bk_st in self.browse(cr, uid, ids, context=context): - if vals.get('journal_id') and bk_st.line_ids: - if any([x.voucher_id and True or False for x in bk_st.line_ids]): - raise osv.except_osv(_('Unable to Change Journal!'), _('You can not change the journal as you already reconciled some statement lines!')) - return super(account_bank_statement, self).write(cr, uid, ids, vals, context=context) - - -class account_bank_statement_line(osv.osv): - _inherit = 'account.bank.statement.line' - - def onchange_partner_id(self, cr, uid, ids, partner_id, context=None): - res = super(account_bank_statement_line, self).onchange_partner_id(cr, uid, ids, partner_id, context=context) - if 'value' not in res: - res['value'] = {} - res['value'].update({'voucher_id' : False}) - return res - - def onchange_amount(self, cr, uid, ids, amount, context=None): - return {'value' : {'voucher_id' : False}} - - def _amount_reconciled(self, cursor, user, ids, name, args, context=None): - if not ids: - return {} - res = {} - for line in self.browse(cursor, user, ids, context=context): - if line.voucher_id: - res[line.id] = line.voucher_id.amount# - else: - res[line.id] = 0.0 - return res - - def _check_amount(self, cr, uid, ids, context=None): - for obj in self.browse(cr, uid, ids, context=context): - if obj.voucher_id: - diff = abs(obj.amount) - abs(obj.voucher_id.amount) - if not self.pool.get('res.currency').is_zero(cr, uid, obj.statement_id.currency, diff): - return False - return True - - _constraints = [ - (_check_amount, 'The amount of the voucher must be the same amount as the one on the statement line.', ['amount']), - ] - - _columns = { - 'amount_reconciled': fields.function(_amount_reconciled, - string='Amount reconciled', type='float'), - 'voucher_id': fields.many2one('account.voucher', 'Reconciliation'), - } - - def unlink(self, cr, uid, ids, context=None): - voucher_obj = self.pool.get('account.voucher') - statement_line = self.browse(cr, uid, ids, context=context) - unlink_ids = [] - for st_line in statement_line: - if st_line.voucher_id: - unlink_ids.append(st_line.voucher_id.id) - voucher_obj.unlink(cr, uid, unlink_ids, context=context) - return super(account_bank_statement_line, self).unlink(cr, uid, ids, context=context) - - def resolve_o2m_operations(cr, uid, target_osv, operations, fields, context): results = [] for operation in operations: diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml index a5885156442..a6f3a6cd277 100644 --- a/addons/account_voucher/account_voucher_view.xml +++ b/addons/account_voucher/account_voucher_view.xml @@ -193,59 +193,7 @@ {'state':'posted'} - - - account.bank.statement.invoice.form.inherit - account.bank.statement - - - -