})
if f.get('relation',False):
obj_name = f['relation']
- self._relations[-1]['relation'] = f['relation']
+ result[-1]['relation'] = f['relation']
+ self._relations = result
+
+class sparse(function):
+
+ def convert_value(self, obj, cr, uid, record, value, read_value, context=None):
+ """
+ + For a many2many field, a list of tuples is expected.
+ Here is the list of tuple that are accepted, with the corresponding semantics ::
+
+ (0, 0, { values }) link to a new record that needs to be created with the given values dictionary
+ (1, ID, { values }) update the linked record with id = ID (write *values* on it)
+ (2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well)
+ (3, ID) cut the link to the linked record with id = ID (delete the relationship between the two objects but does not delete the target object itself)
+ (4, ID) link to existing record with id = ID (adds a relationship)
+ (5) unlink all (like using (3,ID) for all linked records)
+ (6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,ID) for each ID in the list of IDs)
+
+ Example:
+ [(6, 0, [8, 5, 6, 4])] sets the many2many to ids [8, 5, 6, 4]
+
+ + For a one2many field, a lits of tuples is expected.
+ Here is the list of tuple that are accepted, with the corresponding semantics ::
+
+ (0, 0, { values }) link to a new record that needs to be created with the given values dictionary
+ (1, ID, { values }) update the linked record with id = ID (write *values* on it)
+ (2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well)
+
+ Example:
+ [(0, 0, {'field_name':field_value_record1, ...}), (0, 0, {'field_name':field_value_record2, ...})]
+ """
+
+ if self._type == 'many2many':
+ assert value[0][0] == 6, 'Unsupported m2m value for sparse field: %s' % value
+ return value[0][2]
+
+ elif self._type == 'one2many':
+ if not read_value:
+ read_value = []
+ relation_obj = obj.pool.get(self.relation)
+ for vals in value:
+ assert vals[0] in (0,1,2), 'Unsupported o2m value for sparse field: %s' % vals
+ if vals[0] == 0:
+ read_value.append(relation_obj.create(cr, uid, vals[2], context=context))
+ elif vals[0] == 1:
+ relation_obj.write(cr, uid, vals[1], vals[2], context=context)
+ elif vals[0] == 2:
+ relation_obj.unlink(cr, uid, vals[1], context=context)
+ read_value.remove(vals[1])
+ return read_value
+ return value
+
+
+ def _fnct_write(self,obj,cr, uid, ids, field_name, value, args, context=None):
+ if not type(ids) == list:
+ ids = [ids]
+ records = obj.browse(cr, uid, ids, context=context)
+ for record in records:
+ # grab serialized value as object - already deserialized
+ serialized = getattr(record, self.serialization_field)
+ if value is None:
+ # simply delete the key to unset it.
+ serialized.pop(field_name, None)
+ else:
+ serialized[field_name] = self.convert_value(obj, cr, uid, record, value, serialized.get(field_name), context=context)
+ obj.write(cr, uid, ids, {self.serialization_field: serialized}, context=context)
+ return True
+
+ def _fnct_read(self, obj, cr, uid, ids, field_names, args, context=None):
+ results = {}
+ records = obj.browse(cr, uid, ids, context=context)
+ for record in records:
+ # grab serialized value as object - already deserialized
+ serialized = getattr(record, self.serialization_field)
+ results[record.id] = {}
+ for field_name in field_names:
+ if obj._columns[field_name]._type in ['one2many']:
+ value = serialized.get(field_name, [])
+ else:
+ results[record.id].update(field_name=value)
+ return results
+
+ def __init__(self, serialization_field, **kwargs):
+ self.serialization_field = serialization_field
+ return super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', method=True, **kwargs)
+
+
+
+
+
# ---------------------------------------------------------
# Dummy fields
# ---------------------------------------------------------
++#!/usr/bin/env python
++# -*- coding: utf-8 -*-
++##############################################################################
++#
++# OpenERP, Open Source Management Solution
++# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU Affero General Public License as
++# published by the Free Software Foundation, either version 3 of the
++# License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU Affero General Public License for more details.
++#
++# You should have received a copy of the GNU Affero General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++##############################################################################
--import os
--import re
--import sys
--from setuptools import setup, find_packages
++import glob, os, re, setuptools, sys
++from os.path import join, isfile
--execfile('addons/web/common/release.py')
++# List all data files
++def data():
++ files = []
++ for root, dirnames, filenames in os.walk('openerp'):
++ for filename in filenames:
++ if not re.match(r'.*(\.pyc|\.pyo|\~)$',filename):
++ files.append(os.path.join(root, filename))
++ d = {}
++ for v in files:
++ k=os.path.dirname(v)
++ if k in d:
++ d[k].append(v)
++ else:
++ d[k]=[v]
++ r = d.items()
++ if os.name == 'nt':
++ r.append(("Microsoft.VC90.CRT", glob.glob('C:\Microsoft.VC90.CRT\*.*')))
++ return r
--version_dash_incompatible = False
--if 'bdist_rpm' in sys.argv:
-- version_dash_incompatible = True
--try:
-- import py2exe
-- from py2exe_utils import opts
-- version_dash_incompatible = True
--except ImportError:
-- opts = {}
--if version_dash_incompatible:
-- version = version.split('-')[0]
++def gen_manifest():
++ file_list="\n".join(data())
++ open('MANIFEST','w').write(file_list)
--FILE_PATTERNS = \
-- r'.+\.(py|cfg|po|pot|mo|txt|rst|gif|png|jpg|ico|mako|html|js|css|htc|swf)$'
--def find_data_files(source, patterns=FILE_PATTERNS):
-- file_matcher = re.compile(patterns, re.I)
-- out = []
-- for base, _, files in os.walk(source):
-- cur_files = []
-- for f in files:
-- if file_matcher.match(f):
-- cur_files.append(os.path.join(base, f))
-- if cur_files:
-- out.append(
-- (base, cur_files))
++if os.name == 'nt':
++ sys.path.append("C:\Microsoft.VC90.CRT")
-- return out
++def py2exe_options():
++ if os.name == 'nt':
++ import py2exe
++ return {
++ "console" : [ { "script": "openerp-server", "icon_resources": [(1, join("install","openerp-icon.ico"))], }],
++ 'options' : {
++ "py2exe": {
++ "skip_archive": 1,
++ "optimize": 2,
++ "dist_dir": 'dist',
++ "packages": [ "DAV", "HTMLParser", "PIL", "asynchat", "asyncore", "commands", "dateutil", "decimal", "email", "encodings", "imaplib", "lxml", "lxml._elementpath", "lxml.builder", "lxml.etree", "lxml.objectify", "mako", "openerp", "poplib", "pychart", "pydot", "pyparsing", "reportlab", "select", "simplejson", "smtplib", "uuid", "vatnumber", "vobject", "xml", "xml.dom", "yaml", ],
++ "excludes" : ["Tkconstants","Tkinter","tcl"],
++ }
++ }
++ }
++ else:
++ return {}
--setup(
-- name=name,
-- version=version,
-- description=description,
-- long_description=long_description,
-- author=author,
-- author_email=author_email,
-- url=url,
-- download_url=download_url,
-- license=license,
-- install_requires=[
-- "Babel >= 0.9.6",
-- "simplejson >= 2.0.9",
- "python-dateutil >= 1.4.1",
- "pytz",
- "werkzeug == 0.7",
- ],
- tests_require=[
- 'unittest2',
- 'mock',
- ],
- test_suite = 'unittest2.collector',
- zip_safe=False,
- packages=find_packages(),
- classifiers=[
- 'Development Status :: 6 - Production/Stable',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Environment :: Web Environment',
- 'Topic :: Office/Business :: Financial',
- ],
- scripts=['openerp-web'],
- data_files=(find_data_files('addons')
- + opts.pop('data_files', [])
- ),
- **opts
- "python-dateutil >= 1.4.1, < 2",
- "pytz",
- "werkzeug == 0.7",
- ],
- tests_require=[
- 'unittest2',
- 'mock',
- ],
- test_suite = 'unittest2.collector',
- zip_safe=False,
- packages=find_packages(),
- classifiers=[
- 'Development Status :: 6 - Production/Stable',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Environment :: Web Environment',
- 'Topic :: Office/Business :: Financial',
- ],
- scripts=['openerp-web'],
- data_files=(find_data_files('addons')
- + opts.pop('data_files', [])
- ),
- **opts
++execfile(join(os.path.dirname(__file__), 'openerp', 'release.py'))
++
++setuptools.setup(
++ name = 'openerp',
++ version = version,
++ description = description,
++ long_description = long_desc,
++ url = url,
++ author = author,
++ author_email = author_email,
++ classifiers = filter(None, classifiers.split("\n")),
++ license = license,
++ scripts = ['openerp-server'],
++ data_files = data(),
++ packages = setuptools.find_packages(),
++ #include_package_data = True,
++ install_requires = [
++ # TODO the pychart package we include in openerp corresponds to PyChart 1.37.
++ # It seems there is a single difference, which is a spurious print in generate_docs.py.
++ # It is probably safe to move to PyChart 1.39 (the latest one).
++ # (Let setup.py choose the latest one, and we should check we can remove pychart from
++ # our tree.) http://download.gna.org/pychart/
++ # TODO 'pychart',
++ 'babel',
++ 'feedparser',
++ 'gdata',
++ 'lxml',
++ 'mako',
++ 'psycopg2',
++ 'pydot',
++ 'python-dateutil < 2',
++ 'python-ldap',
++ 'python-openid',
++ 'pytz',
++ 'pywebdav',
++ 'pyyaml',
++ 'reportlab',
++ 'simplejson',
++ 'vatnumber',
++ 'vobject',
++ 'werkzeug',
++ 'zsi',
++ ],
++ extras_require = {
++ 'SSL' : ['pyopenssl'],
++ },
++ **py2exe_options()
)
++
++
++# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: