New trunk

bzr revid: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
This commit is contained in:
pinky 2006-12-07 13:41:40 +00:00
commit 004a0b996f
444 changed files with 136485 additions and 0 deletions

3
MANIFEST.in Normal file
View File

@ -0,0 +1,3 @@
recursive-include doc *
recursive-include man *
recursive-include bin *xml *xsl *sql

18
bin/PKG-INFO Normal file
View File

@ -0,0 +1,18 @@
Metadata-Version: 1.1
Name: Tiny ERP
Version: 3.2.0
Author: Tiny.be
Author-email: fp at tiny be
Maintainer: Tiny.be
Maintainer-email: fp at tiny be
Home-page: http://tiny.be
Download-url: http://tinyerp.org/download.php
Summary: TinyERP is an Enterprise Resource Management written entirely in python.
License: GPL
Description: Tiny ERP is a complete ERP and CRM. The main features are accounting (analytic
and financial), stock management, sales and purchases management, tasks
automation, marketing campaigns, help desk, POS, etc. Technical features include
a distributed server, flexible workflows, an object database, a dynamic GUI,
customizable reports, and SOAP and XML-RPC interfaces.
Keywords: ERP, Accounting, Stock, CRM, Enterprise, Logistics, Management, Sales, Purchases
Platform: Linux, Win32

0
bin/__init__.py Normal file
View File

249
bin/addons/__init__.py Normal file
View File

@ -0,0 +1,249 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be)
#
# $Id: __init__.py 1308 2005-09-08 18:02:01Z pinky $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contact a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os, sys, imp
import itertools
from sets import Set
import osv
import tools
import pooler
import netsvc
from osv import fields
logger = netsvc.Logger()
opj = os.path.join
ad = tools.config['addons_path']
sys.path.insert(1,ad)
class Graph(dict):
def addNode(self, name, deps):
max_depth, father = 0, None
for n in [Node(x, self) for x in deps]:
if n.depth >= max_depth:
father = n
max_depth = n.depth
if father:
father.addChild(name)
else:
Node(name, self)
def __iter__(self):
level = 0
done = Set(self.keys())
while done:
level_modules = [(name, module) for name, module in self.items() if module.depth==level]
for name, module in level_modules:
done.remove(name)
yield module
level += 1
class Singleton(object):
def __new__(cls, name, graph):
if name in graph:
inst = graph[name]
else:
inst = object.__new__(cls)
inst.name = name
graph[name] = inst
return inst
class Node(Singleton):
def __init__(self, name, graph):
self.graph = graph
if not hasattr(self, 'childs'):
self.childs = []
if not hasattr(self, 'depth'):
self.depth = 0
def addChild(self, name):
node = Node(name, self.graph)
node.depth = self.depth + 1
if node not in self.childs:
self.childs.append(node)
for attr in ('init', 'update', 'demo'):
if hasattr(self, attr):
setattr(node, attr, True)
self.childs.sort(lambda x,y: cmp(x.name, y.name))
def hasChild(self, name):
return Node(name, self.graph) in self.childs or \
bool([c for c in self.childs if c.hasChild(name)])
def __setattr__(self, name, value):
super(Singleton, self).__setattr__(name, value)
if name in ('init', 'update', 'demo'):
tools.config[name][self.name] = 1
for child in self.childs:
setattr(child, name, value)
if name == 'depth':
for child in self.childs:
setattr(child, name, value + 1)
def __iter__(self):
return itertools.chain(iter(self.childs), *map(iter, self.childs))
def __str__(self):
return self._pprint()
def _pprint(self, depth=0):
s = '%s\n' % self.name
for c in self.childs:
s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1))
return s
def create_graph(module_list, force=[]):
graph = Graph()
packages = []
for module in module_list:
terp_file = opj(ad, module, '__terp__.py')
if os.path.isfile(terp_file):
info = eval(file(terp_file).read())
if info.get('installable', True):
packages.append((module, info.get('depends', []), info))
current,later = Set([p for p, dep, data in packages]), Set()
while packages and current > later:
package, deps, datas = packages[0]
# if all dependencies of 'package' are already in the graph, add 'package' in the graph
if reduce(lambda x,y: x and y in graph, deps, True):
later.clear()
current.remove(package)
graph.addNode(package, deps)
node = Node(package, graph)
node.datas = datas
for kind in ('init', 'demo', 'update'):
if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force:
setattr(node, kind, True)
else:
later.add(package)
packages.append((package, deps, datas))
packages = packages[1:]
for package in later:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependency' % package)
return graph
def init_module_objects(cr, module_name, obj_list):
pool = pooler.get_pool(cr.dbname)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:creating or updating database tables' % module_name)
for obj in obj_list:
#CHECKME: is this test useful? all objects are supposed to have an _auto_init method, right?
#if hasattr(obj, '_auto_init'):
if hasattr(obj, 'init'):
obj.init(cr)
obj._auto_init(cr)
cr.commit()
def load_module_graph(cr, graph, status={}):
package_todo = []
statusi = 0
for package in graph:
status['progress'] = (float(statusi)+0.1)/len(graph)
m = package.name
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m)
sys.stdout.flush()
pool = pooler.get_pool(cr.dbname)
modules = pool.instanciate(m)
cr.execute('select state, demo from ir_module_module where name=%s', (m,))
(package_state, package_demo) = (cr.rowcount and cr.fetchone()) or ('uninstalled', False)
idref = {}
status['progress'] = (float(statusi)+0.4)/len(graph)
if hasattr(package, 'init') or hasattr(package, 'update') or package_state in ('to install', 'to upgrade'):
init_module_objects(cr, m, modules)
for kind in ('init', 'update'):
for filename in package.datas.get('%s_xml' % kind, []):
mode = 'update'
if hasattr(package, 'init') or package_state=='to install':
mode = 'init'
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, filename))
name, ext = os.path.splitext(filename)
if ext == '.csv':
tools.convert_csv_import(cr, m, filename, tools.file_open(opj(m, filename)).read(), idref, mode=mode)
elif ext == '.sql':
queries = tools.file_open(opj(m, filename)).read().split(';')
for query in queries:
new_query = ' '.join(query.split())
if new_query:
cr.execute(new_query)
cr.commit()
else:
tools.convert_xml_import(cr, m, tools.file_open(opj(m, filename)).read(), idref, mode=mode)
if hasattr(package, 'demo') or (package_demo and package_state != 'installed'):
status['progress'] = (float(statusi)+0.75)/len(graph)
for xml in package.datas.get('demo_xml', []):
name, ext = os.path.splitext(xml)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, xml))
if ext == '.csv':
tools.convert_csv_import(cr, m, os.path.basename(xml), tools.file_open(opj(m, xml)).read(), idref)
else:
tools.convert_xml_import(cr, m, tools.file_open(opj(m, xml)).read(), idref)
package_todo.append(package.name)
cr.execute("update ir_module_module set state='installed', demo=%s where state in ('to upgrade', 'to install') and name=%s", (str(hasattr(package, 'demo')) or package_demo, package.name))
cr.commit()
statusi+=1
cr.commit()
# pool = osv.osv.FakePool('base')
# pool = pooler.get_pool(cr.dbname)
# pool.get('ir.model.data')._process_end(cr, 1, package_todo)
# cr.commit()
def register_classes():
module_list = os.listdir(ad)
for package in create_graph(module_list):
m = package.name
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m)
sys.stdout.flush()
imp.load_module(m, *imp.find_module(m))
def load_modules(db, force_demo=False, status={}, update_module=False):
force = []
if force_demo:
force.append('demo')
cr = db.cursor()
if update_module:
cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade')")
else:
cr.execute("select name from ir_module_module where state = 'installed'")
module_list = [name for (name,) in cr.fetchall()]
graph = create_graph(module_list, force)
load_module_graph(cr, graph, status)
cr.commit()
cr.close()

View File

@ -0,0 +1,32 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import ir
import module
import res

View File

@ -0,0 +1,36 @@
{
"name" : "Base",
"version" : "1.0",
"author" : "Tiny",
"website" : "http://tinyerp.com",
"category" : "Generic Modules/Base",
"description": "The kernel of Tiny ERP, needed for all installation.",
"depends" : [],
"init_xml" : [
"base_data.xml",
"base_menu.xml"
],
"demo_xml" : [
"base_demo.xml",
"res/partner/partner_demo.xml",
"res/partner/crm_demo.xml",
],
"update_xml" : [
"base_update.xml",
"ir/ir.xml",
"ir/workflow/workflow_view.xml",
"module/module_data.xml",
"module/module_wizard.xml",
"module/module_view.xml",
"module/module_report.xml",
"res/res_request_view.xml",
"res/partner/partner_report.xml",
"res/partner/partner_view.xml",
"res/partner/partner_wizard.xml",
"res/res_currency_view.xml",
"res/partner/crm_view.xml",
"res/partner/partner_data.xml",
"res/ir_property_view.xml",
],
"installable": True
}

335
bin/addons/base/base.sql Normal file
View File

@ -0,0 +1,335 @@
-------------------------------------------------------------------------
-- Pure SQL
-------------------------------------------------------------------------
CREATE TABLE perm (
id serial NOT NULL,
level smallint DEFAULT 4 NOT NULL,
uid int default null,
gid int default null,
primary key(id)
);
insert into perm (id,uid,gid) values (1,1,1);
CREATE TABLE inherit (
obj_type varchar(128) not null,
obj_id int not null,
inst_type varchar(128) not null,
inst_id int not null
);
-------------------------------------------------------------------------
-- IR dictionary
-------------------------------------------------------------------------
create table ir_values
(
id serial,
perm_id int references perm on delete set null,
name varchar(128) not null,
key varchar(128) not null,
key2 varchar(128) not null,
model varchar(128) not null,
value text,
meta text default NULL,
res_id integer default null,
primary key (id)
);
-------------------------------------------------------------------------
-- Modules Description
-------------------------------------------------------------------------
CREATE TABLE ir_model (
id serial,
model varchar(64) DEFAULT ''::varchar NOT NULL,
name varchar(64),
info text,
primary key(id)
);
CREATE TABLE ir_model_fields (
id serial,
model varchar(64) DEFAULT ''::varchar NOT NULL,
model_id int references ir_model,
name varchar(64) DEFAULT ''::varchar NOT NULL,
relation varchar(64),
field_description varchar(256),
ttype varchar(64),
group_name varchar(64),
view_load boolean,
relate boolean default False,
primary key(id)
);
-------------------------------------------------------------------------
-- Actions
-------------------------------------------------------------------------
CREATE TABLE ir_actions (
id serial NOT NULL,
perm_id int references perm on delete set null,
name varchar(64) DEFAULT ''::varchar NOT NULL,
"type" varchar(64) DEFAULT 'window'::varchar NOT NULL,
usage varchar(32) DEFAULT null,
primary key(id)
);
CREATE TABLE ir_act_window (
view_id integer,
res_model varchar(64),
view_type varchar(16),
"domain" varchar(127),
primary key(id)
)
INHERITS (ir_actions);
CREATE TABLE ir_act_report_xml (
model varchar(64) NOT NULL,
report_name varchar(64) NOT NULL,
report_xsl varchar(64),
report_xml varchar(64),
auto boolean default true
)
INHERITS (ir_actions);
create table ir_act_report_custom (
report_id int
-- report_id int references ir_report_custom
)
INHERITS (ir_actions);
CREATE TABLE ir_act_group (
exec_type varchar(64) DEFAULT 'serial'::varchar NOT NULL
)
INHERITS (ir_actions);
CREATE TABLE ir_act_group_link (
aid integer NOT NULL,
gid integer NOT NULL
);
CREATE TABLE ir_act_execute (
func_name varchar(64) NOT NULL,
func_arg varchar(64)
)
INHERITS (ir_actions);
CREATE TABLE ir_act_wizard (
wiz_name varchar(64) NOT NULL
)
INHERITS (ir_actions);
CREATE TABLE ir_ui_view (
id serial NOT NULL,
perm_id int references perm on delete set null,
name varchar(64) DEFAULT ''::varchar NOT NULL,
model varchar(64) DEFAULT ''::varchar NOT NULL,
"type" varchar(64) DEFAULT 'form'::varchar NOT NULL,
arch text NOT NULL,
field_parent varchar(64),
priority integer DEFAULT 5 NOT NULL,
primary key(id),
CONSTRAINT ir_ui_view_type CHECK (((("type")::text = ('form'::varchar)::text) OR (("type")::text = ('tree'::varchar)::text)))
);
CREATE TABLE ir_ui_menu (
id serial NOT NULL,
perm_id int references perm on delete set null,
parent_id int references ir_ui_menu on delete set null,
name varchar(64) DEFAULT ''::varchar NOT NULL,
icon varchar(64) DEFAULT ''::varchar,
primary key (id)
);
select setval('ir_ui_menu_id_seq', 2);
---------------------------------
-- Res users
---------------------------------
-- level:
-- 0 RESTRICT TO USER
-- 1 RESTRICT TO GROUP
-- 2 PUBLIC
CREATE TABLE res_users (
id serial NOT NULL,
perm_id int references perm on delete set null,
name varchar(64) not null,
active boolean default True,
login varchar(64) NOT NULL UNIQUE,
password varchar(32) default null,
perm_default int references perm on delete set null,
-- action_id int references ir_act_window on delete set null,
action_id int,
primary key(id)
);
alter table res_users add constraint res_users_login_uniq unique (login);
insert into res_users (id,login,password,name,action_id,perm_id,active) values (1,'root',NULL,'Administrator',NULL,1,False);
select setval('res_users_id_seq', 2);
CREATE TABLE res_groups (
id serial NOT NULL,
perm_id int references perm on delete set null,
name varchar(32) NOT NULL,
primary key(id)
);
create table res_roles (
id serial NOT NULL,
perm_id int references perm on delete set null,
parent_id int references res_roles on delete set null,
name varchar(32) NOT NULL,
primary key(id)
);
CREATE TABLE res_roles_users_rel (
uid integer NOT NULL references res_users on delete cascade,
rid integer NOT NULL references res_roles on delete cascade
);
CREATE TABLE res_groups_users_rel (
uid integer NOT NULL references res_users on delete cascade,
gid integer NOT NULL references res_groups on delete cascade
);
---------------------------------
-- Workflows
---------------------------------
create table wkf
(
id serial,
perm_id int references perm on delete set null,
name varchar(64),
osv varchar(64),
on_create bool default False,
primary key(id)
);
create table wkf_activity
(
id serial,
perm_id int references perm on delete set null,
wkf_id int references wkf on delete cascade,
subflow_id int references wkf on delete set null,
split_mode varchar(3) default 'XOR',
join_mode varchar(3) default 'XOR',
kind varchar(16) not null default 'dummy',
name varchar(64),
signal_send varchar(32) default null,
flow_start boolean default False,
flow_stop boolean default False,
action varchar(64) default null,
primary key(id)
);
create table wkf_transition
(
id serial,
perm_id int references perm on delete set null,
act_from int references wkf_activity on delete cascade,
act_to int references wkf_activity on delete cascade,
condition varchar(128) default NULL,
trigger_type varchar(128) default NULL,
trigger_expr_id varchar(128) default NULL,
signal varchar(64) default null,
role_id int references res_roles on delete set null,
primary key(id)
);
create table wkf_instance
(
id serial,
wkf_id int references wkf on delete set null,
uid int default null,
res_id int not null,
res_type varchar(64) not null,
state varchar(32) not null default 'active',
primary key(id)
);
create table wkf_workitem
(
id serial,
act_id int not null references wkf_activity on delete cascade,
inst_id int not null references wkf_instance on delete cascade,
subflow_id int references wkf_instance on delete cascade,
state varchar(64) default 'blocked',
primary key(id)
);
create table wkf_witm_trans
(
trans_id int not null references wkf_transition on delete cascade,
inst_id int not null references wkf_instance on delete cascade
);
create table wkf_logs
(
id serial,
res_type varchar(128) not null,
res_id int not null,
uid int references res_users on delete set null,
act_id int references wkf_activity on delete set null,
time time not null,
info varchar(128) default NULL,
primary key(id)
);
---------------------------------
-- Modules
---------------------------------
CREATE TABLE ir_module_category (
id serial NOT NULL,
perm_id integer,
create_uid integer references res_users on delete set null,
create_date timestamp without time zone,
write_date timestamp without time zone,
write_uid integer references res_users on delete set null,
parent_id integer REFERENCES ir_module_category ON DELETE SET NULL,
name character varying(128) NOT NULL,
primary key(id)
);
CREATE TABLE ir_module_module (
id serial NOT NULL,
perm_id integer,
create_uid integer references res_users on delete set null,
create_date timestamp without time zone,
write_date timestamp without time zone,
write_uid integer references res_users on delete set null,
website character varying(256),
name character varying(128) NOT NULL,
author character varying(128),
url character varying(128),
state character varying(16),
latest_version character varying(64),
shortdesc character varying(256),
category_id integer REFERENCES ir_module_category ON DELETE SET NULL,
description text,
demo boolean default False,
primary key(id)
);
CREATE TABLE ir_module_module_dependency (
id serial NOT NULL,
perm_id integer,
create_uid integer references res_users on delete set null,
create_date timestamp without time zone,
write_date timestamp without time zone,
write_uid integer references res_users on delete set null,
name character varying(128),
version_pattern character varying(128) default NULL,
module_id integer REFERENCES ir_module_module ON DELETE cascade,
primary key(id)
);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,274 @@
<?xml version="1.0"?>
<terp>
<data noupdate="1">
<record model="res.users" id="user_demo">
<field name="login">demo</field>
<field name="password">demo</field>
<field name="name">Demo User</field>
<field name="signature">Fabien Pinckaers</field>
<field name="action_id" ref="action_menu_admin"/>
<field name="address_id" ref="main_address"/>
<field name="company_id" ref="main_company"/>
</record>
<record model="res.currency" id="USD">
<field name="name">USD</field>
<field name="rate">0.8400</field>
<field name="rounding">2</field>
<field name="accuracy">4</field>
</record>
<!-- USA States -->
<record model="res.country.state" id="us-al">
<field name="name">Alabama</field>
<field name="code">al</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ak">
<field name="name">Alaska</field>
<field name="code">ak</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-az">
<field name="name">Arizona</field>
<field name="code">az</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ar">
<field name="name">Arkansas</field>
<field name="code">ar</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ca">
<field name="name">California</field>
<field name="code">ca</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-co">
<field name="name">Colorado</field>
<field name="code">co</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ct">
<field name="name">Connecticut</field>
<field name="code">ct</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-de">
<field name="name">Delaware</field>
<field name="code">de</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-fl">
<field name="name">Florida</field>
<field name="code">fl</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ga">
<field name="name">Georgia</field>
<field name="code">ga</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-hi">
<field name="name">Hawaii</field>
<field name="code">hi</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-id">
<field name="name">Idaho</field>
<field name="code">id</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-il">
<field name="name">Illinois</field>
<field name="code">il</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-in">
<field name="name">Indiana</field>
<field name="code">in</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ia">
<field name="name">Iowa</field>
<field name="code">ia</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ks">
<field name="name">Kansas</field>
<field name="code">ks</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ky">
<field name="name">Kentuky</field>
<field name="code">ky</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-la">
<field name="name">Louisiana</field>
<field name="code">la</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-me">
<field name="name">Maine</field>
<field name="code">me</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-md">
<field name="name">Maryland</field>
<field name="code">md</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ma">
<field name="name">Massachusetts</field>
<field name="code">ma</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-mi">
<field name="name">Michigan</field>
<field name="code">mi</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-mn">
<field name="name">Minnesota</field>
<field name="code">mn</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ms">
<field name="name">Mississippi</field>
<field name="code">ms</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-mo">
<field name="name">Missouri</field>
<field name="code">mo</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-mt">
<field name="name">Montana</field>
<field name="code">mt</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ne">
<field name="name">Nebraska</field>
<field name="code">ne</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-nv">
<field name="name">Nevada</field>
<field name="code">nv</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-nh">
<field name="name">New Hampshire</field>
<field name="code">nh</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-nj">
<field name="name">New Jersey</field>
<field name="code">nj</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-nm">
<field name="name">New Mexico</field>
<field name="code">nm</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ny">
<field name="name">New York</field>
<field name="code">ny</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-nc">
<field name="name">North Carolina</field>
<field name="code">nc</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-nd">
<field name="name">New Dakota</field>
<field name="code">nd</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-oh">
<field name="name">Ohio</field>
<field name="code">oh</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ok">
<field name="name">Oklahoma</field>
<field name="code">ok</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-or">
<field name="name">Oregon</field>
<field name="code">or</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-pa">
<field name="name">Pennsylviania</field>
<field name="code">pa</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ri">
<field name="name">Rhode Island</field>
<field name="code">ri</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-sc">
<field name="name">South Carolina</field>
<field name="code">sc</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-sd">
<field name="name">South Dakota</field>
<field name="code">sd</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-tn">
<field name="name">Tennessee</field>
<field name="code">tn</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-tx">
<field name="name">Texas</field>
<field name="code">tx</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-ut">
<field name="name">Utah</field>
<field name="code">ut</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-vt">
<field name="name">Vermont</field>
<field name="code">vt</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-va">
<field name="name">Virgnia</field>
<field name="code">va</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-wa">
<field name="name">Washington</field>
<field name="code">wa</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-wv">
<field name="name">West Virgnia</field>
<field name="code">wv</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-wi">
<field name="name">Wisconsin</field>
<field name="code">wi</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
<record model="res.country.state" id="us-wy">
<field name="name">Wyoming</field>
<field name="code">wy</field>
<field name="country_id" model="res.country" ref="us"/>
</record>
</data>
</terp>

View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<terp>
<data>
<!-- <menuitem name="Tools" sequence="15" groups="admin" icon="terp-tools"/> -->
<menuitem name="Administration" sequence="20" groups="admin" icon="terp-administration"/>
# Admin config
<menuitem name="Administration/Configuration/Base" sequence="1"/>
<record model="ir.actions.act_window" id="open_module_tree_company">
<field name="name">res.company</field>
<field name="res_model">res.company</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Administration/Configuration/Base/Define Main Company" action="open_module_tree_company" sequence="2" id="menu_company_def"/>
</data>
</terp>

View File

@ -0,0 +1,169 @@
<?xml version="1.0"?>
<terp>
<data>
<!--
======================
Languages
======================
-->
<record model="ir.ui.view" id="view_lang">
<field name="name">Languages</field>
<field name="model">res.lang</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Language">
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="translatable"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_lang">
<field name="name">res.lang</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.lang</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Interface/Languages" action="action_lang"/>
<ir_set>
<field name="key" eval="'meta'"/>
<field name="key2" eval="'lang'"/>
<field name="models" eval="['res.users']"/>
<field name="name">lang</field>
<field name="value" eval="False"/>
<field name="meta" eval="{'type':'selection', 'string':'Language', 'selection':[(False,'en')]}"/>
<field name="replace" eval="True"/>
</ir_set>
<!--
======================
Groups
======================
-->
<record model="ir.ui.view" id="view_groups_form">
<field name="name">res.groups.form</field>
<field name="model">res.groups</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Groups">
<field name="name" colspan="3" select="1"/>
</form>
</field>
</record>
<!--
======================
Users
======================
-->
<record model="ir.ui.view" id="view_users_form_simple_modif">
<field name="name">res.users.form.modif</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="priority" eval="10"/>
<field name="arch" type="xml">
<form string="Users">
<field name="name" colspan="3" select="1"/>
<field name="login" readonly="1" select="1"/>
<field name="password"/>
<label string="Please note that you will have to logout and relog if you change your password." colspan="4"/>
<newline/>
<field name="signature" colspan="3"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_users_form_simple">
<field name="name">res.users.form</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<form string="Users">
<field name="name" readonly="1" colspan="3" select="1"/>
<field name="login" readonly="1" select="1"/>
<newline/>
<field name="signature" readonly="1" colspan="3"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_users_form">
<field name="name">res.users.form</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Users">
<field name="name" select="1"/>
<field name="active" select="1"/>
<field name="login" select="1"/>
<field name="password"/>
<field name="signature"/>
<field name="address_id"/>
<field name="company_id" required="1"/>
<field name="action_id" domain="[('usage','=','menu')]" required="True"/>
<newline/>
<field name="groups_id"/>
<field name="roles_id"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_users_tree">
<field name="name">res.users.tree</field>
<field name="model">res.users</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Users">
<field name="name"/>
<field name="login"/>
</tree>
</field>
</record>
<!--
======================
Company
======================
-->
<record model="ir.ui.view" id="view_company_form">
<field name="name">res.company.form</field>
<field name="model">res.company</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Company">
<field name="name" colspan="3" select="1"/>
<field name="partner_id" select="1"/>
<field name="parent_id" select="1"/>
<field name="rml_header1"/>
<field name="rml_footer1"/>
<field name="rml_footer2"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_company_tree">
<field name="name">res.company.tree</field>
<field name="model">res.company</field>
<field name="type">tree</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Companies">
<field name="name"/>
<field name="partner_id"/>
</tree>
</field>
</record>
# Admin config
<menuitem name="Administration/Configuration/User" sequence="4"/>
<record model="ir.actions.act_window" id="open_module_users_list">
<field name="name">res.users.list</field>
<field name="res_model">res.users</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="base.view_users_tree"/>
</record>
<menuitem name="Administration/Configuration/User/Define Users" action="open_module_users_list" sequence="1" id="menu_users_list"/>
</data>
</terp>

View File

@ -0,0 +1,41 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import ir_sequence
import ir_ui_menu
import ir_ui_view
import ir_actions
import ir_default
import ir_model
import ir_report_custom
import ir_attachment
import ir_cron
import ir_values
import ir_translation
import ir_exports
import workflow

654
bin/addons/base/ir/ir.xml Normal file
View File

@ -0,0 +1,654 @@
<?xml version="1.0"?>
<terp>
<data>
==========================================================
Sequences
==========================================================
<record model="ir.ui.view" id="sequence_view">
<field name="name">ir.sequence.form</field>
<field name="model">ir.sequence</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Sequences">
<separator string="Configuration" colspan="4"/>
<field name="name" colspan="3" select="1"/>
<field name="code" select="1"/>
<field name="active" select="1"/>
<field name="prefix"/>
<field name="suffix"/>
<field name="padding" />
<field name="number_increment"/>
<field name="number_next"/>
<separator string="Legend (for prefix, suffix)" colspan="4"/>
<label string="Year: %%(year)s" colspan="4"/>
<label string="Month: %%(month)s" colspan="4"/>
<label string="Day: %%(day)s" colspan="4"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="ir_sequence_form">
<field name="name">ir.sequence</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.sequence</field>
<field name="view_type">form</field>
<field name="view_id" ref="sequence_view"/>
</record>
<menuitem name="Administration/Custom/Sequences/Sequences" action="ir_sequence_form"/>
==========================================================
Sequences Types
==========================================================
<record model="ir.ui.view" id="sequence_type_form_view">
<field name="name">ir.sequence.type.form</field>
<field name="model">ir.sequence.type</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Sequence Type">
<field name="name" select="1"/>
<field name="code" readonly="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="ir_sequence_type">
<field name="name">ir.sequence.type</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.sequence.type</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" eval="False"/>
</record>
<menuitem name="Administration/Custom/Sequences/Sequence Types" action="ir_sequence_type"/>
==========================================================
Actions
==========================================================
<record model="ir.actions.act_window" id="ir_sequence_actions">
<field name="name">ir.actions.actions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.actions</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Actions" action="ir_sequence_actions"/>
<record model="ir.actions.act_window" id="ir_action_execute">
<field name="name">ir.actions.execute</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.execute</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Execute" action="ir_action_execute"/>
<record model="ir.actions.act_window" id="ir_action_group">
<field name="name">ir.actions.group</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.group</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Group" action="ir_action_group"/>
<record model="ir.actions.act_window" id="ir_action_report_custom">
<field name="name">ir.actions.report.custom</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.report.custom</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Report Custom" action="ir_action_report_custom"/>
<record model="ir.actions.act_window" id="ir_action_report_xml">
<field name="name">ir.actions.report.xml</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.report.xml</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Report Xml" action="ir_action_report_xml"/>
<record model="ir.ui.view" id="view_window_action_tree">
<field name="name">ir.actions.windows.tree</field>
<field name="model">ir.actions.act_window</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Window Action">
<field name="name"/>
<field name="res_model"/>
<field name="view_type"/>
<field name="view_id"/>
<field name="domain"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_window_action_form">
<field name="name">ir.actions.windows.form</field>
<field name="model">ir.actions.act_window</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Open a Window">
<field name="name" colspan="3" select="1"/>
<field name="type" readonly="1"/>
<field name="view_id"/>
<field name="res_model"/>
<field name="view_type"/>
<field name="domain" colspan="3"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="ir_action_window">
<field name="name">ir.actions.act_window</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_window_action_form"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Open Window" action="ir_action_window"/>
<record model="ir.actions.act_window" id="ir_action_wizard">
<field name="name">ir.actions.wizard</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.wizard</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Wizard" action="ir_action_wizard"/>
==========================================================
Companies
==========================================================
<record model="ir.actions.act_window" id="action_res_company_tree">
<field name="name">res.company</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.company</field>
<field name="domain">[('parent_id','=',False)]</field>
<field name="view_type">tree</field>
</record>
<menuitem name="Administration/Users/Company Structure" action="action_res_company_tree"/>
<record model="ir.actions.act_window" id="action_res_company_form">
<field name="name">res.groups</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.company</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Users/Company Structure/Define Companies" action="action_res_company_form"/>
==========================================================
User Roles
==========================================================
<record model="ir.actions.act_window" id="action_res_users">
<field name="name">res.users</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.users</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_users_form"/>
</record>
<menuitem name="Administration/Users/Users" action="action_res_users"/>
<record model="ir.actions.act_window" id="action_res_users_my">
<field name="name">res.users</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.users</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('id','=',uid)]</field>
<field name="view_id" ref="view_users_form_simple_modif"/>
</record>
<menuitem name="Administration/Users/Users/My password" action="action_res_users_my"/>
<record model="ir.actions.act_window" id="action_res_groups">
<field name="name">res.groups</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.groups</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Users/Groups" action="action_res_groups"/>
<record model="ir.ui.view" id="view_roles_form">
<field name="name">res.roles.form</field>
<field name="model">res.roles</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Role">
<field name="name" colspan="3" select="1"/>
<field name="parent_id" colspan="3"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_roles_tree">
<field name="name">res.roles.tree</field>
<field name="model">res.roles</field>
<field name="type">tree</field>
<field name="field_parent">child_id</field>
<field name="arch" type="xml">
<tree string="Roles">
<field name="name"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_res_roles">
<field name="name">res.roles.tree</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.roles</field>
<field name="view_type">tree</field>
<field name="domain" eval="[('parent_id','=',False)]"/>
</record>
<menuitem name="Administration/Users/Roles structure" action="action_res_roles"/>
<record model="ir.actions.act_window" id="action_res_roles_form">
<field name="name">res.roles.tree</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.roles</field>
<field name="view_type">form</field>
</record>
<menuitem name="Administration/Users/Roles structure/Define Roles" action="action_res_roles_form"/>
==========================================================
View
==========================================================
<record model="ir.ui.view" id="view_view_form">
<field name="name">ir.ui.view</field>
<field name="model">ir.ui.view</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="User Interface - Views">
<field name="name" select="1"/>
<field name="type"/>
<field name="model" select="1"/>
<field name="field_parent"/>
<field name="priority"/>
<field name="inherit_id"/>
<field name="arch" colspan="3" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_ui_view">
<field name="name">ir.ui.view</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.ui.view</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_view_form"/>
</record>
<menuitem name="Administration/Custom/Interface/View" action="action_ui_view"/>
==========================================================
Attachment
==========================================================
<record model="ir.ui.view" id="view_attachment_form">
<field name="name">ir.attachment.view</field>
<field name="model">ir.attachment</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Attachments">
<field name="name" colspan="3" select="1"/>
<field name="description" colspan="3"/>
<field name="datas" colspan="3"/>
<field name="datas_fname"/>
<newline/>
<field name="res_model" select="1"/>
<field name="res_id"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_attachment">
<field name="name">ir.attachment</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.attachment</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_attachment_form"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Attachments" action="action_attachment"/>
==========================================================
Report
==========================================================
<record model="ir.ui.view" id="view_report_custom_fields_tree">
<field name="name">ir.report.custom.fields.tree</field>
<field name="model">ir.report.custom.fields</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Report Fields">
<field name="sequence"/>
<field name="name"/>
<field name="width"/>
<field name="field_child0"/>
<field name="field_child1"/>
<field name="field_child2"/>
<field name="field_child3"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_report_custom_fields_form">
<field name="name">ir.report.custom.fields</field>
<field name="model">ir.report.custom.fields</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Report Fields">
<field name="name"/>
<field name="alignment"/>
<field name="width"/>
<field name="sequence"/>
<newline/>
<field name="bgcolor"/>
<field name="fontcolor"/>
<newline/>
<field name="operation"/>
<field name="groupby"/>
<field name="cumulate"/>
<newline/>
<field name="field_child0" domain="[('model_id','=',parent['model_id'])]" on_change="onchange_field_child0(field_child0)"/>
<field name="fc0_operande" domain="[('model_id','=',parent['model_id'])]"/>
<field name="fc0_op"/>
<field name="fc0_condition"/>
<newline/>
<field name="field_child1" on_change="onchange_field_child1(field_child1)"/>
<field name="fc1_operande"/>
<field name="fc1_op"/>
<field name="fc1_condition"/>
<newline/>
<field name="field_child2" on_change="onchange_field_child2(field_child2)"/>
<field name="fc2_operande"/>
<field name="fc2_op"/>
<field name="fc2_condition"/>
<newline/>
<field name="field_child3"/>
<field name="fc3_operande"/>
<field name="fc3_op"/>
<field name="fc3_condition"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_report_custom_form">
<field name="name">ir.report.custom</field>
<field name="model">ir.report.custom</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Custom Report">
<field name="name" select="1"/>
<field name="model_id" select="1" on_change="onchange_model_id(model_id)"/>
<field name="title"/>
<field name="type"/>
<field name="print_format"/>
<field name="print_orientation"/>
<field name="repeat_header"/>
<field name="footer"/>
<field name="sortby"/>
<field name="field_parent"/>
<field name="frequency"/>
<field name="limitt"/>
<field name="menu_id" />
<field name="fields_child0" widget="one2many_list" colspan="3"/>
<field name="state" readonly="1" select="1"/>
<group col="2" colspan="2">
<button name="subscribe" string="Subscribe Report" states="unsubscribed" type="object"/>
<button name="unsubscribe" string="Unsubscribe Report" states="subscribed" type="object"/>
</group>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_report_custom">
<field name="name">ir.report.custom</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.report.custom</field>
<field name="view_type">tree</field>
<field name="view_id" ref="view_report_custom_form"/>
</record>
<!--
<menuitem name="Administration/Report/Report Custom" action="action_report_custom"/>
-->
==========================================================
model
==========================================================
<record model="ir.ui.view" id="view_model_form">
<field name="name">ir.model.form</field>
<field name="model">ir.model</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Model Description">
<field name="name" select="1"/>
<field name="model" select="1"/>
<field name="info" select="1" colspan="3"/>
<separator string="Fields" colspan="4"/>
<field name="field_id" colspan="4" nolabel="1"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_model_tree">
<field name="name">ir.model.tree</field>
<field name="model">ir.model</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Model Description">
<field name="name"/>
<field name="model"/>
</tree>
</field>
</record>
==========================================================
fields_description
==========================================================
<record model="ir.ui.view" id="view_model_fields_form">
<field name="name">ir.model.fields.form</field>
<field name="model">ir.model.fields</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Fields Description">
<field name="name" select="1"/>
<field name="model_id"/>
<field name="field_description" select="1" colspan="4"/>
<field name="ttype" select="1"/>
<field name="relation" select="1"/>
<field name="relate" select="1"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="ir_model_fields_tree">
<field name="name">ir.model.fields.tree</field>
<field name="model">ir.model.fields</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Fields Description">
<field name="name" select="1"/>
<field name="field_description" select="1"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_model_model">
<field name="name">ir.model.form</field>
<field name="res_model">ir.model</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_model_form"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Database Structure/Objects" action="action_model_model" id="ir_model_model_menu"/>
<record model="ir.actions.act_window" id="action_model_fields">
<field name="name">ir.model.fields.form</field>
<field name="res_model">ir.model.fields</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_model_fields_form"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Database Structure/Fields" action="action_model_fields" id="ir_model_model_fields"/>
==========================================================
Translations
==========================================================
<record model="ir.ui.view" id="view_translation_form">
<field name="name">Translations</field>
<field name="model">ir.translation</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Translations">
<field name="name" select="1"/>
<field name="lang" select="1"/>
<field name="src" colspan="3" select="1"/>
<field name="type" select="1"/>
<field name="res_id" select="1"/>
<field name="value" colspan="3" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_translation">
<field name="name">ir.translation.view</field>
<field name="res_model">ir.translation</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_translation_form"/>
</record>
<menuitem name="Administration/Translations/All terms" action="action_translation"/>
<record model="ir.ui.view" id="view_translation_tree">
<field name="name">Translations</field>
<field name="model">ir.translation</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Translations">
<field name="name"/>
<field name="lang"/>
<field name="src"/>
<field name="type"/>
</tree>
</field>
</record>
<!--
=============================================================
Menu Edition
=============================================================
-->
<record model="ir.ui.view" id="edit_menu">
<field name="name">ir.ui.menu.tree</field>
<field name="model">ir.ui.menu</field>
<field name="type">tree</field>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<tree string="Menu">
<field name="complete_name" icon="icon"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="edit_menu_access">
<field name="name">ir.ui.menu.form2</field>
<field name="model">ir.ui.menu</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Menu">
<field name="complete_name"/>
<field name="name" select="1"/>
<field name="sequence"/>
<field name="parent_id" colspan="3" select="1"/>
<field name="groups_id" colspan="3"/>
<field name="icon"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="grant_menu_access">
<field name="name">ir.ui.menu.form2</field>
<field name="res_model">ir.ui.menu</field>
<field name="view_type">form</field>
<field name="view_id" ref="edit_menu_access"/>
</record>
<menuitem name="Administration/Security/Grant Access to menu"
action="grant_menu_access" />
<!--
=============================================================
Cron Jobs
=============================================================
-->
<record model="ir.ui.view" id="ir_cron_view_tree">
<field name="name">ir.cron.tree</field>
<field name="model">ir.cron</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Scheduled Actions">
<field name="nextcall"/>
<field name="name"/>
<field name="interval_number"/>
<field name="interval_type"/>
<field name="numbercall"/>
</tree>
</field>
</record> <record model="ir.ui.view" id="ir_cron_view">
<field name="name">ir.cron.form</field>
<field name="model">ir.cron</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Scheduled Actions">
<field name="name" select="1"/>
<field name="active" select="1"/>
<field name="user_id" select="1"/>
<field name="priority" select="1"/>
<newline/>
<field name="interval_number"/>
<field name="interval_type"/>
<newline/>
<field name="nextcall"/>
<field name="numbercall"/>
<field name="doall"/>
<separator string="Action to trigger" colspan="4"/>
<newline/>
<field name="model" readonly="1"/>
<field name="function" readonly="1"/>
<field name="args" colspan="3" readonly="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="ir_cron_act">
<field name="name">ir.cron.form</field>
<field name="res_model">ir.cron</field>
<field name="view_type">form</field>
<field name="view_id" ref="ir_cron_view"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Actions/Scheduled Actions"
action="ir_cron_act"/>
<record model="ir.ui.view" id="ir_access_view_tree">
<field name="name">ir.model.access.tree</field>
<field name="model">ir.model.access</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Access Controls">
<field name="name"/>
<field name="model_id"/>
<field name="group_id"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="ir_access_view_form">
<field name="name">ir.model.access.form</field>
<field name="model">ir.model.access</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Access Controls">
<field name="name" select="1" colspan="3"/>
<field name="model_id" select="1"/>
<field name="group_id" select="1"/>
<newline/>
<field name="perm_read"/>
<field name="perm_write"/>
<field name="perm_create"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="ir_access_act">
<field name="name">ir.model.access.form</field>
<field name="res_model">ir.model.access</field>
<field name="view_type">form</field>
<field name="view_id" ref="ir_access_view_form"/>
</record>
<menuitem name="Administration/Security/Access Controls" action="ir_access_act"/>
</data>
</terp>

View File

@ -0,0 +1,141 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
class actions(osv.osv):
_name = 'ir.actions.actions'
_table = 'ir_actions'
_columns = {
'name': fields.char('Action Name', required=True, size=64),
'type': fields.char('Action Type', required=True, size=32),
'usage': fields.char('Action Usage', size=32)
}
_defaults = {
'usage': lambda *a: False,
}
actions()
class act_execute(osv.osv):
_name = 'ir.actions.execute'
_table = 'ir_act_execute'
_sequence = 'ir_actions_id_seq'
_columns = {
'name': fields.char('name', size=64, required=True, translate=True),
'type': fields.char('type', size=32, required=True),
'func_name': fields.char('Function Name', size=64, required=True),
'func_arg': fields.char('Function Argument', size=64),
'usage': fields.char('Action Usage', size=32)
}
act_execute()
class group(osv.osv):
_name = 'ir.actions.group'
_table = 'ir_act_group'
_sequence = 'ir_actions_id_seq'
_columns = {
'name': fields.char('Group Name', size=64, required=True),
'type': fields.char('Action Type', size=32, required=True),
'exec_type': fields.char('Execution sequence', size=64, required=True),
'usage': fields.char('Action Usage', size=32)
}
group()
class report_custom(osv.osv):
_name = 'ir.actions.report.custom'
_table = 'ir_act_report_custom'
_sequence = 'ir_actions_id_seq'
_columns = {
'name': fields.char('Report Name', size=64, required=True, translate=True),
'type': fields.char('Report Type', size=32, required=True),
'model':fields.char('Model', size=64, required=True),
'report_id': fields.integer('Report Ref.', required=True),
'usage': fields.char('Action Usage', size=32)
}
report_custom()
class report_xml(osv.osv):
_name = 'ir.actions.report.xml'
_table = 'ir_act_report_xml'
_sequence = 'ir_actions_id_seq'
_columns = {
'name': fields.char('Name', size=64, required=True, translate=True),
'type': fields.char('Report Type', size=32, required=True),
'model': fields.char('Model', size=64, required=True),
'report_name': fields.char('Internal Name', size=64, required=True),
'report_xsl': fields.char('XSL path', size=256),
'report_xml': fields.char('XML path', size=256),
'report_rml': fields.char('RML path', size=256),
'auto': fields.boolean('Automatic XSL:RML', required=True),
'usage': fields.char('Action Usage', size=32)
}
_defaults = {
'type': lambda *a: 'ir.actions.report.xml',
'auto': lambda *a: True,
}
report_xml()
class act_window(osv.osv):
_name = 'ir.actions.act_window'
_table = 'ir_act_window'
_sequence = 'ir_actions_id_seq'
_columns = {
'name': fields.char('Action Name', size=64, required=True, translate=True),
'type': fields.char('Action Type', size=32, required=True),
'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'),
'domain': fields.char('Domain Value', size=250),
'context': fields.char('Context Value', size=250),
'res_model': fields.char('Model', size=64),
'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'),
'view_mode': fields.selection((('form,list','Form - List'),('list,form','List - Form')), string='Mode of view'),
'usage': fields.char('Action Usage', size=32)
}
_defaults = {
'type': lambda *a: 'ir.actions.act_window',
'view_type': lambda *a: 'form',
'view_mode': lambda *a: 'form,tree',
'context': lambda *a: '{}'
}
act_window()
class act_wizard(osv.osv):
_name = 'ir.actions.wizard'
_table = 'ir_act_wizard'
_sequence = 'ir_actions_id_seq'
_columns = {
'name': fields.char('Wizard info', size=64, required=True, translate=True),
'type': fields.char('Action type', size=32, required=True),
'wiz_name': fields.char('Wizard name', size=64, required=True),
'multi': fields.boolean('Action on multiple doc.', help="If set to true, the wizard will not be displayed on the right toolbar of a form views.")
}
_defaults = {
'type': lambda *a: 'ir.actions.wizard',
'multi': lambda *a: False,
}
act_wizard()

View File

@ -0,0 +1,43 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
class ir_attachment(osv.osv):
_name = 'ir.attachment'
_columns = {
'name': fields.char('Attachment Name',size=64, required=True),
'datas': fields.binary('Data'),
'datas_fname': fields.char('Data Filename',size=64),
'description': fields.text('Description'),
'res_model': fields.char('Resource Model',size=64, required=True, readonly=True),
'res_id': fields.integer('Resource ID', required=True, readonly=True),
'link': fields.char('Link', size=256)
}
ir_attachment()

View File

@ -0,0 +1,139 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
#
# SPEC: Execute "model.function(*eval(args))" periodically
# date : date to execute the job or NULL if directly
# delete_after: delete the ir.cron entry after execution
# interval_* : period
# max_repeat : number of execution or NULL if endlessly
#
# TODO:
# Error treatment: exception, request, ... -> send request to uid
#
from mx import DateTime
import time
import netsvc
import tools
import pooler
from osv import fields,osv
next_wait = 60
_intervalTypes = {
'work_days': lambda interal: DateTime.RelativeDateTime(days=interval),
'days': lambda interval: DateTime.RelativeDateTime(days=interval),
'hours': lambda interval: DateTime.RelativeDateTime(hours=interval),
'weeks': lambda interval: DateTime.RelativeDateTime(days=7*interval),
'months': lambda interval: DateTime.RelativeDateTime(months=interval),
'minutes': lambda interval: DateTime.RelativeDateTime(minutes=interval),
}
class ir_cron(osv.osv, netsvc.Agent):
_name = "ir.cron"
_columns = {
'name': fields.char('Name', size=60, required=True),
'user_id': fields.many2one('res.users', 'User', required=True),
'active': fields.boolean('Active'),
'interval_number': fields.integer('Interval Number'),
'interval_type': fields.selection( [('minutes', 'Minutes'),
('hours', 'Hours'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'),
# number of time the function is called, a negative number
# indicates that the function will always be called.
'numbercall': fields.integer('Number of calls'),
# Repeat missed cronjobs ?
'doall' : fields.boolean('Repeat all missed'),
'nextcall' : fields.datetime('Next call date', required=True),
'model': fields.char('Model', size=64),
'function': fields.char('Function', size=64),
'args': fields.text('Arguments'),
# 0 = Very Urgent, 10 = not urgent
'priority': fields.integer('Priority (0=Very Urgent)')
}
_defaults = {
'nextcall' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'priority' : lambda *a: 5,
'user_id' : lambda obj,cr,uid,context: uid,
'interval_number' : lambda *a: 1,
'interval_type' : lambda *a: 'months',
'numbercall' : lambda *a: 1,
'active' : lambda *a: 1,
'doall' : lambda *a: 1
}
def _callback(self, cr, uid, model, func, args):
args = (args or []) and eval(args)
f = getattr(self.pool.get(model), func)
f(cr, uid, *args)
def _poolJobs(self, db_name, check=False):
now = DateTime.now()
#FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie
# un nouveau pooljob avec comme parametre la bd
try:
cr = pooler.get_db(db_name).cursor()
except:
return False
try:
cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
for job in cr.dictfetchall():
nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
numbercall = job['numbercall']
ok = False
while nextcall<now and numbercall:
if numbercall > 0:
numbercall -= 1
if not ok or job['doall']:
self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
if numbercall:
nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
ok = True
addsql=''
if not numbercall:
addsql = ', active=False'
cr.execute("update ir_cron set nextcall=%s, numbercall=%d"+addsql+" where id=%d",
(nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id']))
cr.commit()
finally:
cr.close()
#
# Can be improved to do at the min(min(nextcalls), time()+next_wait)
# But is this an improvement ?
#
if not check:
self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name])
# def __init__(self):
# super(ir_cron, self).__init__()
ir_cron()

View File

@ -0,0 +1,43 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
class ir_default(osv.osv):
_name = 'ir.default'
_columns = {
'field_tbl': fields.char('Model',size=64),
'field_name': fields.char('Model field',size=64),
'value': fields.char('Default Value',size=64),
'uid': fields.many2one('res.users', 'Users'),
'page': fields.char('View',size=64),
'ref_table': fields.char('Table Ref.',size=64),
'ref_id': fields.integer('ID Ref.',size=64),
}
ir_default()

View File

@ -0,0 +1,50 @@
##############################################################################
#
# Copyright (c) 2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id$
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
class ir_exports(osv.osv):
_name = "ir.exports"
_columns = {
'name': fields.char('Export name', size=128),
'resource': fields.char('Resource', size=128),
'export_fields': fields.one2many('ir.exports.line', 'export_id',
'Export Id'),
}
ir_exports()
class ir_exports_line(osv.osv):
_name = 'ir.exports.line'
_columns = {
'name': fields.char('Field name', size=64),
'export_id': fields.many2one('ir.exports', 'Exportation', select=True),
}
ir_exports_line()

View File

@ -0,0 +1,32 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
import ir

View File

@ -0,0 +1,273 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
import ir
import netsvc
import time
import tools
import pooler
class ir_model(osv.osv):
_name = 'ir.model'
_rec_name = 'model'
_columns = {
'name': fields.char('Model name', size=64, translate=True),
'model': fields.char('Object name', size=64, required=True),
'info': fields.text('Information'),
'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
}
_defaults = {
'name': lambda *a: 'No Name',
}
ir_model()
class ir_model_fields(osv.osv):
_name = 'ir.model.fields'
_columns = {
'name': fields.char('Name', size=64),
'model': fields.char('Model Name', size=64, required=True),
# on pourrait egalement changer ca en many2one, mais le prob c'est qu'alors faut
# faire une jointure a chaque fois qu'on recherche vu que le client ne connait que le nom
# de l'objet et pas son id
'relation': fields.char('Model Relation', size=64),
'model_id': fields.many2one('ir.model', 'Model id', required=True, select=True),
# in fact, this is the field label
'field_description': fields.char('Field Description', size=256),
'ttype': fields.char('Field Type', size=64),
'relate': fields.boolean('Click and Relate'),
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
'group_name': fields.char('Group Name', size=128),
'view_load': fields.boolean('View Auto-Load'),
}
_defaults = {
'relate': lambda *a: 1,
'view_load': lambda *a: 0,
'name': lambda *a: 'No Name',
'field_description': lambda *a: 'No description available',
}
_order = "id"
ir_model_fields()
class ir_model_access(osv.osv):
_name = 'ir.model.access'
_columns = {
'name': fields.char('Name', size=64, required=True),
'model_id': fields.many2one('ir.model', 'Model', required=True),
'group_id': fields.many2one('res.groups', 'Group'),
'perm_read': fields.boolean('Read Access'),
'perm_write': fields.boolean('Write Access'),
'perm_create': fields.boolean('Create Access'),
}
def check(self, cr, uid, model_name, mode='read'):
assert mode in ['read','write','create'], 'Invalid access mode for security'
# fetch the list of rules for this "permission type" on this model
cr.execute('select group_id, perm_'+mode+' from ir_model_access a left join ir_model m on (a.model_id=m.id) where m.model=%s', (model_name,))
# if no rule is found, grant the access
if not cr.rowcount:
return True
# compute the list of groups which have the right we are looking for
ids = map(lambda x: str(x[0]), filter(lambda x: x[1], cr.fetchall()))
if not ids:
raise osv.except_osv('Access denied !', 'You can not %s this resource !' % mode)
ids_str = ','.join(ids)
# check if the user is part of one of those groups
cr.execute('select count(*) from res_groups_users_rel where uid=%d and gid in ('+ids_str+')', (uid,))
if cr.fetchone()[0]:
return True
raise osv.except_osv('Access denied !', 'You can not %s this resource !' % mode)
check = tools.cache()(check)
#
# Methods to clean the cache on the Check Method.
#
def write(self, cr, uid, *args, **argv):
res = super(ir_model_access, self).write(cr, uid, *args, **argv)
self.check()
return res
def create(self, cr, uid, *args, **argv):
res = super(ir_model_access, self).create(cr, uid, *args, **argv)
self.check()
return res
def unlink(self, cr, uid, *args, **argv):
res = super(ir_model_access, self).unlink(cr, uid, *args, **argv)
self.check()
return res
ir_model_access()
class ir_model_data(osv.osv):
_name = 'ir.model.data'
_columns = {
'name': fields.char('XML Identifier', required=True, size=64),
'model': fields.char('Model', required=True, size=64),
'module': fields.char('Module', required=True, size=64),
'res_id': fields.integer('Resource ID'),
'noupdate': fields.boolean('Non Updatable'),
'date_update': fields.datetime('Update Date'),
'date_init': fields.datetime('Init Date')
}
_defaults = {
'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'noupdate': lambda *a: False
}
def __init__(self, pool):
osv.osv.__init__(self, pool)
self.loads = {}
self.doinit = True
self.unlink_mark = {}
def _get_id(self,cr, uid, module, xml_id):
ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
assert len(ids)==1, '%d reference(s) to %s. You should have only one !' % (len(ids),xml_id)
return ids[0]
def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True):
if not xml_id:
return False
try:
id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id']
self.loads[(module,xml_id)] = (model,id)
except:
id = False
return id
def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False):
warning = True
if xml_id and ('.' in xml_id):
assert len(xml_id.split('.'))==2, '"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id' % (xml_id)
warning = False
module, xml_id = xml_id.split('.')
if (not xml_id) and (not self.doinit):
return False
action_id = False
if xml_id:
cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id))
results = cr.fetchall()
for action_id2,res_id2 in results:
cr.execute('select id from '+self.pool.get(model)._table+' where id=%d', (res_id2,))
result3 = cr.fetchone()
if not result3:
cr.execute('delete from ir_model_data where id=%d', (action_id2,))
else:
res_id,action_id = res_id2,action_id2
if action_id and res_id:
self.pool.get(model).write(cr, uid, [res_id], values)
self.write(cr, uid, [action_id], {'date_update': time.strftime('%Y-%m-%d %H:%M:%S')})
elif res_id:
self.pool.get(model).write(cr, uid, [res_id], values)
if xml_id:
self.create(cr, uid, {'name':xml_id, 'model':model, 'module':module, 'res_id':res_id, 'noupdate':noupdate})
else:
if mode=='init' or (mode=='update' and xml_id):
res_id = self.pool.get(model).create(cr, uid, values)
if xml_id:
self.create(cr, uid, {'name':xml_id, 'model':model, 'module':module, 'res_id':res_id, 'noupdate':noupdate})
if xml_id:
if warning:
assert (module,xml_id) not in self.loads, "id '%s' is already defined in module '%s' !" % (xml_id, module)
if res_id:
self.loads[(module,xml_id)] = (model, res_id)
return res_id
def _unlink(self, cr, uid, model, ids, direct=False):
#self.pool.get(model).unlink(cr, uid, ids)
for id in ids:
self.unlink_mark[(model, id)]=False
cr.execute('delete from ir_model_data where res_id=%d and model=\'%s\'', (id,model))
return True
def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None):
obj = self.pool.get('ir.values')
if type(models[0])==type([]) or type(models[0])==type(()):
model,res_id = models[0]
else:
res_id=None
model = models[0]
if res_id:
where = ' and res_id=%d' % (res_id,)
else:
where = ' and (res_id is null)'
if key2:
where += ' and key2=\'%s\'' % (key2,)
else:
where += ' and (key2 is null)'
cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name))
res = cr.fetchone()
if not res:
res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta)
return True
def _process_end(self, cr, uid, modules):
if not modules:
return True
module_str = ["'%s'" % m for m in modules]
cr.execute('select id,name,model,res_id,module from ir_model_data where module in ('+','.join(module_str)+') and not noupdate')
wkf_todo = []
for (id, name, model, res_id,module) in cr.fetchall():
if (module,name) not in self.loads:
self.unlink_mark[(model,res_id)] = id
if model=='workflow.activity':
cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%d)', (res_id,))
wkf_todo.extend(cr.fetchall())
cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%d where act_to=%d", (res_id,res_id))
cr.execute("delete from wkf_transition where act_to=%d", (res_id,))
for model,id in wkf_todo:
wf_service = netsvc.LocalService("workflow")
wf_service.trg_write(uid, model, id, cr)
cr.commit()
for (model,id) in self.unlink_mark.keys():
if self.pool.get(model):
print 'Deleting %s@%s' % (id, model),
try:
self.pool.get(model).unlink(cr, uid, [id])
if self.unlink_mark[(model,id)]:
self.unlink(cr, uid, [self.unlink_mark[(model,id)]])
cr.commit()
print '... ok'
except:
print '... ko'
print '-'*60
print 'WARNING: Could not delete id', id, 'of model', model
print '\tThere should be some relation that points to this resource'
print '\tYou should manually fix this and restart --update=module'
return True
ir_model_data()

View File

@ -0,0 +1,206 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
from osv.orm import browse_null
import ir
import report.custom
class report_custom(osv.osv):
_name = 'ir.report.custom'
_columns = {
'name': fields.char('Report Name', size=64, required=True, translate=True),
'model_id': fields.many2one('ir.model','Model', required=True, change_default=True),
'type': fields.selection([('table','Tabular'),('pie','Pie Chart'),('bar','Bar Chart'),('line','Line Plot')], "Report Type", size=64, required='True'),
'title': fields.char("Report title", size=64, required='True', translate=True),
'print_format': fields.selection((('A4','a4'),('A5','a5')), 'Print format', required=True),
'print_orientation': fields.selection((('landscape','Landscape'),('portrait','Portrait')), 'Print orientation', required=True, size=16),
'repeat_header': fields.boolean('Repeat Header'),
'footer': fields.char('Report Footer', size=64, required=True),
'sortby': fields.char('Sorted By', size=64),
'fields_child0': fields.one2many('ir.report.custom.fields', 'report_id','Fields', required=True),
'field_parent': fields.many2one('ir.model.fields','Child Field'),
'state': fields.selection([('unsubscribed','Unsubscribed'),('subscribed','Subscribed')], 'State', size=64),
'frequency': fields.selection([('Y','Yearly'),('M','Monthly'),('D','Daily')], 'Frequency', size=64),
'limitt': fields.char('Limit', size=9),
'menu_id': fields.many2one('ir.ui.menu', 'Menu')
}
_defaults = {
'print_format': lambda *a: 'A4',
'print_orientation': lambda *a: 'portrait',
'state': lambda *a: 'unsubscribed',
'type': lambda *a: 'table',
'footer': lambda *a: 'Generated by Tiny ERP'
}
def onchange_model_id(self, cr, uid, ids, model_id):
if not(model_id):
return {}
return {'domain': {'field_parent': [('model_id','=',model_id)]}}
def unsubscribe(self, cr, uid, ids, context={}):
#TODO: should delete the ir.actions.report.custom for these reports and do an ir_del
self.write(cr, uid, ids, {'state':'unsubscribed'})
return True
def subscribe(self, cr, uid, ids, context={}):
for report in self.browse(cr, uid, ids):
report.fields_child0.sort(lambda x,y : x.sequence - y.sequence)
# required on field0 does not seem to work( cause we use o2m_l ?)
if not report.fields_child0:
raise osv.except_osv('Invalid operation :', 'Enter at least one field !')
if report.type in ['pie', 'bar', 'line'] and report.field_parent:
raise osv.except_osv('Invalid operation :', 'Tree can only be used in tabular reports')
# Otherwise it won't build a good tree. See level.pop in custom.py.
if report.type == 'table' and report.field_parent and report.fields_child0 and not report.fields_child0[0].groupby:
raise osv.except_osv('Invalid operation :', 'When creating tree (field child) report, data must be group by the first field')
if report.type == 'pie':
if len(report.fields_child0) != 2:
raise osv.except_osv('Invalid operation :', 'Pie charts need exactly two fields')
else:
c_f = {}
for i in range(2):
c_f[i] = []
tmp = report.fields_child0[i]
for j in range(3):
c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[1])):
raise osv.except_osv('Invalid operation : ','Second field should be figures')
if report.type == 'bar':
if len(report.fields_child0) < 2:
raise osv.except_osv('Invalid operation : ','Bar charts need at least two fields')
else:
c_f = {}
for i in range(len(report.fields_child0)):
c_f[i] = []
tmp = report.fields_child0[i]
for j in range(3):
c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
if i == 0:
pass
else:
if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[i])):
raise osv.except_osv('Invalid operation : ','Field %d should be a figure' %(i,))
if report.state=='subscribed':
continue
name = report.name
model = report.model_id.model
action_def = {'report_id':report.id, 'type':'ir.actions.report.custom', 'model':model, 'name':name}
id = self.pool.get('ir.actions.report.custom').create(cr, uid, action_def)
m_id = report.menu_id.id
action = "ir.actions.report.custom,%d" % (id,)
if not report.menu_id:
ir.ir_set(cr, uid, 'action', 'client_print_multi', name, [(model, False)], action, False, True)
else:
ir.ir_set(cr, uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(m_id))], action, False, True)
self.write(cr, uid, [report.id], {'state':'subscribed'}, context)
return True
report_custom()
class report_custom_fields(osv.osv):
_name = 'ir.report.custom.fields'
_columns = {
'name': fields.char('Name', size=64, required=True),
'report_id': fields.many2one('ir.report.custom', 'Report Ref', select=True),
'field_child0': fields.many2one('ir.model.fields', 'field child0', required=True),
'fc0_operande': fields.many2one('ir.model.fields', 'Constraint'),
'fc0_condition': fields.char('Condition', size=64),
'fc0_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
'field_child1': fields.many2one('ir.model.fields', 'field child1'),
'fc1_operande': fields.many2one('ir.model.fields', 'Constraint'),
'fc1_condition': fields.char('condition', size=64),
'fc1_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
'field_child2': fields.many2one('ir.model.fields', 'field child2'),
'fc2_operande': fields.many2one('ir.model.fields', 'Constraint'),
'fc2_condition': fields.char('condition', size=64),
'fc2_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
'field_child3': fields.many2one('ir.model.fields', 'field child3'),
'fc3_operande': fields.many2one('ir.model.fields', 'Constraint'),
'fc3_condition': fields.char('condition', size=64),
'fc3_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
'alignment': fields.selection((('left','left'),('right','right'),('center','center')), 'Alignment', required=True),
'sequence': fields.integer('Sequence', required=True),
'width': fields.integer('Fixed Width'),
'operation': fields.selection((('none', 'None'),('calc_sum','Calculate Sum'),('calc_avg','Calculate Average'),('calc_count','Calculate Count'),('calc_max', 'Get Max'))),
'groupby' : fields.boolean('Group by'),
'bgcolor': fields.char('Background Color', size=64),
'fontcolor': fields.char('Font color', size=64),
'cumulate': fields.boolean('Cumulate')
}
_defaults = {
'alignment': lambda *a: 'left',
'bgcolor': lambda *a: 'white',
'fontcolor': lambda *a: 'black',
'operation': lambda *a: 'none',
}
_order = "sequence"
def onchange_any_field_child(self, cr, uid, ids, field_id, level):
if not(field_id):
return {}
next_level_field_name = 'field_child%d' % (level+1)
next_level_operande = 'fc%d_operande' % (level+1)
field = self.pool.get('ir.model.fields').browse(cr, uid, [field_id])[0]
res = self.pool.get(field.model).fields_get(cr, uid, field.name)
if res[field.name].has_key('relation'):
cr.execute('select id from ir_model where model=%s', (res[field.name]['relation'],))
(id,) = cr.fetchone() or (False,)
if id:
return {
'domain': {
next_level_field_name: [('model_id', '=', id)],
next_level_operande: [('model_id', '=', id)]
},
'required': {
next_level_field_name: True
}
}
else:
print "Warning: using a relation field which uses an unknown object"
return {'required': {next_level_field_name: True}}
else:
return {'domain': {next_level_field_name: []}}
def get_field_child_onchange_method(level):
return lambda self, cr, uid, ids, field_id: self.onchange_any_field_child(cr, uid, ids, field_id, level)
onchange_field_child0 = get_field_child_onchange_method(0)
onchange_field_child1 = get_field_child_onchange_method(1)
onchange_field_child2 = get_field_child_onchange_method(2)
report_custom_fields()

View File

@ -0,0 +1,93 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import threading
import time
from osv import fields,osv
class ir_sequence_type(osv.osv):
_name = 'ir.sequence.type'
_columns = {
'name': fields.char('Sequence Name',size=64, required=True),
'code': fields.char('Sequence Code',size=32, required=True),
}
ir_sequence_type()
def _code_get(self, cr, uid, context={}):
cr.execute('select code, name from ir_sequence_type')
return cr.fetchall()
class ir_sequence(osv.osv):
_name = 'ir.sequence'
_columns = {
'name': fields.char('Sequence Name',size=64, required=True),
'code': fields.selection(_code_get, 'Sequence Code',size=64, required=True),
'active': fields.boolean('Active'),
'prefix': fields.char('Prefix',size=64),
'suffix': fields.char('Suffix',size=64),
'number_next': fields.integer('Next Number', required=True),
'number_increment': fields.integer('Increment Number', required=True),
'padding' : fields.integer('Number padding', required=True),
}
_defaults = {
'active': lambda *a: True,
'number_increment': lambda *a: 1,
'number_next': lambda *a: 1,
'padding' : lambda *a : 0,
}
sequence_semaphore = threading.Semaphore()
def _process(self, s):
return (s or '') % {'year':time.strftime('%Y'), 'month': time.strftime('%m'), 'day':time.strftime('%d')}
def get_id(self, cr, uid, sequence_id, test='id=%d'):
self.sequence_semaphore.acquire()
cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True', (sequence_id,))
res = cr.dictfetchone()
if res:
cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%d and active=True', (res['id'],))
self.sequence_semaphore.release()
if res['number_next']:
return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix'])
else:
return self._process(res['prefix']) + self._process(res['suffix'])
else:
self.sequence_semaphore.release()
return False
def get(self, cr, uid, code):
return self.get_id(cr, uid, code, test='code=%s')
def set(self, cr, uid, code, next_number):
self.sequence_semaphore.acquire()
cr.execute('update ir_sequence set number_next=%d where code=%s and active=True', (next_number, code,))
self.sequence_semaphore.release()
return True
ir_sequence()

View File

@ -0,0 +1,88 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields, osv
from osv.osv import Cacheable
class ir_translation(osv.osv, Cacheable):
_name = "ir.translation"
_log_access = False
_columns = {
'name': fields.char('Field Name', size=128, required=True),
'res_id': fields.integer('Resource ID'),
'lang': fields.char('Language', size=5),
'type': fields.char('Type', size=16),
'src': fields.text('Source'),
'value': fields.text('Translation Value'),
}
_sql = """
create index ir_translation_ltn on ir_translation (lang,type,name);
create index ir_translation_res_id on ir_translation (res_id);
"""
def _get_ids(self, cr, uid, name, tt, lang, ids):
translations, to_fetch = {}, []
for id in ids:
trans = self.get((lang, name, id))
if trans:
translations[id] = trans
else:
to_fetch.append(id)
if to_fetch:
cr.execute('select res_id,value from ir_translation where lang=%s and type=%s and name=%s and res_id in ('+','.join(map(str, to_fetch))+')', (lang,tt,name))
for res_id, value in cr.fetchall():
self.add((lang, tt, name, res_id), value)
translations[res_id] = value
return translations
def _set_ids(self, cr, uid, name, tt, lang, ids, value):
cr.execute('delete from ir_translation where lang=%s and type=%s and name=%s and res_id in ('+','.join(map(str,ids))+')', (lang,tt,name))
for id in ids:
self.create(cr, uid, {'lang':lang, 'type':tt, 'name':name, 'res_id':id, 'value':value})
return len(ids)
def _get_source(self, cr, uid, name, tt, lang, source=None):
trans = self.get((lang, tt, name, source))
if trans:
return trans
if source:
source = source.strip().replace('\n',' ')
if isinstance(source, unicode):
source = source.encode('utf8')
cr.execute('select value from ir_translation where lang=%s and type=%s and name=%s and src=%s', (lang, tt, str(name), source))
else:
cr.execute('select value from ir_translation where lang=%s and type=%s and name=%s', (lang, tt, str(name)))
res = cr.fetchone()
if res:
self.add((lang, tt, name, source), res[0])
return res[0]
else:
self.add((lang, tt, name, source), False)
return False
ir_translation()

View File

@ -0,0 +1,123 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: ir_ui_menu.py 1005 2005-07-25 08:41:42Z nicoe $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields, osv
from osv.orm import browse_null, browse_record
def one_in(setA, setB):
"""Check the presence of an element of setA in setB
"""
for x in setA:
if x in setB:
return True
return False
icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',
'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER',
'STOCK_CONNECT', 'STOCK_CONVERT', 'STOCK_COPY', 'STOCK_CUT', 'STOCK_DELETE',
'STOCK_DIALOG_AUTHENTICATION', 'STOCK_DIALOG_ERROR', 'STOCK_DIALOG_INFO',
'STOCK_DIALOG_QUESTION', 'STOCK_DIALOG_WARNING', 'STOCK_DIRECTORY', 'STOCK_DISCONNECT',
'STOCK_DND', 'STOCK_DND_MULTIPLE', 'STOCK_EDIT', 'STOCK_EXECUTE', 'STOCK_FILE',
'STOCK_FIND', 'STOCK_FIND_AND_REPLACE', 'STOCK_FLOPPY', 'STOCK_GOTO_BOTTOM',
'STOCK_GOTO_FIRST', 'STOCK_GOTO_LAST', 'STOCK_GOTO_TOP', 'STOCK_GO_BACK',
'STOCK_GO_DOWN', 'STOCK_GO_FORWARD', 'STOCK_GO_UP', 'STOCK_HARDDISK',
'STOCK_HELP', 'STOCK_HOME', 'STOCK_INDENT', 'STOCK_INDEX', 'STOCK_ITALIC',
'STOCK_JUMP_TO', 'STOCK_JUSTIFY_CENTER', 'STOCK_JUSTIFY_FILL',
'STOCK_JUSTIFY_LEFT', 'STOCK_JUSTIFY_RIGHT', 'STOCK_MEDIA_FORWARD',
'STOCK_MEDIA_NEXT', 'STOCK_MEDIA_PAUSE', 'STOCK_MEDIA_PLAY',
'STOCK_MEDIA_PREVIOUS', 'STOCK_MEDIA_RECORD', 'STOCK_MEDIA_REWIND',
'STOCK_MEDIA_STOP', 'STOCK_MISSING_IMAGE', 'STOCK_NETWORK', 'STOCK_NEW',
'STOCK_NO', 'STOCK_OK', 'STOCK_OPEN', 'STOCK_PASTE', 'STOCK_PREFERENCES',
'STOCK_PRINT', 'STOCK_PRINT_PREVIEW', 'STOCK_PROPERTIES', 'STOCK_QUIT',
'STOCK_REDO', 'STOCK_REFRESH', 'STOCK_REMOVE', 'STOCK_REVERT_TO_SAVED',
'STOCK_SAVE', 'STOCK_SAVE_AS', 'STOCK_SELECT_COLOR', 'STOCK_SELECT_FONT',
'STOCK_SORT_ASCENDING', 'STOCK_SORT_DESCENDING', 'STOCK_SPELL_CHECK',
'STOCK_STOP', 'STOCK_STRIKETHROUGH', 'STOCK_UNDELETE', 'STOCK_UNDERLINE',
'STOCK_UNDO', 'STOCK_UNINDENT', 'STOCK_YES', 'STOCK_ZOOM_100',
'STOCK_ZOOM_FIT', 'STOCK_ZOOM_IN', 'STOCK_ZOOM_OUT',
'terp-account', 'terp-crm', 'terp-mrp', 'terp-product', 'terp-purchase', 'terp-sale', 'terp-tools',
'terp-administration', 'terp-hr', 'terp-partner', 'terp-project', 'terp-report', 'terp-stock'
])
class ir_ui_menu(osv.osv):
_name = 'ir.ui.menu'
def search(self, cr, uid, args, offset=0, limit=2000, order=None):
ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order)
user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id']
result = []
for menu in self.browse(cr, uid, ids):
if not len(menu.groups_id):
result.append(menu.id)
continue
for g in menu.groups_id:
if g.id in user_groups:
result.append(menu.id)
break
return result
def _get_full_name(self, cr, uid, ids, name, args, context):
res = {}
for m in self.browse(cr, uid, ids):
res[m.id] = self._get_one_full_name(m)
return res
def _get_one_full_name(self, menu, level=6):
if level<=0:
return '...'
if menu.parent_id:
parent_path = self._get_one_full_name(menu.parent_id, level-1) + "/"
else:
parent_path = ''
return parent_path + menu.name
def copy(self, cr, uid, id, default=None, context={}):
res = super(ir_ui_menu, self).copy(cr, uid, id, context=context)
ids = self.pool.get('ir.values').search(cr, uid, [('model','=','ir.ui.menu'),('res_id','=',id)])
for iv in self.pool.get('ir.values').browse(cr, uid, ids):
new_id = self.pool.get('ir.values').copy(cr, uid, iv.id, default={'res_id':res}, context=context)
return res
_columns = {
'name': fields.char('Menu', size=64, required=True, translate=True),
'sequence': fields.integer('Sequence'),
'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child ids'),
'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
'groups_id': fields.many2many('res.groups', 'ir_ui_menu_group_rel', 'menu_id', 'gid', 'Groups'),
'complete_name': fields.function(_get_full_name, method=True, string='Complete Name', type='char', size=128),
'icon': fields.selection(lambda *a: icons, 'Icon', size=64)
}
_defaults = {
'icon' : lambda *a: 'STOCK_OPEN',
'sequence' : lambda *a: 10
}
_order = "sequence,id"
ir_ui_menu()

View File

@ -0,0 +1,76 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
from xml import dom
def _check_xml(self, cr, uid, ids):
try:
cr.execute('select arch from ir_ui_view where id in ('+','.join(map(str,ids))+')')
for row in cr.fetchall():
doc = dom.minidom.parseString(row[0])
return True
except Exception, e:
return False
class view(osv.osv):
_name = 'ir.ui.view'
_columns = {
'name': fields.char('View Name',size=64, required=True),
'model': fields.char('Model', size=64, required=True),
'priority': fields.integer('Priority', required=True),
'type': fields.selection((('tree','Tree'),('form','Form')), 'View Type', required=True),
'arch': fields.text('View Architecture', required=True),
'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'),
'field_parent': fields.char('Childs Field',size=64)
}
_defaults = {
'arch': lambda *a: '<?xml version="1.0"?>\n<tree title="Unknwown">\n\t<field name="name"/>\n</tree>',
'priority': lambda *a: 16
}
_order = "priority"
_constraints = [
(_check_xml, 'Invalid XML for View Architecture!', ['arch'])
]
view()
class view_sc(osv.osv):
_name = 'ir.ui.view_sc'
_columns = {
'name': fields.char('Shortcut Name', size=64, required=True),
'res_id': fields.integer('Resource Ref.', required=True),
'sequence': fields.integer('Sequence'),
'user_id': fields.many2one('res.users', 'User Ref.', required=True, ondelete='cascade'),
'resource': fields.char('Resource Name', size=64, required=True)
}
_order = 'sequence'
_defaults = {
'resource': lambda *a: 'ir.ui.menu',
}
view_sc()

View File

@ -0,0 +1,153 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import osv,fields
import pickle
class ir_values(osv.osv):
_name = 'ir.values'
_columns = {
'name': fields.char('Name', size=128),
'model': fields.char('Name', size=128),
'value': fields.text('Value'),
'object': fields.boolean('Is Object'),
'key': fields.char('Name', size=128),
'key2': fields.char('Value', size=256),
'meta': fields.text('Meta Datas'),
'res_id': fields.integer('Resource ID'),
'user_id': fields.many2one('res.users', 'User', ondelete='cascade')
}
_defaults = {
'key': lambda *a: 'action',
'key2': lambda *a: 'tree_but_open',
}
def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False):
if not isobject:
value = pickle.dumps(value)
if meta:
meta = pickle.dumps(meta)
ids_res = []
for model in models:
if type(model)==type([]) or type(model)==type(()):
model,res_id = model
else:
res_id=False
if replace:
ids = self.search(cr, uid, [('key','=',key),('key2','=',key2),('name','=',name),('model','=',model),('res_id','=',res_id)])
self.unlink(cr, uid, ids)
vals = {
'name': name,
'value': value,
'model': model,
'object': isobject,
'key': key,
'key2': key2 and key2[:200],
'meta': meta,
'user_id': preserve_user and uid,
}
if res_id:
vals['res_id']= res_id
ids_res.append(self.create(cr, uid, vals))
return ids_res
#
# Improve to add user_id check
#
def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True):
result = []
for m in models:
if type(m)==type([]) or type(m)==type(()):
m,res_id = m
else:
res_id=False
where1 = ['key=%s','model=%s']
where2 = [key,m]
where_opt = []
if key2:
where1.append('key2=%s')
where2.append(key2[:200])
else:
dest = where1
if not key2_req or meta:
dest=where_opt
dest.append('key2 is null')
if res_id_req and (models[-1][0]==m):
if res_id:
where1.append('res_id=%d' % (res_id,))
else:
where1.append('(res_id is NULL)')
else:
if res_id:
if (models[-1][0]==m):
where1.append('(res_id=%d or (res_id is null))' % (res_id,))
where_opt.append('res_id=%d' % (res_id,))
else:
where1.append('res_id=%d' % (res_id,))
if not without_user:
where_opt.append('user_id=%d' % (uid,))
result = []
ok = True
while ok and len(result)==0:
cr.execute('select id from ir_values where '+' and '.join(where1+where_opt), where2)
result = [x[0] for x in cr.fetchall()]
if len(where_opt):
where_opt.pop()
else:
ok = False
if result:
break
if not result:
return []
cr.execute('select id,name,value,object,meta from ir_values where id in ('+','.join(map(str,result))+')')
result = cr.fetchall()
def _result_get(x):
if x[3]:
model,id = x[2].split(',')
datas = self.pool.get(model).read(cr, uid, [int(id)], False, context)
if not len(datas):
#ir_del(cr, uid, x[0])
return False
datas = datas[0]
else:
datas = pickle.loads(x[2])
if meta:
meta2 = pickle.loads(x[4])
return (x[0],x[1],datas,meta2)
return (x[0],x[1],datas)
res = filter(bool, map(lambda x: _result_get(x), list(result)))
return res
ir_values()

View File

@ -0,0 +1,2 @@
import workflow
import print_instance

View File

@ -0,0 +1,88 @@
import psycopg
import pydot
wkf_id = 231
db = psycopg.connect('dbname=terp', serialize=0)
cr=db.cursor()
def graph_get(cr, graph, wkf_id, nested=True, workitem={}):
cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
nodes = cr.dictfetchall()
activities = {}
actfrom = {}
actto = {}
for n in nodes:
activities[n['id']] = n
if n['subflow_id'] and nested:
cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
wkfinfo = cr.dictfetchone()
graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=10, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
(s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
graph.add_subgraph(graph2)
actfrom[n['id']] = s2
actto[n['id']] = s1
else:
args = {}
if n['flow_start'] or n['flow_stop']:
args['style']='filled'
args['color']='lightgrey'
args['label']=n['name']
if n['action']:
args['label']+='\\n'+n['action']
if n['subflow_id']:
args['shape'] = 'box'
if n['id'] in workitem:
args['label']+='\\nx '+str(workitem[n['id']])
args['color'] = "red"
graph.add_node(pydot.Node(n['id'], **args))
actfrom[n['id']] = n['id']
actto[n['id']] = n['id']
cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
transitions = cr.dictfetchall()
for t in transitions:
args = {}
args['label'] = str(t['condition'])
if t['signal']:
args['label'] += '\\n'+str(t['signal'])
args['style'] = 'bold'
if activities[t['act_from']]['split_mode']=='AND':
args['arrowtail']='box'
elif str(activities[t['act_from']]['split_mode'])=='OR ':
args['arrowtail']='inv'
if activities[t['act_to']]['join_mode']=='AND':
args['arrowhead']='crow'
graph.add_edge(pydot.Edge(actfrom[t['act_from']],actto[t['act_to']], fontsize=8, **args))
nodes = cr.dictfetchall()
cr.execute('select id from wkf_activity where flow_start=True limit 1')
start = cr.fetchone()[0]
cr.execute('select id from wkf_activity where flow_stop=True limit 1')
stop = cr.fetchone()[0]
return (start,stop)
def graph_instance_get(cr, graph, inst_id, nested=False):
workitems = {}
cr.execute('select * from wkf_instance where id=%d', (inst_id,))
inst = cr.dictfetchone()
def workitem_get(instance):
cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,))
workitems = dict(cr.fetchall())
cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
for (subflow_id,) in cr.fetchall():
workitems.update(workitem_get(subflow_id))
return workitems
graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id))
cr.execute('select * from wkf where id=%d', (wkf_id,))
wkfinfo = cr.dictfetchone()
graph = pydot.Dot(fontsize = 16, label = "\\n\\nWorkflow: %s\\n OSV: %s"% (wkfinfo['name'],wkfinfo['osv']))
graph_instance_get(cr, graph, 1155, True)
graph.write_ps('/tmp/a.ps', prog='dot')

View File

@ -0,0 +1,172 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import time, os
import netsvc
import report,pooler,tools
def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
import pydot
cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
nodes = cr.dictfetchall()
activities = {}
actfrom = {}
actto = {}
for n in nodes:
activities[n['id']] = n
if n['subflow_id'] and nested:
cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
wkfinfo = cr.dictfetchone()
graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=10, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
(s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
graph.add_subgraph(graph2)
actfrom[n['id']] = s2
actto[n['id']] = s1
else:
args = {}
if n['flow_start'] or n['flow_stop']:
args['style']='filled'
args['color']='lightgrey'
args['label']=n['name']
if n['subflow_id']:
args['shape'] = 'box'
if n['id'] in workitem:
args['label']+='\\nx '+str(workitem[n['id']])
args['color'] = "red"
graph.add_node(pydot.Node(n['id'], **args))
actfrom[n['id']] = (n['id'],{})
actto[n['id']] = (n['id'],{})
cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
transitions = cr.dictfetchall()
for t in transitions:
args = {}
args['label'] = str(t['condition'])
if t['signal']:
args['label'] += '\\n'+str(t['signal'])
args['style'] = 'bold'
if activities[t['act_from']]['split_mode']=='AND':
args['arrowtail']='box'
elif str(activities[t['act_from']]['split_mode'])=='OR ':
args['arrowtail']='inv'
if activities[t['act_to']]['join_mode']=='AND':
args['arrowhead']='crow'
activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0])
activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
graph.add_edge(pydot.Edge( activity_from ,activity_to, fontsize=8, **args))
nodes = cr.dictfetchall()
cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,))
start = cr.fetchone()[0]
cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,))
stop = cr.fetchall()
stop = (stop[0][1], dict(stop))
return ((start,{}),stop)
def graph_instance_get(cr, graph, inst_id, nested=False):
workitems = {}
cr.execute('select * from wkf_instance where id=%d', (inst_id,))
inst = cr.dictfetchone()
def workitem_get(instance):
cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,))
workitems = dict(cr.fetchall())
cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
for (subflow_id,) in cr.fetchall():
workitems.update(workitem_get(subflow_id))
return workitems
graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id))
#
# TODO: pas clean: concurrent !!!
#
class report_graph_instance(object):
def __init__(self, cr, uid, ids, data):
try:
import pydot
except Exception,e:
print 'Import Error for pydot, you will not be able to render workflows'
print 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html'
raise e
self.done = False
try:
cr.execute('select * from wkf where osv=%s limit 1', (data['model'],))
wkfinfo = cr.dictfetchone()
cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d order by state limit 1', (data['id'],wkfinfo['id']))
inst_id = cr.fetchone()[0]
graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv']))
graph_instance_get(cr, graph, inst_id, data.get('nested', False))
ps_string = graph.create_ps(prog='dot')
except:
# string is in PS, like the success message would have been
ps_string = '''%PS-Adobe-3.0
/inch {72 mul} def
/Times-Roman findfont 50 scalefont setfont
1.5 inch 15 inch moveto
(No workflow available) show
showpage'''
input, output = os.popen2('ps2pdf -sPAPERSIZE=a3 - -')
input.write(ps_string)
input.close()
self.result = output.read()
output.close()
self.done = True
def is_done(self):
return self.done
def get(self):
if self.done:
return self.result
else:
return None
class report_graph(report.interface.report_int):
def __init__(self, name, table):
report.interface.report_int.__init__(self, name)
self.table = table
def result(self):
if self.obj.is_done():
return (True, self.obj.get(), 'pdf')
else:
return (False, False, False)
def create(self, cr, uid, ids, data, context={}):
self.obj = report_graph_instance(cr, uid, ids, data)
return (self.obj.get(), 'pdf')
report_graph('report.workflow.instance.graph', 'ir.workflow')

View File

@ -0,0 +1,16 @@
Copyright (c) 2004 Ero Carrera
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,33 @@
Metadata-Version: 1.0
Name: pydot
Version: 0.9.9
Summary: Python interface to Graphiz's Dot
Home-page: http://dkbza.org/pydot.html
Author: Ero Carrera
Author-email: ero@dkbza.org
License: MIT
Description: Graphviz's dot language Python interface.
This module provides with a full interface to create handle modify
and process graphs in Graphviz's dot language.
References:
pydot Homepage: http://www.dkbza.org/pydot.html
Graphviz: http://www.research.att.com/sw/tools/graphviz/
DOT Language: http://www.research.att.com/~erg/graphviz/info/lang.html
Programmed and tested with Graphviz 1.12 and Python 2.3.3 on GNU/Linux
by Ero Carrera (c) 2004 [ero@dkbza.org]
Distributed under MIT license [http://opensource.org/licenses/mit-license.html].
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: Software Development :: Libraries :: Python Modules

View File

@ -0,0 +1,29 @@
pydot - Python interface to Graphviz's Dot language
Ero Carrera (c) 2004
ero@dkbza.org
This code is distributed under the MIT license.
Requirements:
-------------
pyparsing: pydot requires the pyparsing module in order to be
able to load DOT files.
GraphViz: is needed in order to render the graphs into any of
the plethora of output formats supported.
Installation:
-------------
Should suffice with doing:
python setup.py install
Needless to say, no installation is needed just to use the module. A mere:
import pydot
should do it, provided that the directory containing the modules is on Python
module search path.

View File

@ -0,0 +1 @@
from pydot import *

View File

@ -0,0 +1,352 @@
#!/bin/env python
"""
The dotparser parses graphviz files in dot and dot files and transforms them
into a class representation defined by pydot.
The module needs pyparsing (tested with version 1.2) and pydot (tested with 0.9.9)
Author: Michael Krause <michael@krause-software.de>
"""
import sys
import glob
import pydot
from pyparsing import __version__ as pyparsing_version
from pyparsing import Literal, CaselessLiteral, Word, \
Upcase, OneOrMore, ZeroOrMore, Forward, NotAny, \
delimitedList, oneOf, Group, Optional, Combine, \
alphas, nums, restOfLine, cStyleComment, nums, \
alphanums, printables, empty, quotedString, \
ParseException, ParseResults, CharsNotIn, _noncomma
class P_AttrList:
def __init__(self, toks):
self.attrs = {}
i = 0
while i < len(toks):
attrname = toks[i]
attrvalue = toks[i+1]
self.attrs[attrname] = attrvalue
i += 2
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self.attrs)
class DefaultStatement(P_AttrList):
def __init__(self, default_type, attrs):
self.default_type = default_type
self.attrs = attrs
def __repr__(self):
return "%s(%s, %r)" % \
(self.__class__.__name__, self.default_type, self.attrs)
def push_top_graph_stmt(str, loc, toks):
attrs = {}
g = None
for element in toks:
if isinstance(element, ParseResults) or \
isinstance(element, tuple) or \
isinstance(element, list):
element = element[0]
if element == 'strict':
attrs['strict'] = True
elif element in ['graph', 'digraph']:
attrs['graph_type'] = element
elif type(element) == type(''):
attrs['graph_name'] = element
elif isinstance(element, pydot.Graph):
g = pydot.Graph(**attrs)
g.__dict__.update(element.__dict__)
for e in g.get_edge_list():
e.parent_graph = g
for e in g.get_node_list():
e.parent_graph = g
for e in g.get_subgraph_list():
e.set_graph_parent(g)
elif isinstance(element, P_AttrList):
attrs.update(element.attrs)
else:
raise ValueError, "Unknown element statement: %r " % element
if g is not None:
g.__dict__.update(attrs)
return g
def add_defaults(element, defaults):
d = element.__dict__
for key, value in defaults.items():
if not d.get(key):
d[key] = value
def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge=None):
if defaults_graph is None:
defaults_graph = {}
if defaults_node is None:
defaults_node = {}
if defaults_edge is None:
defaults_edge = {}
for element in toks:
if isinstance(element, pydot.Graph):
add_defaults(element, defaults_graph)
g.add_subgraph(element)
elif isinstance(element, pydot.Node):
add_defaults(element, defaults_node)
g.add_node(element)
elif isinstance(element, pydot.Edge):
add_defaults(element, defaults_edge)
g.add_edge(element)
elif isinstance(element, ParseResults):
for e in element:
add_elements(g, [e], defaults_graph, defaults_node, defaults_edge)
elif isinstance(element, DefaultStatement):
if element.default_type == 'graph':
default_graph_attrs = pydot.Node('graph')
default_graph_attrs.__dict__.update(element.attrs)
g.add_node(default_graph_attrs)
# defaults_graph.update(element.attrs)
# g.__dict__.update(element.attrs)
elif element.default_type == 'node':
default_node_attrs = pydot.Node('node')
default_node_attrs.__dict__.update(element.attrs)
g.add_node(default_node_attrs)
#defaults_node.update(element.attrs)
elif element.default_type == 'edge':
default_edge_attrs = pydot.Node('edge')
default_edge_attrs.__dict__.update(element.attrs)
g.add_node(default_edge_attrs)
#defaults_edge.update(element.attrs)
else:
raise ValueError, "Unknown DefaultStatement: %s " % element.default_type
elif isinstance(element, P_AttrList):
g.__dict__.update(element.attrs)
else:
raise ValueError, "Unknown element statement: %r " % element
def push_graph_stmt(str, loc, toks):
g = pydot.Subgraph()
add_elements(g, toks)
return g
def push_subgraph_stmt(str, loc, toks):
for e in toks:
if len(e)==3:
g = e[2]
g.set_name(e[1])
return g
def push_default_stmt(str, loc, toks):
# The pydot class instances should be marked as
# default statements to be inherited by actual
# graphs, nodes and edges.
# print "push_default_stmt", toks
default_type = toks[0][0]
if len(toks) > 1:
attrs = toks[1].attrs
else:
attrs = {}
if default_type in ['graph', 'node', 'edge']:
return DefaultStatement(default_type, attrs)
else:
raise ValueError, "Unknown default statement: %r " % toks
def push_attr_list(str, loc, toks):
p = P_AttrList(toks)
return p
def get_port(node):
if len(node)>1:
if isinstance(node[1], ParseResults):
if len(node[1][0])==2:
if node[1][0][0]==':':
return node[1][0][1]
return None
def push_edge_stmt(str, loc, toks):
tok_attrs = [a for a in toks if isinstance(a, P_AttrList)]
attrs = {}
for a in tok_attrs:
attrs.update(a.attrs)
n_prev = toks[0]
e = []
for n_next in tuple(toks)[2::2]:
port = get_port(n_prev)
if port is not None:
n_prev_port = ':'+port
else:
n_prev_port = ''
port = get_port(n_next)
if port is not None:
n_next_port = ':'+port
else:
n_next_port = ''
e.append(pydot.Edge(n_prev[0]+n_prev_port, n_next[0]+n_next_port, **attrs))
n_prev = n_next
return e
def push_node_stmt(str, loc, toks):
if len(toks) == 2:
attrs = toks[1].attrs
else:
attrs = {}
node_name = toks[0]
if isinstance(node_name, list) or isinstance(node_name, tuple):
if len(node_name)>0:
node_name = node_name[0]
n = pydot.Node(node_name, **attrs)
return n
def strip_quotes( s, l, t ):
return [ t[0].strip('"') ]
graphparser = None
def GRAPH_DEF():
global graphparser
if not graphparser:
# punctuation
colon = Literal(":")
lbrace = Literal("{")
rbrace = Literal("}")
lbrack = Literal("[")
rbrack = Literal("]")
lparen = Literal("(")
rparen = Literal(")")
equals = Literal("=")
comma = Literal(",")
dot = Literal(".")
slash = Literal("/")
bslash = Literal("\\")
star = Literal("*")
semi = Literal(";")
at = Literal("@")
minus = Literal("-")
# keywords
strict_ = Literal("strict")
graph_ = Literal("graph")
digraph_ = Literal("digraph")
subgraph_ = Literal("subgraph")
node_ = Literal("node")
edge_ = Literal("edge")
identifier = Word(alphanums + "_" ).setName("identifier")
double_quote = Literal('"')
double_quoted_string = \
Combine( double_quote + ZeroOrMore(CharsNotIn('"')) + double_quote )
alphastring_ = OneOrMore(CharsNotIn(_noncomma))
ID = (identifier | double_quoted_string.setParseAction(strip_quotes) |\
alphastring_).setName("ID")
html_text = Combine(Literal("<<") + OneOrMore(CharsNotIn(",]")))
float_number = Combine(Optional(minus) + \
OneOrMore(Word(nums + "."))).setName("float_number")
righthand_id = (float_number | ID | html_text).setName("righthand_id")
port_angle = (at + ID).setName("port_angle")
port_location = (Group(colon + ID) | \
Group(colon + lparen + ID + comma + ID + rparen)).setName("port_location")
port = (Group(port_location + Optional(port_angle)) | \
Group(port_angle + Optional(port_location))).setName("port")
node_id = (ID + Optional(port))
a_list = OneOrMore(ID + Optional(equals.suppress() + righthand_id) + \
Optional(comma.suppress())).setName("a_list")
attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) + \
rbrack.suppress()).setName("attr_list")
attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt")
edgeop = (Literal("--") | Literal("->")).setName("edgeop")
stmt_list = Forward()
graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + \
rbrace.suppress()).setName("graph_stmt")
subgraph = (Group(Optional(subgraph_ + Optional(ID)) + graph_stmt) | \
Group(subgraph_ + ID)).setName("subgraph")
edgeRHS = OneOrMore(edgeop + Group(node_id | subgraph))
edge_stmt = Group(node_id | subgraph) + edgeRHS + Optional(attr_list)
node_stmt = (node_id + Optional(attr_list) + semi.suppress()).setName("node_stmt")
assignment = (ID + equals.suppress() + righthand_id).setName("assignment")
stmt = (assignment | edge_stmt | attr_stmt | node_stmt | subgraph).setName("stmt")
stmt_list << OneOrMore(stmt + Optional(semi.suppress()))
graphparser = (Optional(strict_) + Group((graph_ | digraph_)) + \
Optional(ID) + graph_stmt).setResultsName("graph")
singleLineComment = "//" + restOfLine
graphparser.ignore(singleLineComment)
graphparser.ignore(cStyleComment)
assignment.setParseAction(push_attr_list)
a_list.setParseAction(push_attr_list)
edge_stmt.setParseAction(push_edge_stmt)
node_stmt.setParseAction(push_node_stmt)
attr_stmt.setParseAction(push_default_stmt)
subgraph.setParseAction(push_subgraph_stmt)
graph_stmt.setParseAction(push_graph_stmt)
graphparser.setParseAction(push_top_graph_stmt)
return graphparser
def parse_dot_data(data):
try:
graphparser = GRAPH_DEF()
if pyparsing_version >= '1.2':
graphparser.parseWithTabs()
tokens = graphparser.parseString(data)
graph = tokens.graph
return graph
except ParseException, err:
print err.line
print " "*(err.column-1) + "^"
print err
return None

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
from distutils.core import setup
import pydot
setup( name = 'pydot',
version = pydot.__version__,
description = 'Python interface to Graphiz\'s Dot',
author = 'Ero Carrera',
author_email = 'ero@dkbza.org',
url = 'http://dkbza.org/pydot.html',
license = 'MIT',
platforms = ["any"],
classifiers = ['Development Status :: 5 - Production/Stable', \
'Intended Audience :: Science/Research', \
'License :: OSI Approved :: MIT License',\
'Natural Language :: English', \
'Operating System :: OS Independent', \
'Programming Language :: Python', \
'Topic :: Scientific/Engineering :: Visualization',\
'Topic :: Software Development :: Libraries :: Python Modules'],
long_description = "\n".join(pydot.__doc__.split('\n')),
py_modules = ['pydot', 'dot_parser'])

View File

@ -0,0 +1,129 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: workflow.py 1304 2005-09-08 14:35:42Z nicoe $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields, osv
class workflow(osv.osv):
_name = "workflow"
_table = "wkf"
_log_access = False
_columns = {
'name': fields.char('Name', size=64, required=True),
'osv': fields.char('Resource Model', size=64, required=True),
'on_create': fields.boolean('On Create'),
'activities': fields.one2many('workflow.activity', 'wkf_id', 'Activities'),
}
_defaults = {
'on_create': lambda *a: True
}
workflow()
class wkf_activity(osv.osv):
_name = "workflow.activity"
_table = "wkf_activity"
_log_access = False
_columns = {
'name': fields.char('Name', size=64, required=True),
'wkf_id': fields.many2one('workflow', 'Workflow', required=True, select=True),
'split_mode': fields.selection([('XOR', 'Xor'), ('OR','Or'), ('AND','And')], 'Split Mode', size=3, required=True),
'join_mode': fields.selection([('XOR', 'Xor'), ('AND', 'And')], 'Join Mode', size=3, required=True),
'kind': fields.selection([('dummy', 'Dummy'), ('function', 'Function'), ('subflow', 'Subflow'), ('stopall', 'Stop All')], 'Kind', size=64, required=True),
'action': fields.char('Action', size=64),
'flow_start': fields.boolean('Flow Start'),
'flow_stop': fields.boolean('Flow Stop'),
'subflow_id': fields.many2one('workflow', 'Subflow'),
'signal_send': fields.char('Signal (subflow.*)', size=32),
'out_transitions': fields.one2many('workflow.transition', 'act_from', 'Outgoing transitions'),
'in_transitions': fields.one2many('workflow.transition', 'act_to', 'Incoming transitions'),
}
_defaults = {
'kind': lambda *a: 'dummy',
'join_mode': lambda *a: 'XOR',
'split_mode': lambda *a: 'XOR',
}
wkf_activity()
class wkf_transition(osv.osv):
_table = "wkf_transition"
_name = "workflow.transition"
_log_access = False
_rec_name = 'signal' #TODO: pas top mais bon...
_columns = {
'trigger_model': fields.char('Trigger Type', size=128),
'trigger_expr_id': fields.char('Trigger Expr ID', size=128),
'signal': fields.char('Signal (button Name)', size=64),
'role_id': fields.many2one('res.roles', 'Role Required'),
'condition': fields.char('Condition', required=True, size=128),
'act_from': fields.many2one('workflow.activity', 'Source Activity', required=True, select=True),
'act_to': fields.many2one('workflow.activity', 'Destination Activity', required=True, select=True),
}
_defaults = {
'condition': lambda *a: 'True',
}
wkf_transition()
class wkf_instance(osv.osv):
_table = "wkf_instance"
_name = "workflow.instance"
_rec_name = 'res_type'
_log_access = False
_columns = {
'wkf_id': fields.many2one('workflow', 'Workflow', ondelete="cascade"),
'uid': fields.integer('User ID'),
'res_id': fields.integer('Resource ID'),
'res_type': fields.char('Resource Model', size=64),
'state': fields.char('State', size=32),
}
wkf_instance()
class wkf_workitem(osv.osv):
_table = "wkf_workitem"
_name = "workflow.workitem"
_log_access = False
_rec_name = 'state'
_columns = {
'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade"),
'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade"),
'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade"),
'state': fields.char('State', size=64),
}
wkf_workitem()
class wkf_triggers(osv.osv):
_table = "wkf_triggers"
_name = "workflow.triggers"
_log_access = False
_columns = {
'res_id': fields.integer('Resource ID', size=128),
'model': fields.char('Model', size=128),
'instance_id': fields.many2one('workflow.instance', 'Destination Instance', ondelete="cascade"),
'workitem_id': fields.many2one('workflow.workitem', 'Workitem', required=True, ondelete="cascade"),
}
wkf_triggers()

View File

@ -0,0 +1,68 @@
import psycopg
import pydot
wkf_id = 193
db = psycopg.connect('dbname=terp', serialize=0)
cr=db.cursor()
def graph_get(cr, graph, wkf_id, nested=True):
cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
nodes = cr.dictfetchall()
activities = {}
actfrom = {}
actto = {}
for n in nodes:
activities[n['id']] = n
if n['subflow_id'] and nested:
cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
wkfinfo = cr.dictfetchone()
graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=10, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
(s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested)
graph.add_subgraph(graph2)
actfrom[n['id']] = s2
actto[n['id']] = s1
else:
args = {}
if n['flow_start'] or n['flow_stop']:
args['style']='filled'
args['color']='lightgrey'
args['label']=n['name']
if n['action']:
args['label']+='\\n'+n['action']
if n['subflow_id']:
args['shape'] = 'box'
graph.add_node(pydot.Node(n['id'], **args))
actfrom[n['id']] = n['id']
actto[n['id']] = n['id']
cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
transitions = cr.dictfetchall()
for t in transitions:
args = {}
args['label'] = str(t['condition'])
if t['signal']:
args['label'] += '\\n'+str(t['signal'])
args['style'] = 'bold'
if activities[t['act_from']]['split_mode']=='AND':
args['arrowtail']='box'
elif str(activities[t['act_from']]['split_mode'])=='OR ':
args['arrowtail']='inv'
if activities[t['act_to']]['join_mode']=='AND':
args['arrowhead']='crow'
graph.add_edge(pydot.Edge(actfrom[t['act_from']],actto[t['act_to']], fontsize=8, **args))
nodes = cr.dictfetchall()
cr.execute('select id from wkf_activity where flow_start=True limit 1')
start = cr.fetchone()[0]
cr.execute('select id from wkf_activity where flow_stop=True limit 1')
stop = cr.fetchone()[0]
return (start,stop)
cr.execute('select * from wkf where id=%d', (wkf_id,))
wkfinfo = cr.dictfetchone()
graph = pydot.Dot(fontsize = 16, label = "\\n\\nWorkflow: %s\\n OSV: %s"% (wkfinfo['name'],wkfinfo['osv']))
graph_get(cr, graph, wkf_id, True)
graph.write_ps('/tmp/a.ps', prog='dot')

View File

@ -0,0 +1,209 @@
<?xml version="1.0"?>
<terp>
<data>
<menuitem name="Administration/Custom/Low level/Base/Workflows"/>
<!--
================================
Workflows
================================
-->
<record model="ir.ui.view" id="view_workflow_form">
<field name="name">workflow.form</field>
<field name="model">workflow</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Workflow">
<field name="name" select="1"/>
<field name="osv" select="1"/>
<field name="on_create"/>
<separator string="Activities" colspan="4"/>
<field name="activities" colspan="4" nolabel="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_workflow_form">
<field name="name">workflow.form</field>
<field name="res_model">workflow</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_form"/>
</record>
<menuitem
name="Administration/Custom/Low level/Base/Workflows/Workflows"
action="action_workflow_form"
id="menu_workflow"/>
<!--
================================
Activities
================================
-->
<record model="ir.ui.view" id="view_workflow_activity_form">
<field name="name">workflow.activity.form</field>
<field name="model">workflow.activity</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Activity">
<field name="name" colspan="3" select="1"/>
<field name="kind" select="1"/>
<field name="action" colspan="3" select="1"/>
<field name="subflow_id"/>
<field name="signal_send"/>
<newline/>
<field name="flow_start"/>
<field name="flow_stop"/>
<field name="split_mode"/>
<field name="join_mode"/>
<separator string="Outgoing transitions" colspan="4"/>
<field name="out_transitions" colspan="4" nolabel="1">
<tree string="Transitions">
<field name="act_to"/>
<field name="signal"/>
<field name="role_id"/>
<field name="condition"/>
<field name="trigger_model"/>
<field name="trigger_expr_id"/>
</tree>
</field>
<separator string="Incoming transitions" colspan="4"/>
<field name="in_transitions" colspan="4" nolabel="1">
<tree string="Transitions">
<field name="act_from"/>
<field name="signal"/>
<field name="role_id"/>
<field name="condition"/>
<field name="trigger_model"/>
<field name="trigger_expr_id"/>
</tree>
</field>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_workflow_activity_form">
<field name="name">workflow.activity.form</field>
<field name="res_model">workflow.activity</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_activity_form"/>
</record>
<menuitem
name="Administration/Custom/Low level/Base/Workflows/Activities"
action="action_workflow_activity_form"
id="menu_workflow_activity"/>
<!--
================================
Transitions
================================
-->
<record model="ir.ui.view" id="view_workflow_transition_form">
<field name="name">workflow.transition.form</field>
<field name="model">workflow.transition</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Transition">
<field name="act_from" select="1"/>
<field name="act_to" select="1"/>
<field name="condition" colspan="3"/>
<field name="signal"/>
<field name="role_id"/>
<field name="trigger_model"/>
<field name="trigger_expr_id"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_workflow_transition_tree">
<field name="name">workflow.transition.tree</field>
<field name="model">workflow.transition</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Transition">
<field name="act_from"/>
<field name="act_to"/>
<field name="signal"/>
<field name="role_id"/>
<field name="condition"/>
<field name="trigger_model"/>
<field name="trigger_expr_id"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_workflow_transition_form">
<field name="name">workflow.transition.form</field>
<field name="res_model">workflow.transition</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_transition_form"/>
</record>
<menuitem
name="Administration/Custom/Low level/Base/Workflows/Transitions"
action="action_workflow_transition_form"
id="menu_workflow_transition"/>
<!--
================================
Instances
================================
-->
<record model="ir.ui.view" id="view_workflow_instance_form">
<field name="name">workflow.instance.form</field>
<field name="model">workflow.instance</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Workflow Instances">
<field name="wkf_id" select="1"/>
<field name="uid" select="1"/>
<field name="res_id" select="1"/>
<field name="res_type" select="1"/>
<field name="state" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_workflow_instance_form">
<field name="name">workflow.instance.form</field>
<field name="res_model">workflow.instance</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_instance_form"/>
</record>
<menuitem
name="Administration/Custom/Low level/Base/Workflows/Instances"
action="action_workflow_instance_form"
id="menu_workflow_instance"/>
<!--
================================
Workitems
================================
-->
<record model="ir.ui.view" id="view_workflow_workitem_form">
<field name="name">workflow.workitem.form</field>
<field name="model">workflow.workitem</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Workflow Workitems">
<field name="act_id" select="1"/>
<field name="subflow_id" select="1"/>
<field name="inst_id" select="1"/>
<field name="state" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_workflow_workitem_form">
<field name="name">workflow.workitem.form</field>
<field name="res_model">workflow.workitem</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_workitem_form"/>
</record>
<menuitem
name="Administration/Custom/Low level/Base/Workflows/Workitems"
action="action_workflow_workitem_form"
id="menu_workflow_workitem"/>
</data>
</terp>

View File

@ -0,0 +1,31 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import module
import wizard
import report

View File

@ -0,0 +1,274 @@
##############################################################################
#
# Copyright (c) 2005 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import tarfile
import re
import urllib
import os
import tools
from osv import fields, osv
class module_repository(osv.osv):
_name = "ir.module.repository"
_description = "Module Repository"
_columns = {
'name': fields.char('Name', size=128),
'url': fields.char('Url', size=256, required=True),
}
module_repository()
def get_module_info(name):
try:
f = file(os.path.join(tools.config['addons_path'], name, '__terp__.py'), 'r')
data = f.read()
info = eval(data)
f.close()
except:
return {}
return info
class module_category(osv.osv):
_name = "ir.module.category"
_description = "Module Category"
def _module_nbr(self,cr,uid, ids, prop, unknow_none,context):
cr.execute('select category_id,count(*) from ir_module_module where category_id in ('+','.join(map(str,ids))+') or category_id in (select id from ir_module_category where parent_id in ('+','.join(map(str,ids))+')) group by category_id')
result = dict(cr.fetchall())
for id in ids:
cr.execute('select id from ir_module_category where parent_id=%d', (id,))
childs = [c for c, in cr.fetchall()]
result[id] = reduce(lambda x,y:x+y, [result.get(c, 0) for c in childs], result.get(id, 0))
return result
_columns = {
'name': fields.char("Name", size=128, required=True),
'parent_id': fields.many2one('ir.module.category', 'Parent Category', select=True),
'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Parent Category'),
'module_nr': fields.function(_module_nbr, method=True, string='# of Modules', type='integer')
}
_order = 'name'
module_category()
class module(osv.osv):
_name = "ir.module.module"
_description = "Module"
def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}):
res = {}
for m in self.browse(cr, uid, ids):
res[m.id] = get_module_info(m.name).get('version', False)
return res
_columns = {
'name': fields.char("Name", size=128, readonly=True, required=True),
'category_id': fields.many2one('ir.module.category', 'Category', readonly=True),
'shortdesc': fields.char('Short description', size=256, readonly=True),
'description': fields.text("Description", readonly=True),
'author': fields.char("Author", size=128, readonly=True),
'website': fields.char("Website", size=256, readonly=True),
'installed_version': fields.function(_get_installed_version, method=True, string='Installed version', type='char'),
'latest_version': fields.char('Latest version', size=64, readonly=True),
'url': fields.char('URL', size=128, readonly=True),
'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies'),
'state': fields.selection([
('uninstallable','Uninstallable'),
('uninstalled','Not Installed'),
('installed','Installed'),
('to upgrade','To be upgraded'),
('to remove','To be removed'),
('to install','To be installed')
], string='State', readonly=True),
'demo': fields.boolean('Demo data'),
}
_defaults = {
'state': lambda *a: 'uninstalled',
'demo': lambda *a: False,
}
_order = 'name'
def state_change(self, cr, uid, ids, newstate, context={}, level=50):
if level<1:
raise 'Recursion error in modules dependencies !'
ids_dest = []
for module in self.browse(cr, uid, ids):
for dep in module.dependencies_id:
ids2 = self.search(cr, uid, [('name','=',dep.name)])
for id in ids2:
if (id not in ids_dest):
ids_dest.append(id)
if module.state=='uninstalled':
self.write(cr, uid, [module.id], {'state': newstate})
if ids_dest:
self.state_change(cr, uid, ids_dest, newstate, context, level-1)
for module in self.browse(cr, uid, ids):
if module.state!='installed':
demo=True
for dep in module.dependencies_id:
ids2 = self.search(cr, uid, [('name', '=', dep.name)])
for module2 in self.browse(cr, uid, ids2):
demo = demo and module2.demo
self.write(cr, uid, [module.id], {'demo':demo})
return True
def button_install(self, cr, uid, ids, context={}):
return self.state_change(cr, uid, ids, 'to install', context)
def button_install_cancel(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'uninstalled'})
return True
def button_uninstall(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'to remove'})
return True
def button_remove_cancel(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'installed'})
return True
def button_upgrade(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'to upgrade'})
return True
def button_upgrade_cancel(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'installed'})
return True
def button_update_translations(self, cr, uid, ids, context={}):
cr.execute('select code from res_lang where translatable=TRUE')
langs = [l[0] for l in cr.fetchall()]
modules = self.read(cr, uid, ids, ['name'])
for module in modules:
files = get_module_info(module['name']).get('translations', {})
for lang in langs:
if files.has_key(lang):
filepath = files[lang]
# if filepath does not contain :// we prepend the path of the module
if filepath.find('://') == -1:
filepath = os.path.join(tools.config['addons_path'], module['name'], filepath)
tools.trans_load(filepath, lang)
return True
# update the list of available packages
def update_list(self, cr, uid, context={}):
robj = self.pool.get('ir.module.repository')
adp = tools.config['addons_path']
# iterate through installed modules and mark them as being so
for name in os.listdir(adp):
if os.path.isdir(os.path.join(adp, name)):
version = get_module_info(name).get('version', False)
if version:
ids = self.search(cr, uid, [('name','=',name)])
if not ids:
id = self.create(cr, uid, {
'name': name,
'latest_version': version,
'state': 'installed',
})
else:
self.write(cr, uid, ids, {'state': 'installed'})
# make the list of all installable modules
for repository in robj.browse(cr, uid, robj.search(cr, uid, [])):
index_page = urllib.urlopen(repository.url).read()
modules = re.findall('.*<a href="([a-zA-Z0-9.\-]+)_([a-zA-Z0-9.\-]+)\.tar\.gz">.*', index_page)
for name, version in modules:
# TODO: change this using urllib
url = os.path.join(repository.url, name + '_' + version + ".tar.gz")
ids = self.search(cr, uid, [('name','=',name)])
if not ids:
self.create(cr, uid, {
'name': name,
'latest_version': version,
'url': url,
'state': 'uninstalled',
})
else:
for r in self.read(cr, uid, ids, ['latest_version']):
if r['latest_version'] < version:
self.write(cr, uid, [r['id']], {'latest_version': version, 'url':url})
return True
#
# TODO: update dependencies
#
def info_get(self, cr, uid, ids, context={}):
categ_obj = self.pool.get('ir.module.category')
for module in self.browse(cr, uid, ids, context):
url = module.url
adp = tools.config['addons_path']
info = False
if url:
tar = tarfile.open(mode="r|gz", fileobj=urllib.urlopen(url))
for tarinfo in tar:
if tarinfo.name.endswith('__terp__.py'):
info = eval(tar.extractfile(tarinfo).read())
elif os.path.isdir(os.path.join(adp, module.name)):
info = get_module_info(module.name)
if info:
categ = info.get('category', 'Unclassified')
parent = False
for c in categ.split('/'):
ids = categ_obj.search(cr, uid, [('name','=',c), ('parent_id','=',parent)])
if not ids:
parent = categ_obj.create(cr, uid, {'name':c, 'parent_id':parent})
else:
parent = ids[0]
self.write(cr, uid, [module.id], {
'author': info.get('author',False),
'website': info.get('website',False),
'shortdesc': info.get('name',False),
'description': info.get('description',False),
'category_id': parent
})
return True
module()
class module_dependency(osv.osv):
_name = "ir.module.module.dependency"
_description = "Module dependency"
_columns = {
'name': fields.char('Name', size=128),
'module_id': fields.many2one('ir.module.module', 'Module', select=True),
#'module_dest_id': fields.many2one('ir.module.module', 'Module'),
'version_pattern': fields.char('Required Version', size=128),
}
# returns the ids of module version records which match all dependencies
# [version_id, ...]
def resolve(self, cr, uid, ids):
vobj = self.pool.get('ir.module.module.version')
objs = self.browse(cr, uid, ids)
res = {}
for o in objs:
pattern = o.version_pattern and eval(o.version_pattern) or []
print "pattern", pattern
res[o.id] = vobj.search(cr, uid, [('module','=',o.module.id)]+pattern)
#TODO: add smart dependencies resolver here
# it should compute the best version for each module
return [r[0] for r in res.itervalues()]
module_dependency()

View File

@ -0,0 +1,228 @@
##############################################################################
#
# Copyright (c) 2005 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import tarfile
import re
import urllib2
import os
import shutil
from sets import Set
from osv import fields, osv
import tools
class module(osv.osv):
_name = "module.module"
_description = "Module"
def _costs_get(self, cr, uid, ids, prop=None, unknown_none=None, unknown_dict={}):
dossiers = self.browse(cr, uid, ids)
res = {}
for d in dossiers:
costs = [l.amount_costs for l in d.lot_id]
cost_amount = reduce(lambda x, y: x+y, costs, 0.0)
res[d.id] = cost_amount
return res
_columns = {
'name': fields.char("Name", size=128, readonly=True),
'shortdesc': fields.char('Short description', size=256, readonly=True),
'description': fields.text("Description", readonly=True),
'author': fields.char("Author", size=128, readonly=True),
'website': fields.char("Website", size=256, readonly=True),
# 'running_version': fields.function(_get_installed_version, method=True, string='Installed version'),
# 'installed_version': fields.function(_get_installed_version, method=True, string='Installed version'),
'latest_version': fields.many2one('module.module.version', 'Latest version'),
'versions': fields.one2many('module.module.version', 'module', 'Versions', readonly=True),
'state': fields.selection([('uninstalled', 'Uninstalled'), ('preinstall','To install'),('installed','Installed'),('running','Running')], 'State'),
# 'active': fields.boolean('Active'),
}
# update the list of available packages
def update(self, cr, uid, ids, *args):
vobj = self.pool.get('module.module.version')
# update installed_version
# get the index page containing available packages from the server
index_page = urllib2.urlopen('http://www.tinyerp.org/download/modules_test').read()
# print index_page
# parses it
modules = re.findall('.*<a href="([a-zA-Z0-9.\-]+)_([a-zA-Z0-9.\-]+)\.tar\.gz">.*', index_page)
# create module.module records and module.module.version as needed
for name, version in modules:
print "name", name, "version", version
# open module package on the remote server and extract its __terp__.py
url = 'http://www.tinyerp.org/download/modules_test/' + name + '_' + version + ".tar.gz"
tar = tarfile.open(mode="r|gz", fileobj=urllib2.urlopen(url))
info = {}
# we need to go through the whole tar file, because we use a stream and we
# are not allowed to search backward in the stream, so we can't extract one
# particular file directly
for tarinfo in tar:
if tarinfo.name.endswith('__terp__.py'):
info = eval(tar.extractfile(tarinfo).read())
break
tar.close()
print info
ids = self.search(cr, uid, [('name','=',name)])
print ids
if not ids:
id = self.create(cr, uid, {
'name': name,
'shortdesc': info.get('name', False),
'description': info.get('description', False),
'author': info.get('author', False),
'website': info.get('website', False),
'state': 'uninstalled',
})
print "module_id", id
else:
assert len(ids)==1, "There shouldn't be two modules with the same name"
id = ids[0]
version_ids = vobj.search(cr, uid, [('module','=',id),('name','=',version)])
print version_ids
if not version_ids:
version_id = vobj.create(cr, uid, {
'name': version,
'module': id,
'state': 'uninstalled',
})
print "version_id", version_id
# update latest_version
#TODO: compute latest version
self.write(cr, uid, [id], {'latest_version': version_id})
# else:
# assert len(version_ids)==1, "There shouldn't be two versions with the same name"
# version_id = version_ids[0]
return True
def install(self, cr, uid, ids, *args):
objs = self.browse(cr, uid, ids)
vobj = self.pool.get('module.module.version')
# get the id of latest version for each module
version_ids = Set([o.latest_version.id for o in objs])
# for o in objs:
# version_ids.add()
# version_ids = reduce(lambda dic, o: dic.update({o.latest_version.id:True}), objs, {})
print "version_ids", version_ids
# add the list of dependencies
dependencies_ids = vobj.get_dependencies(cr, uid, list(version_ids))
print "depends", dependencies_ids
version_ids.update(dependencies_ids)
# version_ids = reduce(lambda dic, dep: dic.update({dep:True}), dependencies_ids, version_ids)
print "version_ids2", version_ids
# remove existing version of modules
self.remove(cr, uid, ids)
# install all selected modules and their dependencies
vobj.install(cr, uid, list(version_ids))
return True
# remove existing version of modules if they exist
def remove(self, cr, uid, ids, *args):
objs = self.browse(cr, uid, ids)
adp = tools.config['addons_path']
addons = os.listdir(adp)
for o in objs:
if o.name in addons:
shutil.rmtree(os.path.join(adp, o.name))
return True
module()
class module_version(osv.osv):
_name = "module.module.version"
_description = "Module Version"
_columns = {
'name': fields.char('Name', size=64),
'module': fields.many2one('module.module', "Module"),
'dependencies': fields.one2many('module.module.dependency', 'version', 'Dependencies'),
'state': fields.selection([('uninstalled','Uninstalled'), ('preinstall','To install'), ('installed','Installed'), ('running','Running')], 'State'),
}
def install(self, cr, uid, ids, *args):
print "install versions", ids
objs = self.browse(cr, uid, ids)
for o in objs:
# download and unpack to destination folder
url = 'http://www.tinyerp.org/download/modules_test/' + o.module.name + '_' + o.name + ".tar.gz"
tar = tarfile.open(mode="r|gz", fileobj=urllib2.urlopen(url))
for tarinfo in tar:
tar.extract(tarinfo, tools.config['addons_path'])
return True
def get_dependencies(self, cr, uid, ids, *args):
dobj = self.pool.get('module.module.dependency')
print "get_depends", ids
# for each dependency, get dependencies
objs = self.browse(cr, uid, ids)
depends = []
for o in objs:
print "name", o.name
o_depends = dobj.resolve(cr, uid, [d.id for d in o.dependencies])
print "depends", o_depends
depends.extend(o_depends)
# depends.extend([d.id for d in o.dependencies])
print "total depends", depends
# merge the list
# return the list of ids
return depends
module_version()
# a module dependency record represents one dependency of a particular version of a module
# it can depend on a range of version of one module
class module_dependency(osv.osv):
_name = "module.module.dependency"
_description = "Module dependency"
_columns = {
'dependency_for': fields.many2one('module.module.version', 'Version'),
'module': fields.many2one('module.module', 'Module'),
'version_pattern': fields.char('Version pattern', size=128),
}
# returns the ids of module version records which match all dependencies
# [version_id, ...]
def resolve(self, cr, uid, ids):
vobj = self.pool.get('module.module.version')
objs = self.browse(cr, uid, ids)
res = {}
for o in objs:
pattern = o.version_pattern and eval(o.version_pattern) or []
print "pattern", pattern
res[o.id] = vobj.search(cr, uid, [('module','=',o.module.id)]+pattern)
#TODO: add smart dependencies resolver here
# it should compute the best version for each module
return [r[0] for r in res.itervalues()]
module_dependency()

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<terp>
<data>
<!--
<record model="ir.module.repository" id="module_repository_tiny">
<field name="name">Tiny ERP Base Repository</field>
<field name="url">http://tinyerp.org/download/modules/</field>
</record>
-->
</data>
</terp>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<terp>
<data>
<report id="ir_module_reference_print"
string="Technical guide"
model="ir.module.module"
name="ir.module.reference"
rml="base/module/report/ir_module_reference.rml"
auto="False" />
</data>
</terp>

View File

@ -0,0 +1,198 @@
<?xml version="1.0" ?>
<terp>
<data>
#
# Modules Categories
#
<record model="ir.ui.view" id="view_module_category_form">
<field name="name">ir.module.category.form</field>
<field name="model">ir.module.category</field>
<field name="type">form</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<form string="Module Category">
<field name="name" colspan="3"/>
<field name="parent_id" colspan="3"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_module_category_tree">
<field name="name">ir.module.category.tree</field>
<field name="model">ir.module.category</field>
<field name="type">tree</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Module Category">
<field name="name"/>
<field name="module_nr"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_module_category_tree">
<field name="name">ir.module.category</field>
<field name="res_model">ir.module.category</field>
<field name="view_type">tree</field>
<field name="domain">[('parent_id','=',False)]</field>
</record>
<menuitem
name="Administration/Modules Management/Categories of Modules"
action="action_module_category_tree"
/>
#
# Click on a category
#
<record model="ir.actions.act_window" id="action_module_open_categ">
<field name="name">ir.module.module</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('category_id','=',active_id)]</field>
</record>
<record model="ir.values" id="ir_action_module_category">
<field name="key2" eval="'tree_but_open'"/>
<field name="model" eval="'ir.module.category'"/>
<field name="name">Categorized Modules</field>
<field name="value" eval="'ir.actions.act_window,%d'%action_module_open_categ"/>
<field name="object" eval="True"/>
</record>
<!-- Modules -->
<record model="ir.ui.view" id="module_form">
<field name="name">ir.module.module.form</field>
<field name="model">ir.module.module</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Module">
<notebook>
<page string="Module">
<field name="name" select="1"/>
<field name="shortdesc" colspan="3"/>
<field name="description" colspan="3"/>
<field name="installed_version"/>
<field name="latest_version"/>
<field name="author"/>
<field name="website"/>
<field name="url"/>
<field name="demo" readonly="1"/>
<field name="state" readonly="1"/>
<group col="7" colspan="2">
<button string="Update Infos" name="info_get" type="object" states="uninstalled,installed,to upgrade,to remove"/>
<button string="Cancel Install" name="button_install_cancel" type="object" states="to install"/>
<button string="Install" name="button_install" type="object" states="uninstalled"/>
<!--
<button string="Cancel Upgrade" name="button_upgrade_cancel" type="object" states="to upgrade"/>
<button string="Cancel Remove" name="button_remove_cancel" type="object" states="to remove"/>
<button string="Uninstall" name="button_uninstall" type="object" states="installed"/>
-->
<button string="Upgrade" name="button_upgrade" type="object" states="installed"/>
<!--
<button string="Update translations" name="button_update_translations" type="object" states="installed"/>
-->
</group>
</page>
<page string="Dependencies">
<field name="dependencies_id" colspan="4" nolabel="1">
<tree string="Dependencies">
<field name="name"/>
<field name="version_pattern"/>
</tree>
</field>
</page>
</notebook>
</form>
</field>
</record>
<record model="ir.ui.view" id="module_tree">
<field name="name">ir.module.module.tree</field>
<field name="model">ir.module.module</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Module list" colors="blue:state=='to upgrade' or state=='to install';grey:state=='uninstalled' or state=='uninstallable'">
<field name="name"/>
<field name="shortdesc"/>
<field name="author"/>
<field name="installed_version"/>
<field name="latest_version"/>
<field name="state"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_module_tree">
<field name="name">ir.module.module</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain"></field>
</record>
<menuitem name="Administration/Modules Management/Modules" action="open_module_tree"/>
<record model="ir.actions.act_window" id="open_module_tree_install">
<field name="name">ir.module.module</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('state','=','installed')]</field>
</record>
<menuitem name="Administration/Modules Management/Modules/Installed Modules" action="open_module_tree_install"/>
<record model="ir.actions.act_window" id="open_module_tree_uninstall">
<field name="name">ir.module.module</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('state','=','uninstalled')]</field>
</record>
<menuitem name="Administration/Modules Management/Modules/Uninstalled Modules" action="open_module_tree_uninstall"/>
<record model="ir.actions.act_window" id="open_module_tree_upgrade">
<field name="name">ir.module.module</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('state','&lt;&gt;','uninstalled'),('state','&lt;&gt;','installed'),('state','&lt;&gt;','uninstallable'),]</field>
</record>
<menuitem name="Administration/Modules Management/Modules/Modules to be installed, upgraded or removed" action="open_module_tree_upgrade"/>
<record model="ir.ui.view" id="repository_form">
<field name="name">ir.module.repository.form</field>
<field name="model">ir.module.repository</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Repository">
<field name="name" colspan="3" select="1"/>
<field name="url" colspan="3" select="1"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="repository_tree">
<field name="name">ir.module.repository.tree</field>
<field name="model">ir.module.repository</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Repository list">
<field name="name"/>
<field name="url"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_repository_tree">
<field name="name">ir.module.repository</field>
<field name="res_model">ir.module.repository</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<!--
<menuitem
name="Administration/Modules Management/Repositories"
action="open_repository_tree"
id="menu_module_repository_tree"
/>
-->
</data>
</terp>

View File

@ -0,0 +1,76 @@
<?xml version="1.0"?>
<terp>
<data>
<wizard
id="wizard_info_get"
string="Request Info"
model="ir.module.module"
name="module.info_get"/>
<!--
<record model="ir.actions.wizard" id="wizard_update">
<field name="name">Download module list</field>
<field name="wiz_name">module.module.update</field>
</record>
<menuitem
name="Administration/Module Management/Download module list"
action="wizard_update"
type="wizard"
groups="admin"
icon="STOCK_CONVERT"
id="menu_module_update"/>
-->
<record model="ir.actions.wizard" id="wizard_upgrade">
<field name="name">Apply marked changes</field>
<field name="wiz_name">module.upgrade</field>
</record>
<menuitem
name="Administration/Modules Management/Apply Upgrades"
action="wizard_upgrade"
id="menu_wizard_upgrade"
type="wizard"/>
<record model="ir.actions.wizard" id="wizard_lang_install">
<field name="name">Install new language file</field>
<field name="wiz_name">module.lang.install</field>
</record>
<menuitem
name="Administration/Translations/Load a new language"
action="wizard_lang_install"
id="menu_wizard_lang_install"
type="wizard"/>
<record model="ir.actions.wizard" id="wizard_scan_addons">
<field name="name">Scan 'addons' path</field>
<field name="wiz_name">module.module.scan</field>
</record>
<menuitem
name="Administration/Modules Management/Update modules list"
action="wizard_scan_addons"
id="menu_wizard_module_scan"
type="wizard" />
<record model="ir.actions.wizard" id="wizard_lang_export">
<field name="name">Export a language</field>
<field name="wiz_name">module.lang.export</field>
</record>
<menuitem
name="Administration/Translations/Export a language"
action="wizard_lang_export"
id="menu_wizard_lang_export"
type="wizard"/>
<record model="ir.actions.wizard" id="wizard_lang_import">
<field name="name">Import a language</field>
<field name="wiz_name">module.lang.import</field>
</record>
<menuitem
name="Administration/Translations/Import a language"
action="wizard_lang_import"
id="menu_wizard_lang_import"
type="wizard"/>
</data>
</terp>

View File

@ -0,0 +1,29 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import ir_module_reference_print

View File

@ -0,0 +1,173 @@
<?xml version="1.0"?>
<document filename="test.pdf">
<template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20">
<pageTemplate id="first">
<frame id="first" x1="42.0" y1="42.0" width="511" height="758"/>
</pageTemplate>
</template>
<stylesheet>
<blockTableStyle id="Standard_Outline">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
</blockTableStyle>
<blockTableStyle id="Table1">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<blockBackground colorName="#e6e6e6" start="0,0" stop="0,0"/>
<blockBackground colorName="#e6e6e6" start="1,0" stop="1,0"/>
<blockBackground colorName="#e6e6e6" start="2,0" stop="2,0"/>
<blockBackground colorName="#e6e6e6" start="0,1" stop="0,1"/>
<blockBackground colorName="#e6e6e6" start="1,1" stop="1,1"/>
<blockBackground colorName="#e6e6e6" start="2,1" stop="2,1"/>
</blockTableStyle>
<blockTableStyle id="Tableau1">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="GRID" colorName="black"/>
<blockBackground colorName="#ff6633" start="0,0" stop="0,0"/>
</blockTableStyle>
<blockTableStyle id="Tableau2">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<blockBackground colorName="#e6e6e6" start="0,0" stop="0,0"/>
<blockBackground colorName="#e6e6e6" start="1,0" stop="1,0"/>
<blockBackground colorName="#e6e6e6" start="0,1" stop="0,1"/>
<blockBackground colorName="#e6e6e6" start="1,1" stop="1,1"/>
</blockTableStyle>
<blockTableStyle id="Tableau3">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="GRID" colorName="black"/>
<blockBackground colorName="#ffcc99" start="0,0" stop="0,0"/>
</blockTableStyle>
<blockTableStyle id="Tableau4">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
</blockTableStyle>
<initialize>
<paraStyle name="all" alignment="justify"/>
</initialize>
<paraStyle name="P1" fontName="Times-Roman" fontSize="20.0" leading="25" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P2" fontName="Times-Roman" fontSize="10.0" leading="13" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P3" fontName="Times-Roman" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P4" fontName="Times-Roman" fontSize="11.0" leading="14" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P5" fontName="Times-Roman" fontSize="16.0" leading="20" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P6" fontName="Times-Roman"/>
<paraStyle name="P7" fontName="Times-Roman" fontSize="15.0" leading="19" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P8" fontName="Times-Roman" fontSize="11.0" leading="14" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P9" fontName="Times-Roman" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Standard" fontName="Times-Roman"/>
<paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Table Contents" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Caption" fontName="Times-Roman" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="Index" fontName="Times-Roman"/>
</stylesheet>
<story>
<para style="Standard">
<font color="white"> </font>
</para>
<blockTable colWidths="139.0,220.0,152.0" repeatRows="1" style="Table1">
<tr>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P1">Reference Guide</para>
</td>
<td>
<para style="P2">
<font color="white"> </font>
</para>
</td>
</tr>
<tr>
<td>
<para style="Table Contents">[[ company.name ]]</para>
</td>
<td>
<para style="P3">Introspection report on objects</para>
</td>
<td>
<para style="P4">Printed: [[ time.strftime('%y-%m-%d')]]</para>
</td>
</tr>
</blockTable>
<para style="Standard">
<font color="white"> </font>
</para>
<section>
<para style="Text body">[[ repeatIn(objects, 'module') ]]</para>
<blockTable colWidths="510.0" repeatRows="1" style="Tableau1">
<tr>
<td>
<para style="P5">Module: [[ module.name ]]</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="276.0,234.0" repeatRows="1" style="Tableau2">
<tr>
<td>
<para style="Standard">Name: [[ module.shortdesc]]</para>
</td>
<td>
<para style="Standard">Version: [[module.latest_version]]</para>
</td>
</tr>
<tr>
<td>
<para style="Standard">Directory: [[ module.name ]]</para>
</td>
<td>
<para style="Standard">Web: [[ module.website ]]</para>
</td>
</tr>
</blockTable>
<para style="P6">[[ module.description ]]</para>
<section>
<para style="Standard">[[ repeatIn(findobj(module.name) ,'object') ]]</para>
<blockTable colWidths="510.0" repeatRows="1" style="Tableau3">
<tr>
<td>
<para style="P7">Object: [[ object.name ]]</para>
<pre style="P8">[[ objdoc(object.model) ]]</pre>
</td>
</tr>
</blockTable>
<blockTable colWidths="113.0,397.0" repeatRows="1" style="Tableau4">
<tr>
<td>
<para style="P9"><font face="Times-Roman">[[ repeatIn(findflds(object.model), 'field') ]]</font> [[ field[0] ]]</para>
</td>
<td>
<para style="Standard">
<font face="Times-Roman">[[ field[1].get('string', 'Unknown') ]], [[ field[1]['type'] ]] [[field[1].get('required',False) and ', required']] [[field[1].get('readonly',False) and ', readonly']] </font>
</para>
<para style="Standard">[[ field[1].get('help', '') ]]</para>
</td>
</tr>
</blockTable>
<para style="Standard">
<font color="white"> </font>
</para>
</section>
<para style="Standard">
<font color="white"> </font>
</para>
<para style="Standard">
<font color="white"> </font>
</para>
<para style="Standard">
<font color="white"> </font>
</para>
</section>
<para style="Standard">
<font color="white"> </font>
</para>
</story>
</document>

Binary file not shown.

View File

@ -0,0 +1,60 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import time
from report import report_sxw
class ir_module_reference_print(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(ir_module_reference_print, self).__init__(cr, uid, name, context)
self.localcontext.update({
'time': time,
'findobj': self._object_find,
'objdoc': self._object_doc,
'findflds': self._fields_find,
})
def _object_doc(self, obj):
modobj = self.pool.get(obj)
return modobj.__doc__
def _object_find(self, module):
modobj = self.pool.get('ir.model')
if module=='base':
ids = modobj.search(self.cr, self.uid, [('model','=like','res%')])
ids += modobj.search(self.cr, self.uid, [('model','=like','ir%')])
else:
ids = modobj.search(self.cr, self.uid, [('model','=like',module+'%')])
return modobj.browse(self.cr, self.uid, ids)
def _fields_find(self, obj):
modobj = self.pool.get(obj)
res = modobj.fields_get(self.cr, self.uid).items()
return res
report_sxw.report_sxw('report.ir.module.reference', 'ir.module.module', 'addons/base/module/report/ir_module_reference.rml', parser=ir_module_reference_print)

View File

@ -0,0 +1,35 @@
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard_install_module
import wizard_update_module
import wizard_module_upgrade
import wizard_module_info_get
import wizard_module_lang_install
import add_new
import wizard_export_lang
import wizard_import_lang

View File

@ -0,0 +1,100 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be)
#
# $Id$
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contact a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import re
import glob
import time
import imp
import tools
import wizard
import pooler
module_name_re = re.compile('.*addons.(.*?).__terp__.py$')
_info_arch = '''<?xml version="1.0"?>
<form string="Scan for new modules">
<label string="This function will check if you installed new modules in the 'addons' path of your server installation." colspan="4" />
</form>
'''
_info_fields = {}
def get_module_info(name):
try:
f = file(os.path.join(tools.config['addons_path'], name, '__terp__.py'), 'r')
data = f.read()
info = eval(data)
f.close()
except:
return {}
return info
class wizard_install_module(wizard.interface):
def watch_dir(self, cr, uid, data, context):
mod_obj = pooler.get_pool(cr.dbname).get('ir.module.module')
all_mods = mod_obj.read(cr, uid, mod_obj.search(cr, uid, []), ['name', 'state'])
known_modules = set([x['name'] for x in all_mods])
ls_ad = glob.glob(os.path.join(tools.config['addons_path'], '*', '__terp__.py'))
modules = set([module_name_re.match(name).group(1) for name in ls_ad])
new_modules = modules - known_modules
for module in new_modules:
terp = get_module_info(module)
if not terp.get('installable', True):
continue
imp.load_module(module, *imp.find_module(module))
mod_id = mod_obj.create(cr, uid, {
'name': module,
'state': 'uninstalled',
'description': terp.get('description', ''),
'shortdesc': terp.get('name', ''),
'author': terp.get('author', 'Unknown')})
dependencies = terp.get('depends', [])
for d in dependencies:
cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d))
for module in known_modules:
terp = get_module_info(module)
if terp.get('installable', True):
for mod in all_mods:
if mod['name'] == module and mod['state'] == 'uninstallable':
mod_obj.write(cr, uid, [mod['id']], {'state': 'uninstalled'})
return {}
states = {
'init': {
'actions': [],
'result': {'type':'form', 'arch': _info_arch, 'fields': _info_fields, 'state':[('end','Cancel','gtk-cancel'),('addmod','Check new modules','gtk-ok')]}
},
'addmod': {
'actions': [watch_dir],
'result': {'type':'state', 'state':'end'}
},
}
wizard_install_module('module.module.scan')

View File

@ -0,0 +1,91 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import tools
import base64
import StringIO
import csv
import pooler
view_form_init="""<?xml version="1.0"?>
<form string="Export language">
<image name="gtk-info" size="64" colspan="2"/>
<group colspan="2" col="4">
<separator string="Export translation file" colspan="4"/>
<label align="0.0" string="Choose a language to export:" colspan="4"/>
<field name="lang" colspan="4"/>
</group>
</form>"""
view_form_finish="""<?xml version="1.0"?>
<form string="Export language">
<image name="gtk-info" size="64" colspan="2"/>
<group colspan="2" col="4">
<separator string="Export done" colspan="4"/>
<field name="data" readonly="1" colspan="3"/>
<label align="0.0" string="Save this document to a .CSV file and open it with\n your favourite spreadsheet software. The file\n encoding is UTF-8. You have to translate the latest\n column before reimporting it." colspan="4"/>
</group>
</form>"""
class wizard_export_lang(wizard.interface):
def _get_language(self, cr, uid, context):
lang_obj=pooler.get_pool(cr.dbname).get('res.lang')
ids=lang_obj.search(cr, uid, [('active', '=', True),])
langs=lang_obj.browse(cr, uid, ids)
return [(lang.code, lang.translatable and lang.name or 'New language') for lang in langs]
def _get_file(self, cr, uid, data, context):
file=tools.trans_generate(data['form']['lang'], 'all')
buf=StringIO.StringIO()
writer=csv.writer(buf)
for row in file:
writer.writerow(row)
del file
out=base64.encodestring(buf.getvalue())
buf.close()
return {'data': out}
fields_form={
'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,},
}
fields_form_finish={
'data': {'string':'File', 'type':'binary', 'readonly': True,},
}
states={
'init':{
'actions':[],
'result':{'type':'form', 'arch':view_form_init, 'fields': fields_form, 'state':[('end', 'Cancel', 'gtk-cancel'),('finish', 'Ok', 'gtk-ok')]}
},
'finish':{
'actions':[_get_file],
'result':{'type':'form', 'arch':view_form_finish, 'fields': fields_form_finish, 'state':[('end', 'Close', 'gtk-cancel')]}
},
}
wizard_export_lang('module.lang.export')

View File

@ -0,0 +1,75 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import tools
import base64
import pooler
view_form="""<?xml version="1.0"?>
<form string="Import language">
<image name="gtk-info" size="64" colspan="2"/>
<group colspan="2" col="4">
<separator string="Import new language" colspan="4"/>
<field name="name"/>
<field name="code"/>
<field name="data" colspan="3"/>
<label string="You have to import a .CSV file wich is encoded in UTF-8.\nPlease check that the first line of your file is:" colspan="4" align="0.0"/>
<label string="type,name,res_id,src,value" colspan="4"/>
</group>
</form>"""
class wizard_import_lang(wizard.interface):
def _import_lang(self, cr, uid, data, context):
form=data['form']
lang_obj=pooler.get_pool(cr.dbname).get('res.lang')
ids=lang_obj.search(cr, uid, [('code', '=', form['code'])])
if ids:
lang_obj.write(cr, uid, ids, {'name': form['name']})
else:
lang_obj.create(cr, uid, {'code': form['code'], 'name': form['name']})
buf=base64.decodestring(data['form']['data']).split('\n')
tools.trans_load_data(cr.dbname, buf, data['form']['code'])
return {}
fields_form={
'name':{'string':'Language name', 'type':'char', 'size':64, 'required':True},
'code':{'string':'Code (eg:en_US)', 'type':'char', 'size':5, 'required':True},
'data':{'string':'File', 'type':'binary', 'required':True},
}
states={
'init':{
'actions':[],
'result':{'type':'form', 'arch':view_form, 'fields':fields_form, 'state':[('end', 'Cancel', 'gtk-cancel'), ('finish', 'Ok', 'gtk-ok')]}
},
'finish':{
'actions':[],
'result':{'type':'action', 'action':_import_lang, 'state':'end'}
},
}
wizard_import_lang('module.lang.import')

View File

@ -0,0 +1,67 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import netsvc
#TODO: upgraded modules
#TODO: removed modules
additional_changes_form = '''<?xml version="1.0"?>
<form string="Additional modules">
<label string="The following additional modules need to be installed:"/>
<newline/>
<field name="additional"/>
</form>'''
additional_changes_fields = {
'additional': {'string':'Additional modules', 'type':'one2many', 'relation':'ir.module.module', 'readonly':True},
}
class wizard_install_module(wizard.interface):
def _get_value(self, cr, uid, data, context):
service = netsvc.LocalService("object_proxy")
extra = service.execute(cr.dbname, uid, 'ir.module.module', 'get_extra_modules', data['ids'])
return {'additional': extra}
def _install_module(self, cr, uid, data, context):
service = netsvc.LocalService("object_proxy")
res = service.execute(cr.dbname, uid, 'ir.module.module', 'install', data['ids'])
return {}
states = {
'init': {
'actions': [_get_value],
'result': {'type':'form', 'arch':additional_changes_form, 'fields':additional_changes_fields, 'state':[('install','Install'), ('end','Cancel')]}
},
'install': {
'actions': [_install_module],
'result': {'type':'state', 'state':'end'}
},
}
wizard_install_module('module.module.install')

View File

@ -0,0 +1,46 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import netsvc
class wizard_info_get(wizard.interface):
def _update_module(self, cr, uid, data, context):
service = netsvc.LocalService("object_proxy")
service.execute(cr.dbname, uid, 'ir.module.module', 'info_get', data['ids'])
return {}
states = {
'init': {
'actions': [_update_module],
'result': {'type':'state', 'state':'end'}
},
}
wizard_info_get('module.info_get')

View File

@ -0,0 +1,83 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import tools
view_form_end = """<?xml version="1.0"?>
<form string="Language file loaded.">
<image name="gtk-info" size="64" colspan="2"/>
<group colspan="2" col="4">
<separator string="Installation done" colspan="4"/>
<label align="0.0" string="The selected language has been successfully installed.\nYou must change the preferences of the user and open a new menu to view changes." colspan="4"/>
</group>
</form>"""
view_form = """<?xml version="1.0"?>
<form string="System Upgrade">
<image name="gtk-info" size="64" colspan="2"/>
<group colspan="2" col="4">
<separator string="System Upgrade" colspan="4"/>
<label align="0.0" string="Choose a language to install:" colspan="4"/>
<field name="lang" colspan="4"/>
<label align="0.0" string="Note that this operation may take a few minutes." colspan="4"/>
</group>
</form>"""
class wizard_lang_install(wizard.interface):
def _lang_install(self, cr, uid, data, context):
print cr, uid, data, context
lang = data['form']['lang']
if lang and lang != 'en_EN':
filename = tools.config["root_path"] + "/i18n/" + lang + ".csv"
tools.trans_load(cr.dbname, filename, lang)
return {}
def _get_language(sel, cr, uid, context):
return tools.scan_languages()
fields_form = {
'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,
},
}
states = {
'init': {
'actions': [],
'result': {'type':'form', 'arch':view_form, 'fields': fields_form, 'state':[('end','Cancel','gtk-cancel'),('start','Start installation','gtk-ok')]}
},
'start': {
'actions': [_lang_install],
'result': {'type':'form', 'arch':view_form_end, 'fields': {}, 'state':[('end','Ok','gtk-ok')]}
},
}
wizard_lang_install('module.lang.install')

View File

@ -0,0 +1,81 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import pooler
view_form_end = """<?xml version="1.0"?>
<form string="System upgrade done">
<separator string="System upgrade done"/>
<label align="0.0" string="The modules have been upgraded / installed !" colspan="4"/>
<label align="0.0" string="You may have to reinstall some language pack." colspan="4"/>
<label align="0.0" string="We suggest you to close all tabs and open a new menu window (Ctrl T)." colspan="4"/>
</form>"""
view_form = """<?xml version="1.0"?>
<form string="System Upgrade">
<image name="gtk-info" size="64" colspan="2"/>
<group colspan="2" col="4">
<label align="0.0" string="Your system will be upgraded." colspan="4"/>
<label align="0.0" string="Note that this operation my take a few minutes." colspan="4"/>
<separator string="Modules to update"/>
<field name="module_info" nolabel="1" colspan="4"/>
</group>
</form>"""
view_field = {
"module_info": {'type':'text', 'string':'Modules', 'readonly':True}
}
class wizard_info_get(wizard.interface):
def _get_install(self, cr, uid, data, context):
pool=pooler.get_pool(cr.dbname)
ids = pool.get('ir.module.module').search(cr, uid, [
('state','<>','uninstalled'),
('state','<>','installed'),
('state','<>','uninstallable')])
res = pool.get('ir.module.module').read(cr, uid, ids, ['name','state'], context)
return {'module_info':'\n'.join(map(lambda x: x['name']+' : '+x['state'], res))}
def _upgrade_module(self, cr, uid, data, context):
(db, pool)=pooler.restart_pool(cr.dbname, update_module=True)
return {}
states = {
'init': {
'actions': [_get_install],
'result': {'type':'form', 'arch':view_form, 'fields': view_field, 'state':[('end','Cancel','gtk-cancel'),('start','Start Upgrade','gtk-ok')]}
},
'start': {
'actions': [_upgrade_module],
'result': {'type':'form', 'arch':view_form_end, 'fields': {}, 'state':[('end','Close','gtk-close')]}
},
}
wizard_info_get('module.upgrade')

View File

@ -0,0 +1,61 @@
# -*- coding: iso-8859-1 -*-
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import netsvc
class wizard_update_module(wizard.interface):
def _update_module(self, cr, uid, data, context):
service = netsvc.LocalService("object_proxy")
service.execute(cr.dbname, uid, 'ir.module.module', 'update_list')
return {}
def _action_module_open(self, cr, uid, data, context):
return {
'domain': "[]",
'name': 'Open Module List',
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'ir.module.module',
'view_id': False,
'type': 'ir.actions.act_window'
}
states = {
'init': {
'actions': [_update_module],
'result': {'type':'state', 'state':'open_window'}
},
'open_window': {
'actions': [],
'result': {'type': 'action', 'action': _action_module_open, 'state':'end'}
}
}
wizard_update_module('module.module.update')

View File

@ -0,0 +1,246 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<xsl:apply-templates select="report"/>
</xsl:template>
<xsl:template match="report">
<document filename="example_5.pdf">
<template leftMargin="1.5cm" rightMargin="1.5cm" topMargin="1.5cm" bottomMargin="1.5cm" title="Reporting" author="Generated by Tiny ERP, Fabien Pinckaers">
<xsl:attribute name="pageSize">
<xsl:value-of select="/report/config/pageSize"/>
</xsl:attribute>
<pageTemplate id="first">
<pageGraphics>
<drawCentredString>
<xsl:attribute name="x">
<xsl:value-of select="/report/config/pageWidth div 2"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="/report/config/pageHeight - 56.69"/>
</xsl:attribute>
<xsl:value-of select="config/report-header"/>
</drawCentredString>
<fill color="(0.2,0.2,0.2)"/>
<setFont name="Helvetica" size="10"/>
<drawCentredString y="10mm">
<xsl:attribute name="x">
<xsl:value-of select="/report/config/pageWidth div 2"/>
</xsl:attribute>
<xsl:value-of select="config/report-footer"/>
</drawCentredString>
<fill color="(0.969,0.2,0.2)"/>
<setFont name="Helvetica" size="8"/>
<drawString x="1.5cm">
<xsl:attribute name="y">
<xsl:value-of select="/report/config/pageHeight - 56.69"/>
</xsl:attribute><xsl:text>Tiny ERP</xsl:text>
</drawString>
<fill color="(0.2,0.2,0.2)"/>
<drawRightString>
<xsl:attribute name="x">
<xsl:value-of select="/report/config/pageWidth - 45"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="/report/config/pageHeight - 56.69"/>
</xsl:attribute><xsl:value-of select="/report/config/date"/>
</drawRightString>
</pageGraphics>
<frame id="column" x1="1.5cm" y1="1.5cm">
<xsl:attribute name="width">
<xsl:value-of select="/report/config/pageWidth - 85"/>
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of select="/report/config/pageHeight - 100"/>
</xsl:attribute>
</frame>
</pageTemplate>
</template>
<stylesheet>
<paraStyle name="sum" fontName="Helvetica" textColor="green"/>
<paraStyle name="sum_float" fontName="Helvetica" alignment="right" textColor="green"/>
<paraStyle name="sum_end" fontName="Helvetica" textColor="red"/>
<paraStyle name="sum_float_end" fontName="Helvetica" alignment="right" textColor="red"/>
<blockTableStyle id="table">
<blockValign value="TOP"/>
<blockFont name="Helvetica" size="12" start="0,0" stop="-1,0"/>
<blockBackground colorName="(0.8,0.8,0.8)" start="0,0" stop="-1,0"/>
<lineStyle kind="GRID" colorName="lightgrey" thickness="0.3"/>
<lineStyle kind="LINEBELOW" colorName="black" thickness="1.5" start="0,0" stop="-1,0"/>
<lineStyle kind="LINEABOVE" colorName="black" thickness="1.5" start="0,0" stop="-1,0"/>
</blockTableStyle>
</stylesheet>
<story>
<blockTable style="table">
<xsl:attribute name="colWidths">
<xsl:value-of select="/report/config/tableSize"/>
</xsl:attribute>
<xsl:apply-templates select="header"/>
<xsl:apply-templates select="group"/>
<xsl:if test="group//@sum">
<tr>
<xsl:for-each select="group[position()=1]/record[position()=1]/field">
<xsl:choose>
<xsl:when test="position()=1">
<td><para style="sum_end">SUM</para></td>
</xsl:when>
<xsl:when test="@sum">
<xsl:variable name="ici">
<xsl:value-of select="@id"/>
</xsl:variable>
<td><para style="sum_float_end"><xsl:value-of select="sum(../../../group/record/field[@id=$ici])"/></para></td>
</xsl:when>
<xsl:otherwise>
<td/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:if>
<xsl:if test="group//@count">
<tr>
<xsl:for-each select="group[position()=1]/record[position()=1]/field">
<xsl:choose>
<xsl:when test="position()=1">
<td><para style="sum_end">#</para></td>
</xsl:when>
<xsl:when test="@count">
<xsl:variable name="ici">
<xsl:value-of select="@id"/>
</xsl:variable>
<td><para style="sum_float_end"><xsl:value-of select="count(../../../group/record/field[@id=$ici])"/></para></td>
</xsl:when>
<xsl:otherwise>
<td/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:if>
<xsl:if test="group//@avg">
<tr>
<xsl:for-each select="group[position()=1]/record[position()=1]/field">
<xsl:choose>
<xsl:when test="position()=1">
<td><para style="sum_end">AVG</para></td>
</xsl:when>
<xsl:when test="@avg">
<xsl:variable name="ici">
<xsl:value-of select="@id"/>
</xsl:variable>
<td><para style="sum_float_end"><xsl:value-of select="sum(../../../group/record/field[@id=$ici]) div count(../../../group/record/field[@id=$ici])"/></para></td>
</xsl:when>
<xsl:otherwise>
<td/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:if>
</blockTable>
</story>
</document>
</xsl:template>
<xsl:template match="header">
<tr>
<xsl:apply-templates select="field"/>
</tr>
</xsl:template>
<xsl:template match="group">
<xsl:if test="not(/report/config/totalonly)">
<xsl:apply-templates select="record"/>
</xsl:if>
<xsl:if test="/report/config/groupby">
<!-- SUM -->
<xsl:if test="//@sum">
<tr>
<xsl:for-each select="record[position()=1]/field">
<xsl:choose>
<xsl:when test="/report/config/groupby = @id">
<td><para style="sum"><xsl:value-of select="."/> (SUM)</para></td>
</xsl:when>
<xsl:when test="@sum">
<xsl:variable name="ici">
<xsl:value-of select="@id"/>
</xsl:variable>
<td><para style="sum_float"><xsl:value-of select="sum(../../record/field[@id=$ici])"/></para></td>
</xsl:when>
<xsl:otherwise>
<td/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:if>
<!-- COUNT -->
<xsl:if test="//@count">
<tr>
<xsl:for-each select="record[position()=1]/field">
<xsl:choose>
<xsl:when test="/report/config/groupby = @id">
<td><para style="sum"><xsl:value-of select="."/> (#)</para></td>
</xsl:when>
<xsl:when test="@count">
<xsl:variable name="ici">
<xsl:value-of select="@id"/>
</xsl:variable>
<td><para style="sum_float"><xsl:value-of select="count(../../record/field[@id=$ici])"/></para></td>
</xsl:when>
<xsl:otherwise>
<td/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:if>
<!-- AVG -->
<xsl:if test="//@avg">
<tr>
<xsl:for-each select="record[position()=1]/field">
<xsl:choose>
<xsl:when test="/report/config/groupby = @id">
<td><para style="sum"><xsl:value-of select="."/> (AVG)</para></td>
</xsl:when>
<xsl:when test="@avg">
<xsl:variable name="ici">
<xsl:value-of select="@id"/>
</xsl:variable>
<td><para style="sum_float"><xsl:value-of select="sum(../../record/field[@id=$ici]) div count(../../record/field[@id=$ici])"/></para></td>
</xsl:when>
<xsl:otherwise>
<td/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template match="record">
<tr>
<xsl:apply-templates select="field"/>
</tr>
</xsl:template>
<xsl:template match="field">
<xsl:choose>
<xsl:when test="@level">
<td><pre><xsl:value-of select="@level"/><xsl:value-of select="."/></pre></td>
</xsl:when>
<xsl:otherwise>
<td><para><xsl:value-of select="."/></para></td>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,36 @@
<?xml version = '1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:variable name="signature" select="//corporate-header/signature"/>
<xsl:variable name="title">Tiny ERP Report</xsl:variable>
<xsl:variable name="leftMargin">1cm</xsl:variable>
<xsl:variable name="rightMargin">1cm</xsl:variable>
<xsl:variable name="topMargin">1cm</xsl:variable>
<xsl:variable name="bottomMargin">1cm</xsl:variable>
<xsl:variable name="pageSize">21cm,29.7cm</xsl:variable>
<xsl:variable name="page_format">a4_letter</xsl:variable>
<xsl:template name="first_page_frames">
<frame id="column" x1="1.5cm" y1="1.5cm">
<xsl:attribute name="width">
<xsl:value-of select="/report/config/PageWidth - 85"/>
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of select="/report/config/PageHeight - 100"/>
</xsl:attribute>
</frame>
</xsl:template>
<xsl:template name="other_pages_frames">
<frame id="column" x1="1.5cm" y1="1.5cm">
<xsl:attribute name="width">
<xsl:value-of select="/report/config/PageWidth - 85"/>
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of select="/report/config/PageHeight - 100"/>
</xsl:attribute>
</frame>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:import href="../../base/report/custom_default.xsl"/>
<xsl:import href="../../base/report/custom_rml.xsl"/>
<xsl:template match="/">
<xsl:call-template name="rml">
<xsl:with-param name="pageSize" select="report/config/PageSize"/>
<xsl:with-param name="page_format" select="report/config/PageFormat"/>
</xsl:call-template>
</xsl:template>
<!-- stylesheet -->
<xsl:template name="stylesheet">
<paraStyle name="title" fontName="Helvetica-Bold" fontSize="22" alignment="center"/>
<blockTableStyle id="products">
<blockBackground colorName="grey" start="0,0" stop="-1,0"/>
<blockValign value="TOP"/>
<blockAlignment value="RIGHT"/>
<lineStyle kind="GRID" colorName="black"/>
</blockTableStyle>
</xsl:template>
<xsl:template name="story">
<xsl:apply-templates select="report"/>
</xsl:template>
<xsl:template match="report">
<xsl:apply-templates select="config"/>
<!--<setNextTemplate name="other_pages"/>-->
<blockTable style="products">
<xsl:if test="string-length(./config/tableSize)&gt;1">
<xsl:attribute name="colWidths">
<xsl:value-of select="./config/tableSize"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="header"/>
<xsl:apply-templates select="lines"/>
</blockTable>
</xsl:template>
<xsl:template match="config">
<para style="title">
<xsl:value-of select="report-header"/>
</para>
<spacer length="1cm" width="2mm"/>
</xsl:template>
<xsl:template match="header">
<tr>
<xsl:for-each select="field">
<td>
<para>
<xsl:value-of select="."/>
</para>
</td>
</xsl:for-each>
</tr>
</xsl:template>
<xsl:template match="lines">
<xsl:apply-templates select="row"/>
</xsl:template>
<xsl:template match="row">
<tr>
<xsl:apply-templates select="col"/>
</tr>
</xsl:template>
<xsl:template match="col">
<td>
<xsl:choose>
<xsl:when test="@para='yes'">
<xsl:choose>
<xsl:when test="@tree='yes'">
<para>
<xsl:attribute name="leftIndent"><xsl:value-of select="@space"/></xsl:attribute>
<xsl:value-of select="."/>
</para>
</xsl:when>
<xsl:otherwise>
<para>
<xsl:value-of select="."/>
</para>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xpre>
<xsl:value-of select="."/>
</xpre>
</xsl:otherwise>
</xsl:choose>
</td>
</xsl:template>
<!-- <xsl:template match="col">
<td>
<xsl:if test="@tree='yes'">
<xsl:choose>
<xsl:when test="@para='yes'">
<para>
<xsl:attribute name="leftIndent"><xsl:value-of select="@space"/></xsl:attribute>
<xsl:value-of select="."/>
</para>
</xsl:when>
<xsl:otherwise>
<xpre>
<xsl:value-of select="."/>
</xpre>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="@tree!='yes'">
<xpre>
<xsl:value-of select="."/>
</xpre>
</xsl:if>
</td>
</xsl:template>
-->
</xsl:stylesheet>

View File

@ -0,0 +1,62 @@
<?xml version = '1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template name="first_page_graphics_report"/>
<xsl:template name="other_pages_graphics_report"/>
<xsl:template name="rml">
<document>
<template author="Generated by Tiny ERP, Fabien Pinckaers">
<xsl:attribute name="pageSize">
<xsl:value-of select="$pageSize"/>
</xsl:attribute>
<xsl:attribute name="leftMargin">
<xsl:value-of select="$leftMargin"/>
</xsl:attribute>
<xsl:attribute name="rightMargin">
<xsl:value-of select="$rightMargin"/>
</xsl:attribute>
<xsl:attribute name="topMargin">
<xsl:value-of select="$topMargin"/>
</xsl:attribute>
<xsl:attribute name="bottomMargin">
<xsl:value-of select="$bottomMargin"/>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="$title"/>
</xsl:attribute>
<pageTemplate id="first_page">
<pageGraphics>
<xsl:call-template name="first_page_graphics_report"/>
</pageGraphics>
<xsl:call-template name="first_page_frames"/>
</pageTemplate>
<pageTemplate id="other_pages">
<pageGraphics>
<xsl:call-template name="other_pages_graphics_report"/>
</pageGraphics>
<xsl:call-template name="other_pages_frames"/>
</pageTemplate>
</template>
<stylesheet>
<xsl:call-template name="stylesheet"/>
</stylesheet>
<story>
<xsl:call-template name="story"/>
</story>
</document>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,70 @@
<?xml version = '1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template name="first_page_graphics_report"/>
<xsl:template name="other_pages_graphics_report"/>
<!--
<xsl:template name="first_page_graphics_corporation"/>
<xsl:template name="other_pages_graphics_corporation"/>
<xsl:template name="first_page_frames"/>
<xsl:template name="other_pages_frames"/>
-->
<xsl:template name="rml">
<document>
<template author="Generated by Tiny ERP, Fabien Pinckaers">
<xsl:attribute name="pageSize">
<xsl:value-of select="$pageSize"/>
</xsl:attribute>
<xsl:attribute name="leftMargin">
<xsl:value-of select="$leftMargin"/>
</xsl:attribute>
<xsl:attribute name="rightMargin">
<xsl:value-of select="$rightMargin"/>
</xsl:attribute>
<xsl:attribute name="topMargin">
<xsl:value-of select="$topMargin"/>
</xsl:attribute>
<xsl:attribute name="bottomMargin">
<xsl:value-of select="$bottomMargin"/>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="$title"/>
</xsl:attribute>
<pageTemplate id="first_page">
<pageGraphics>
<xsl:call-template name="first_page_graphics_corporation"/>
<xsl:call-template name="first_page_graphics_report"/>
</pageGraphics>
<xsl:call-template name="first_page_frames"/>
</pageTemplate>
<pageTemplate id="other_pages">
<pageGraphics>
<xsl:call-template name="other_pages_graphics_corporation"/>
<xsl:call-template name="other_pages_graphics_report"/>
</pageGraphics>
<xsl:call-template name="other_pages_frames"/>
</pageTemplate>
</template>
<stylesheet>
<xsl:call-template name="stylesheet"/>
</stylesheet>
<story>
<xsl:call-template name="story"/>
</story>
</document>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,38 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import tools
import partner
import res_currency
import res_company
import res_user
import res_request
import ir_property

View File

@ -0,0 +1,77 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import osv,fields
# -------------------------------------------------------------------------
# Properties
# -------------------------------------------------------------------------
def _models_get2(self, cr, uid, context={}):
obj = self.pool.get('ir.model.fields')
ids = obj.search(cr, uid, [('view_load','=',1)])
res = []
done = {}
for o in obj.browse(cr, uid, ids, context=context):
if o.relation not in done:
res.append( [o.relation, o.relation])
done[o.relation] = True
return res
def _models_get(self, cr, uid, context={}):
obj = self.pool.get('ir.model.fields')
ids = obj.search(cr, uid, [('view_load','=',1)])
res = []
done = {}
for o in obj.browse(cr, uid, ids, context=context):
if o.model_id.id not in done:
res.append( [o.model_id.model, o.model_id.name])
done[o.model_id.id] = True
return res
class ir_property(osv.osv):
_name = 'ir.property'
_columns = {
'name': fields.char('Name', size=128),
'value': fields.reference('Value', selection=_models_get2, size=128),
'res_id': fields.reference('Resource', selection=_models_get, size=128),
'company_id': fields.many2one('res.company', 'Company'),
'fields_id': fields.many2one('ir.model.fields', 'Fields', ondelete='cascade', required=True)
}
def get(self, cr, uid, name, model, res_id=False, context={}):
cr.execute('select id from ir_model_fields where name=%s and model=%s', (name, model))
res = cr.fetchone()
if res:
nid = self.search(cr, uid, [('fields_id','=',res[0]),('res_id','=',res_id)])
if nid:
d = self.browse(cr, uid, nid[0], context).value
return (d and int(d.split(',')[1])) or False
return False
ir_property()

View File

@ -0,0 +1,43 @@
<?xml version="1.0"?>
<terp>
<data>
==========================================================
Properties
==========================================================
<record model="ir.ui.view" id="ir_property_view">
<field name="name">ir.property.form</field>
<field name="model">ir.property</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Properties">
<separator string="Property" colspan="4"/>
<field name="name" select="1"/>
<field name="company_id" select="1"/>
<field name="fields_id" colspan="3" select="1"/>
<field name="value" colspan="3"/>
<field name="res_id" colspan="3"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="ir_property_form">
<field name="name">ir.property</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.property</field>
<field name="view_type">form</field>
<field name="domain">[('res_id','=',False)]</field>
<field name="view_id" ref="ir_property_view"/>
</record>
<menuitem name="Administration/Custom/Properties/Default Properties" action="ir_property_form" id="menu_ir_property_form"/>
<record model="ir.actions.act_window" id="ir_property_form_all">
<field name="name">ir.property</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.property</field>
<field name="view_type">form</field>
<field name="view_id" ref="ir_property_view"/>
</record>
<menuitem name="Administration/Custom/Properties/All Properties" action="ir_property_form_all" id="menu_ir_property_form_all"/>
</data>
</terp>

View File

@ -0,0 +1,37 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import tools
from partner import *
from crm import *
import wizard
import report

View File

@ -0,0 +1,105 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import time
from osv import fields,osv
#
# Sale/Purchase Canal, Media
#
class res_partner_canal(osv.osv):
_name = "res.partner.canal"
_description = "Channels"
_columns = {
'name': fields.char('Channel Name',size=64, required=True),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a: 1,
}
res_partner_canal()
#
# Partner: State of Mind
#
class res_partner_som(osv.osv):
_name = "res.partner.som"
_columns = {
'name': fields.char('State of Mind',size=64, required=True),
'factor': fields.float('Factor', required=True)
}
res_partner_som()
def _links_get(self, cr, uid, context={}):
obj = self.pool.get('res.request.link')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['object', 'name'], context)
return [(r['object'], r['name']) for r in res]
class res_partner_event(osv.osv):
_name = "res.partner.event"
_columns = {
'name': fields.char('Events',size=64, required=True),
'som': fields.many2one('res.partner.som', 'State of Mind'),
'description': fields.text('Description'),
'planned_cost': fields.float('Planned Cost'),
'planned_revenue': fields.float('Planned Revenue'),
'probability': fields.float('Probability (0.50)'),
'document': fields.reference('Document', selection=_links_get, size=128),
'partner_id': fields.many2one('res.partner', 'Partner', select=True),
'date': fields.datetime('Date', size=16),
'user_id': fields.many2one('res.users', 'User'),
'canal_id': fields.many2one('res.partner.canal', 'Channel'),
'partner_type': fields.selection([('customer','Customer'),('retailer','Retailer'),('prospect','Commercial Prospect')], 'Partner Relation'),
'type': fields.selection([('sale','Sale Opportunity'),('purchase','Purchase Offer'),('prospect','Prospect Contact')], 'Type of Event'),
'event_ical_id': fields.char('iCal id', size=64),
}
_order = 'date desc'
_defaults = {
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
}
res_partner_event()
class res_partner_event_type(osv.osv):
_name = "res.partner.event.type"
_description = "Partner Events"
_columns = {
'name': fields.char('Event Type',size=64, required=True),
'key': fields.char('Key', size=64, required=True),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a: 1
}
def check(self, cr, uid, key, context={}):
return self.search(cr, uid, [('key','=',key)])
res_partner_event_type()

View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<terp>
<data noupdate="1">
<record model="res.partner.canal">
<field name="name">website</field>
</record>
<record model="res.partner.canal">
<field name="name">phone</field>
</record>
<record model="res.partner.canal">
<field name="name">direct</field>
</record>
<record model="res.partner.canal">
<field name="name">E-mail</field>
</record>
<record model="res.partner.som">
<field name="name">Fury</field>
<field name="factor">1.0</field>
</record>
<record model="res.partner.som">
<field name="name">Unhappy</field>
<field name="factor">3.0</field>
</record>
<record model="res.partner.som">
<field name="name">Normal</field>
<field name="factor">5.0</field>
</record>
<record model="res.partner.som">
<field name="name">Happy</field>
<field name="factor">7.0</field>
</record>
<record model="res.partner.som">
<field name="name">Very Happy</field>
<field name="factor">8.5</field>
</record>
</data>
</terp>

View File

@ -0,0 +1,116 @@
<?xml version="1.0"?>
<terp>
<data>
<record model="ir.ui.view" id="res_partner_canal-view">
<field name="name">res.partner.canal.form</field>
<field name="model">res.partner.canal</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Channel">
<field name="name" select="1"/>
<field name="active" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="res_partner_canal-act">
<field name="name">res.partner.canal.form</field>
<field name="res_model">res.partner.canal</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Partners/Configuration/Partner events/Channels" groups="admin" action="res_partner_canal-act"/>
<record model="ir.ui.view" id="res_partner_event_type-view">
<field name="name">res.partner.event.type.form</field>
<field name="model">res.partner.event.type</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Event Type">
<field name="name" select="1"/>
<field name="active" select="1"/>
<field name="key" select="1" readonly="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="res_partner_event_type-act">
<field name="name">res.partner.event.type.form</field>
<field name="res_model">res.partner.event.type</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Partners/Configuration/Partner events/Active partner events" groups="admin" action="res_partner_event_type-act"/>
<record model="ir.ui.view" id="res_partner_som_tree-view">
<field name="name">res.partner.som.tree</field>
<field name="model">res.partner.som</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Partner State of Mind">
<field name="name"/>
<field name="factor"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="res_partner_som-view">
<field name="name">res.partner.som.form</field>
<field name="model">res.partner.som</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partner State of Mind">
<field name="name" select="1"/>
<field name="factor" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="res_partner_som-act">
<field name="name">res.partner.som.form</field>
<field name="res_model">res.partner.som</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Partners/Configuration/Partner events/States of Mind" groups="admin" action="res_partner_som-act"/>
<record model="ir.ui.view" id="res_partner_event-wopartner-view_form">
<field name="name">res.partner.event.form</field>
<field name="model">res.partner.event</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partner Events">
<separator string="General Description" colspan="4"/>
<field name="name" select="1"/>
<field name="partner_type" select="1"/>
<field name="som" select="1"/>
<field name="date" select="1"/>
<field name="canal_id" select="1"/>
<field name="type" select="1"/>
<field name="user_id" select="1"/>
<field name="probability"/>
<field name="planned_revenue"/>
<field name="planned_cost"/>
<separator string="Description" colspan="4"/>
<field name="description" colspan="3"/>
<separator string="Document Link" colspan="4"/>
<field name="document" colspan="3"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="res_partner_event-wopartner-view_tree">
<field name="name">res.partner.event.tree</field>
<field name="model">res.partner.event</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Partner Events">
<field name="date"/>
<field name="name"/>
<field name="som"/>
<field name="type"/>
<field name="partner_type"/>
<field name="user_id"/>
</tree>
</field>
</record>
</data>
</terp>

View File

@ -0,0 +1,372 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: partner.py 1007 2005-07-25 13:18:09Z kayhman $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import math
from osv import fields,osv
import tools
import ir
import pooler
class res_partner_function(osv.osv):
_name = 'res.partner.function'
_description = 'Function of the contact'
_columns = {
'name': fields.char('Name', size=64, required=True),
'code': fields.char('Code', size=8),
}
_order = 'name'
res_partner_function()
class res_country(osv.osv):
_name = 'res.country'
_description = 'Country'
_columns = {
'name': fields.char('Country Name', size=64, help='The full name of the country.'),
'code': fields.char('Country Code', size=2, help='The ISO country code in two chars. You can use this field for quick search.'),
}
_sql_constraints = [
('name_uniq', 'unique (name)', 'The name of the country must be unique !'),
('code_uniq', 'unique (code)', 'The code of the country must be unique !')
]
def name_search(self, cr, user, name, args=[], operator='ilike', context={}):
ids = self.search(cr, user, [('code','=',name)]+ args)
if not ids:
ids = self.search(cr, user, [('name',operator,name)]+ args)
return self.name_get(cr, user, ids)
_order='code'
res_country()
class res_country_state(osv.osv):
_description="Country state"
_name = 'res.country.state'
_columns = {
'country_id': fields.many2one('res.country', 'Country'),
'name': fields.char('State Name', size=64),
'code': fields.char('State Code', size=2),
}
_order = 'code'
res_country_state()
class res_payterm(osv.osv):
_description = 'Payment term'
_name = 'res.payterm'
_columns = {
'name': fields.char('Payment term (short name)', size=64),
}
res_payterm()
class res_partner_category_type(osv.osv):
_description='Partner category types'
_name = 'res.partner.category.type'
_columns = {
'name': fields.char('Category Name', required=True, size=64),
}
_order = 'name'
res_partner_category_type()
def _cat_type_get(self, cr, uid, context={}):
obj = self.pool.get('res.partner.category.type')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['name'], context)
return [(r['name'], r['name']) for r in res]
class res_partner_category(osv.osv):
def name_get(self, cr, uid, ids, context={}):
if not len(ids):
return []
reads = self.read(cr, uid, ids, ['name','parent_id'], context)
res = []
for record in reads:
name = record['name']
if record['parent_id']:
name = record['parent_id'][1]+' / '+name
res.append((record['id'], name))
return res
def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, unknow_dict):
res = self.name_get(cr, uid, ids)
return dict(res)
def _check_recursion(self, cr, uid, ids):
level = 100
while len(ids):
cr.execute('select distinct parent_id from res_partner_category where id in ('+','.join(map(str,ids))+')')
ids = filter(None, map(lambda x:x[0], cr.fetchall()))
if not level:
return False
level -= 1
return True
_description='Partner Categories'
_name = 'res.partner.category'
_columns = {
'name': fields.char('Category Name', required=True, size=64),
'type_id': fields.many2one('res.partner.category.type', 'Category Type'),
'parent_id': fields.many2one('res.partner.category', 'Parent Category', select=True),
'complete_name': fields.function(_name_get_fnc, method=True, type="char", string='Name'),
'child_ids': fields.one2many('res.partner.category', 'parent_id', 'Childs Category'),
'active' : fields.boolean('Active'),
}
_constraints = [
(_check_recursion, 'Error ! You can not create recursive categories.', ['parent_id'])
]
_defaults = {
'active' : lambda *a: 1,
}
_order = 'parent_id,name'
res_partner_category()
class res_partner_title(osv.osv):
_name = 'res.partner.title'
_columns = {
'name': fields.char('Title', required=True, size=46, translate=True),
'shortcut': fields.char('Shortcut', required=True, size=16),
'domain': fields.selection([('partner','Partner'),('contact','Contact')], 'Domain', required=True, size=24)
}
_order = 'name'
res_partner_title()
def _contact_title_get(self, cr, uid, context={}):
obj = self.pool.get('res.partner.title')
ids = obj.search(cr, uid, [('domain', '=', 'contact')])
res = obj.read(cr, uid, ids, ['shortcut','name'], context)
return [(r['shortcut'], r['name']) for r in res]
def _partner_title_get(self, cr, uid, context={}):
obj = self.pool.get('res.partner.title')
ids = obj.search(cr, uid, [('domain', '=', 'partner')])
res = obj.read(cr, uid, ids, ['shortcut','name'], context)
return [(r['shortcut'], r['name']) for r in res]
def _lang_get(self, cr, uid, context={}):
obj = self.pool.get('res.lang')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['code', 'name'], context)
res = [(r['code'], r['name']) for r in res]
return res + [(False, '')]
class res_partner(osv.osv):
_description='Partner'
_name = "res.partner"
_order = "name"
_columns = {
'name': fields.char('Name', size=128, required=True, select=True),
'date': fields.date('Date'),
'title': fields.selection(_partner_title_get, 'Title', size=32),
'parent_id': fields.many2one('res.partner','Main Company', select=True),
'child_ids': fields.one2many('res.partner', 'parent_id', 'Partner Ref.'),
'ref': fields.char('Code', size=64),
'lang': fields.selection(_lang_get, 'Language', size=5),
'user_id': fields.many2one('res.users', 'Salesman'),
'responsible': fields.many2one('res.users', 'Users'),
'vat': fields.char('VAT',size=32),
'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
'website': fields.char('Website',size=64),
'comment': fields.text('Notes'),
'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
'category_id': fields.many2many('res.partner.category', 'res_partner_category_rel', 'partner_id', 'category_id', 'Categories'),
'events': fields.one2many('res.partner.event', 'partner_id', 'events'),
'credit_limit': fields.float(string='Credit Limit'),
'ean13': fields.char('EAN13', size=13),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a: 1,
}
_sql_constraints = [
('name_uniq', 'unique (name)', 'The name of the partner must be unique !')
]
def _check_ean_key(self, cr, uid, ids):
for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]):
thisean=partner_o['ean13']
if thisean and thisean!='':
if len(thisean)!=13:
return False
sum=0
for i in range(12):
if not (i % 2):
sum+=int(thisean[i])
else:
sum+=3*int(thisean[i])
if math.ceil(sum/10.0)*10-sum!=int(thisean[12]):
return False
return True
# _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])]
def name_get(self, cr, uid, ids, context={}):
if not len(ids):
return []
if context.get('show_ref', False):
rec_name = 'ref'
else:
rec_name = 'name'
res = [(r['id'], r[rec_name]) for r in self.read(cr, uid, ids, [rec_name], context)]
return res
def name_search(self, cr, uid, name, args=[], operator='ilike', context={}, limit=80):
if name:
ids = self.search(cr, uid, [('ref', '=', name)] + args, limit=limit)
if not ids:
ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit)
else:
ids = self.search(cr, uid, args, limit=limit)
return self.name_get(cr, uid, ids, context)
def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None):
partners = self.browse(cr, uid, ids)
for partner in partners:
if len(partner.address):
if partner.address[0].email:
tools.email_send(email_from, [partner.address[0].email], subject, body, on_error)
return True
def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''):
while len(ids):
self.pool.get('ir.cron').create(cr, uid, {
'name': 'Send Partner Emails',
'user_id': uid,
# 'nextcall': False,
'model': 'res.partner',
'function': '_email_send',
'args': repr([ids[:16], email_from, subject, body, on_error])
})
ids = ids[16:]
return True
def address_get(self, cr, uid, ids, adr_pref=['default']):
cr.execute('select type,id from res_partner_address where partner_id in ('+','.join(map(str,ids))+')')
res = cr.fetchall()
adr = dict(res)
# get the id of the (first) default address if there is one,
# otherwise get the id of the first address in the list
if res:
default_address = adr.get('default', res[0][1])
else:
default_address = False
result = {}
for a in adr_pref:
result[a] = adr.get(a, default_address)
return result
def gen_next_ref(self, cr, uid, ids):
if len(ids) != 1:
return True
# compute the next number ref
cr.execute("select ref from res_partner where ref is not null order by char_length(ref) desc, ref desc limit 1")
res = cr.dictfetchall()
ref = res and res[0]['ref'] or '0'
try:
nextref = int(ref)+1
except e:
raise osv.except_osv('Warning', "Couldn't generate the next id because some partners have an alphabetic id !")
# update the current partner
cr.execute("update res_partner set ref=%d where id=%d", (nextref, ids[0]))
return True
res_partner()
class res_partner_bank(osv.osv):
_description='Bank Details'
_name = "res.partner.bank"
_order = "sequence"
_columns = {
'name': fields.char('Account Name', size=64, required=True),
'sequence': fields.integer('Sequence'),
'iban': fields.char('Account number', size=64),
'swift': fields.char('Swift', size=64),
'bank_name': fields.char('Bank Name', size=64),
'bank_guichet': fields.char('Branch', size=64),
'partner_id': fields.many2one('res.partner', 'Partner', required=True, ondelete='cascade', select=True),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a: 1,
}
res_partner_bank()
class res_partner_address(osv.osv):
_description ='Partner Contact'
_name = 'res.partner.address'
_order = 'id'
_columns = {
'partner_id': fields.many2one('res.partner', 'Partner', required=True, ondelete='cascade', select=True),
'type': fields.selection( [ ('default','Default'),('invoice','Invoice'), ('delivery','Delivery'), ('contact','Contact'), ('other','Other') ],'Address Type'),
'function': fields.many2one('res.partner.function', 'Function', relate=True),
'title': fields.selection(_contact_title_get, 'Title', size=32),
'name': fields.char('Contact Name', size=64),
'street': fields.char('Street', size=128),
'street2': fields.char('Street2', size=128),
'zip': fields.char('Zip', change_default=True, size=24),
'city': fields.char('City', size=128),
'state_id': fields.many2one("res.country.state", 'State', domain="[('country_id','=',country_id)]"),
'country_id': fields.many2one('res.country', 'Country'),
'email': fields.char('E-Mail', size=64),
'phone': fields.char('Phone', size=64),
'fax': fields.char('Fax', size=64),
'mobile': fields.char('Mobile', size=64),
'birthdate': fields.char('Birthdate', size=64),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a: 1,
}
def name_get(self, cr, user, ids, context={}):
if not len(ids):
return []
res = []
for r in self.read(cr, user, ids, ['name','zip','city','partner_id']):
if context.get('contact_display', 'contact')=='partner':
res.append((r['id'], r['partner_id'][1]))
else:
addr = str(r['name'] or '')
if r['name'] and (r['zip'] or r['city']):
addr += ', '
addr += str(r['zip'] or '') + ' ' + str(r['city'] or '')
res.append((r['id'], addr))
return res
def name_search(self, cr, user, name, args=[], operator='ilike', context={}, limit=80):
if context.get('contact_display', 'contact')=='partner':
ids = self.search(cr, user, [('partner_id',operator,name)], limit=limit)
else:
ids = self.search(cr, user, [('zip','=',name)] + args, limit=limit)
if not ids:
ids = self.search(cr, user, [('city',operator,name)] + args, limit=limit)
if not ids:
ids = self.search(cr, user, [('name',operator,name)] + args, limit=limit)
return self.name_get(cr, user, ids)
res_partner_address()
# vim:noexpandtab:

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<terp>
<data>
</data>
</terp>

View File

@ -0,0 +1,288 @@
<?xml version="1.0"?>
<terp>
<data noupdate="1">
#
# Resource: res.partner.title
#
<record id="res_partner_title_madam" model="res.partner.title">
<field name="domain">contact</field>
<field name="name">Madam</field>
<field name="shortcut">Ms.</field>
</record>
<record id="res_partner_title_miss" model="res.partner.title">
<field name="domain">contact</field>
<field name="name">Miss</field>
<field name="shortcut">Mss</field>
</record>
<record id="res_partner_title_sir" model="res.partner.title">
<field name="domain">contact</field>
<field name="name">Sir</field>
<field name="shortcut">M.</field>
</record>
#
# Resource: res.partner.category
#
<record id="res_partner_category_0" model="res.partner.category">
<field name="name">Customer</field>
</record>
<record id="res_partner_category_1" model="res.partner.category">
<field name="name">Prospect</field>
</record>
<record id="res_partner_category_2" model="res.partner.category">
<field name="name">Tiny ERP Partners</field>
<field name="parent_id" ref="res_partner_category_0"/>
</record>
<record id="res_partner_category_3" model="res.partner.category">
<field name="name">Starter Partner</field>
<field name="parent_id" ref="res_partner_category_2"/>
</record>
<record id="res_partner_category_4" model="res.partner.category">
<field name="name">Basic Partner</field>
<field name="parent_id" ref="res_partner_category_2"/>
</record>
<record id="res_partner_category_5" model="res.partner.category">
<field name="name">Gold Partner</field>
<field name="parent_id" ref="res_partner_category_2"/>
</record>
<record id="res_partner_category_7" model="res.partner.category">
<field name="name">Openstuff.net</field>
<field name="parent_id" ref="res_partner_category_0"/>
</record>
<record id="res_partner_category_12" model="res.partner.category">
<field name="name">Segmentation</field>
<field name="parent_id" ref="res_partner_category_0"/>
</record>
<record id="res_partner_category_13" model="res.partner.category">
<field name="name">Important customers</field>
<field name="parent_id" ref="res_partner_category_12"/>
</record>
<record id="res_partner_category_14" model="res.partner.category">
<field name="name">Bad customers</field>
<field name="parent_id" ref="res_partner_category_12"/>
</record>
<record id="res_partner_category_8" model="res.partner.category">
<field name="name">Supplier</field>
</record>
<record id="res_partner_category_9" model="res.partner.category">
<field name="name">Components Supplier</field>
<field name="parent_id" ref="res_partner_category_8"/>
</record>
<record id="res_partner_category_10" model="res.partner.category">
<field name="name">Open Source Service Company</field>
<field name="parent_id" ref="res_partner_category_8"/>
</record>
<record id="res_partner_category_11" model="res.partner.category">
<field name="name">Textile Suppliers</field>
<field name="parent_id" ref="res_partner_category_8"/>
</record>
#
# Resource: res.partner
#
<record id="res_partner_asus" model="res.partner">
<field name="name">ASUStek</field>
</record>
<record id="res_partner_agrolait" model="res.partner">
<field name="name">Agrolait</field>
</record>
<record id="res_partner_2" model="res.partner">
<field name="name">Bank Wealthy and sons</field>
</record>
<record id="res_partner_3" model="res.partner">
<field name="lang">en</field>
<field name="name">China Export</field>
</record>
<record id="res_partner_4" model="res.partner">
<field name="name">Distrib PC</field>
</record>
<record id="res_partner_5" model="res.partner">
<field name="name">Ecole de Commerce de Liege</field>
</record>
<record id="res_partner_6" model="res.partner">
<field name="name">Elec Import</field>
</record>
<record id="res_partner_maxtor" model="res.partner">
<field name="name">Maxtor</field>
</record>
<record id="res_partner_seagate" model="res.partner">
<field name="name">Seagate</field>
</record>
<record id="res_partner_8" model="res.partner">
<field name="website">http://mediapole.net</field>
<field name="name">Mediapole SPRL</field>
</record>
<record id="res_partner_9" model="res.partner">
<field name="website">http://opensides.be</field>
<field name="name">Opensides sprl</field>
<field name="ref">os</field>
</record>
<record id="res_partner_10" model="res.partner">
<field name="name">Tecsas</field>
<field name="ean13">3020170000003</field>
</record>
<record id="res_partner_11" model="res.partner">
<field name="name">Leclerc</field>
</record>
<record id="res_partner_14" model="res.partner">
<field name="name">Centrale d'achats BML</field>
<field name="ean13">3020178572427</field>
<field name="parent_id" ref="res_partner_10"/>
</record>
<record id="res_partner_15" model="res.partner">
<field name="name">Magazin BML 1</field>
<field name="ean13">3020178570171</field>
<field name="parent_id" ref="res_partner_14"/>
</record>
#
# Resource: res.partner.address
#
<record id="res_partner_address_1" model="res.partner.address">
<field name="city">Bruxelles</field>
<field name="name">Benoit Mortier</field>
<field name="zip">1030</field>
<field name="country_id" model="res.country" search="[('name','=','Belgium')]"/>
<field name="email">info@opensides.be</field>
<field name="phone">(+32)2 211 34 83</field>
<field name="street">Rue des Palais 44, bte 33</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_9"/>
</record>
<record id="res_partner_address_2" model="res.partner.address">
<field name="city">Avignon CEDEX 09</field>
<field name="name">Laurent Jacot</field>
<field name="zip">84911</field>
<field name="country_id" model="res.country" search="[('name','=','France')]"/>
<field name="email">contact@tecsas.fr</field>
<field name="phone">(+33)4.32.74.10.57</field>
<field name="street">85 rue du traite de Rome</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_10"/>
</record>
<record id="res_partner_address_3" model="res.partner.address">
<field name="city">Louvain-la-Neuve</field>
<field name="name">Thomas Passot</field>
<field name="zip">1348</field>
<field name="country_id" model="res.country" search="[('name','=','Belgium')]"/>
<field name="email">info@mediapole.net</field>
<field name="phone">(+32).10.45.17.73</field>
<field name="street">Rue de l'Angelique, 1</field>
<field name="partner_id" ref="res_partner_8"/>
</record>
<record id="res_partner_address_tang" model="res.partner.address">
<field name="city">Taiwan</field>
<field name="name">Tang</field>
<field name="zip">23410</field>
<field name="title">M.</field>
<field name="country_id" model="res.country" search="[('name','=','Taiwan')]"/>
<field name="street">31 Hong Kong street</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_asus"/>
</record>
<record id="res_partner_address_wong" model="res.partner.address">
<field name="city">Hong Kong</field>
<field name="name">Wong</field>
<field name="zip">23540</field>
<field name="title">M.</field>
<field name="country_id" model="res.country" search="[('name','=','China')]"/>
<field name="street">56 Beijing street</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_maxtor"/>
</record>
<record id="res_partner_address_6" model="res.partner.address">
<field name="city">Bruxelles</field>
<field name="name">Etienne Lacarte</field>
<field name="zip">2365</field>
<field name="title">M.</field>
<field name="country_id" model="res.country" search="[('name','=','Belgium')]"/>
<field name="street">23 rue du Vieux Bruges</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_6"/>
</record>
<record id="res_partner_address_7" model="res.partner.address">
<field name="city">Namur</field>
<field name="name">Jean Guy Lavente</field>
<field name="zip">2541</field>
<field name="title">M.</field>
<field name="country_id" model="res.country" search="[('name','=','Belgium')]"/>
<field name="street">42 rue de la Lesse</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_4"/>
</record>
<record id="res_partner_address_8" model="res.partner.address">
<field name="city">Wavre</field>
<field name="name">Sylvie Lelitre</field>
<field name="zip">5478</field>
<field name="title">Ms.</field>
<field name="country_id" model="res.country" search="[('name','=','Belgium')]"/>
<field name="street">69 rue de Chimay</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_9" model="res.partner.address">
<field name="city">Paris</field>
<field name="name">Arthur Grosbonnet</field>
<field name="zip">75016</field>
<field name="title">M.</field>
<field name="country_id" model="res.country" search="[('name','=','France')]"/>
<field name="street">1 rue Rockfeller</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_2"/>
</record>
<record id="res_partner_address_10" model="res.partner.address">
<field name="city">Liege</field>
<field name="name">Karine Lesbrouffe</field>
<field name="zip">6985</field>
<field name="title">Mss</field>
<field name="country_id" model="res.country" search="[('name','=','Belgium')]"/>
<field name="street">2 Impasse de la Soif</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_5"/>
</record>
<record id="res_partner_address_zen" model="res.partner.address">
<field name="city">Shanghai</field>
<field name="name">Zen</field>
<field name="zip">4785552</field>
<field name="title">M.</field>
<field name="country_id" model="res.country" search="[('name','=','China')]"/>
<field name="street">52 Chop Suey street</field>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_3"/>
</record>
<record id="res_partner_address_12" model="res.partner.address">
<field name="type">default</field>
<field name="name">Centrale</field>
<field name="partner_id" ref="res_partner_10"/>
</record>
<record id="res_partner_address_13" model="res.partner.address">
<field name="type">default</field>
<field name="name">Centrale d'achats 1</field>
<field name="partner_id" ref="res_partner_14"/>
</record>
<record id="res_partner_address_14" model="res.partner.address">
<field name="type">default</field>
<field name="name">Shop 1</field>
<field name="partner_id" ref="res_partner_15"/>
</record>
<record id="res_partner_address_15" model="res.partner.address">
<field name="type">default</field>
<field name="name">Shop 2</field>
<field name="partner_id" ref="res_partner_11"/>
</record>
<record id="res_partner_address_16" model="res.partner.address">
<field name="type">default</field>
<field name="name">Shop 3</field>
<field name="partner_id" ref="res_partner_11"/>
</record>
</data>
</terp>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<terp>
<data>
<report string="Labels" model="res.partner" name="res.partner.address" xml="base/res/partner/report/partner_address.xml" xsl="base/res/partner/report/partner_address.xsl"/>
<!--
<report string="Business Cards" model="res.partner" name="res.partner.businesscard" xml="base/res/partner/report/business_card.xml" xsl="base/res/partner/report/business_card.xsl"/>
-->
</data>
</terp>

View File

@ -0,0 +1,504 @@
<?xml version="1.0"?>
<terp>
<data>
<menuitem name="Partners" sequence="0" icon="terp-partner" id="menu_base_partner"/>
<menuitem name="Partners/Configuration" groups="admin"/>
<!--
================================
Function
================================
-->
<record model="ir.ui.view" id="view_partner_function_form">
<field name="name">res.partner.function.form</field>
<field name="model">res.partner.function</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partner Functions">
<field name="name" select="1"/>
<field name="code" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_function_form">
<field name="name">res.partner.function.form</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.function</field>
<field name="view_type">form</field>
</record>
<menuitem name="Partners/Configuration/Functions" groups="admin" action="action_partner_function_form" id="menu_partner_function_form"/>
<!--
================================
Country
================================
-->
<record model="ir.ui.view" id="view_country_tree">
<field name="name">res.country.tree</field>
<field name="model">res.country</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Country">
<field name="name" />
<field name="code"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_country_form">
<field name="name">res.country.form</field>
<field name="model">res.country</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Country">
<field name="name" select="1"/>
<field name="code" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_country">
<field name="name">res.country.form</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.country</field>
<field name="view_type">form</field>
</record>
<menuitem name="Partners/Configuration/Localisation/Countries" groups="admin" action="action_country" id="menu_country"/>
<!--
================================
State
================================
-->
<record model="ir.ui.view" id="view_country_state_tree">
<field name="name">res.country.state.tree</field>
<field name="model">res.country.state</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="State">
<field name="country_id"/>
<field name="name"/>
<field name="code"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_country_state_form">
<field name="name">res.country.state.form</field>
<field name="model">res.country.state</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="State">
<field name="country_id" select="1"/>
<field name="name" select="1"/>
<field name="code" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_country_state">
<field name="name">res.country.state</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.country.state</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_country_state_form"/>
</record>
<menuitem name="Partners/Configuration/Localisation/States" groups="admin" action="action_country_state" id="menu_country_state"/>
<!--
=====================
Partner Address
=====================
-->
<record model="ir.ui.view" id="view_partner_address_tree">
<field name="name">res.partner.address.tree</field>
<field name="model">res.partner.address</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Partner Contacts">
<field name="partner_id" />
<field name="name" />
<field name="zip"/>
<field name="city"/>
<field name="country_id"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_addess_tree">
<field name="name">res.partner.address.tree</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.address</field>
<field name="view_type">tree</field>
<field name="view_id" ref="view_partner_address_tree"/>
</record>
<record model="ir.ui.view" id="view_partner_address_form1">
<field name="name">res.partner.address.form1</field>
<field name="model">res.partner.address</field>
<field name="type">form</field>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<form string="Partner Contacts">
<field name="partner_id" colspan="3" select="1"/>
<newline/>
<field name="name" select="1"/>
<field name="title" domain="[('domain', '=', 'contact')]"/>
<field name="function"/>
<field name="type" select="1"/>
<field name="street" select="1"/>
<field name="street2"/>
<newline/>
<field name="zip" select="1"/>
<field name="city" select="1"/>
<newline/>
<field name="country_id" select="1"/>
<field name="state_id" select="1"/>
<newline/>
<field name="phone" select="1"/>
<field name="fax"/>
<newline/>
<field name="mobile" select="1"/>
<field name="email" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_address_form">
<field name="name">res.partner.address</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.address</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_partner_address_form1"/>
</record>
<menuitem name="Partners/Partner Contacts" action="action_partner_address_form" id="menu_partner_address_form"/>
<!--
=========================================
the short form used in the partner form
=========================================
-->
<record model="ir.ui.view" id="view_partner_address_form2">
<field name="name">res.partner.address.form2</field>
<field name="model">res.partner.address</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Contacts">
<field name="name" select="1"/>
<field name="title" domain="[('domain', '=', 'contact')]"/>
<field name="street"/>
<field name="street2"/>
<field name="type" select="1"/>
<field name="function"/>
<newline/>
<field name="zip" select="1"/>
<field name="city" select="1"/>
<newline/>
<field name="country_id" select="1"/>
<field name="state_id" select="1"/>
<newline/>
<field name="phone"/>
<field name="fax"/>
<newline/>
<field name="mobile"/>
<field name="email"/>
</form>
</field>
</record>
<!--
=======================
Partner Titles
=======================
-->
<record model="ir.ui.view" id="view_partner_title_form">
<field name="name">res.partner.title.form</field>
<field name="model">res.partner.title</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partners Titles">
<field name="name" select="1"/>
<field name="shortcut" select="1"/>
<field name="domain"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_title">
<field name="name">res.partner.title</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.title</field>
<field name="view_type">form</field>
</record>
<menuitem name="Partners/Configuration/Titles" groups="admin" action="action_partner_title" id="menu_partner_title"/>
<!--
=======================
Partner
=======================
-->
<record model="ir.ui.view" id="view_partner_tree">
<field name="name">res.partner.tree</field>
<field name="model">res.partner</field>
<field name="type">tree</field>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<tree string="Partners">
<field name="name"/>
<field name="ref"/>
<field name="address"/>
<field name="lang"/>
<field name="category_id"/>
<field name="vat"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_partner_form">
<field name="name">res.partner.form</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partners">
<notebook>
<page string="General">
<separator string="General Information" colspan="4"/>
<field name="name" select="1"/>
<field name="title" domain="[('domain', '=', 'partner')]"/>
<field name="ref" select="1"/>
<field name="lang" select="1"/>
<newline/>
<field name="address" mode="form,tree" colspan="4" nolabel="1" select="1">
<form string="Partner Contacts">
<field name="name" select="1"/>
<field name="title" domain="[('domain', '=', 'contact')]"/>
<field name="function"/>
<field name="type" select="1"/>
<field name="street" select="1"/>
<field name="street2"/>
<newline/>
<field name="zip" select="1"/>
<field name="city" select="1"/>
<newline/>
<field name="country_id" select="1" completion="1"/>
<field name="state_id" select="1"/>
<newline/>
<field name="phone"/>
<field name="fax"/>
<newline/>
<field name="mobile"/>
<field name="email" select="1" widget="email" />
</form>
</field>
<separator string="Categories" colspan="4"/>
<field name="category_id" colspan="4" select="1" nolabel="1"/>
</page>
<page string="Extra Info">
<field name="vat" select="1"/>
<field name="active" select="1" />
<field name="credit_limit" select="1"/>
<field name="user_id" select="1"/>
<field name="parent_id" select="1"/>
<field name="website" widget="url"/>
<field name="date" select="1"/>
<field name="bank_ids" colspan="4" nolabel="1"/>
<separator string="Notes" colspan="4"/>
<field name="comment" colspan="4" nolabel="1"/>
</page>
<page string="Event History">
<field name="events" colspan="4" nolabel="1" widget="one2many_list"/>
</page>
<page string="Properties">
<properties/>
</page>
</notebook>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_form">
<field name="name">res.partner</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_partner_form"/>
</record>
<menuitem name="Partners/Partners" action="action_partner_form" id="menu_partner_form"/>
<record model="ir.ui.view" id="view_payterm_form">
<field name="name">res.payterm</field>
<field name="model">res.payterm</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Payment term">
<field name="name" colspan="4" />
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_payterm_form">
<field name="name">res.payterm</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.payterm</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_payterm_form"/>
</record>
<record model="ir.ui.view" id="view_partner_bank_form">
<field name="name">res.partner.bank.form</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Bank Details">
<field name="name" select="1" colspan="3"/>
<field name="sequence"/>
<field name="active" select="1"/>
<field name="iban" select="1"/>
<field name="swift" select="1"/>
<field name="bank_name" select="1"/>
<field name="bank_guichet" select="1"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_partner_bank_tree">
<field name="name">res.partner.bank.tree</field>
<field name="model">res.partner.bank</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Bank Details">
<field name="sequence"/>
<field name="name"/>
<field name="iban"/>
<field name="swift"/>
</tree>
</field>
</record>
<!--
======================
Company Architecture
======================
-->
<record model="ir.ui.view" id="view_partner_tree2">
<field name="name">res.partner.tree</field>
<field name="model">res.partner</field>
<field name="type">tree</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Partners">
<field name="name"/>
<field name="lang"/>
<field name="ref"/>
<field name="vat"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action2">
<field name="name">Company Architecture</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="domain">[('id','in',active_ids)]</field>
<field name="view_type">tree</field>
<field name="view_id" ref="view_partner_tree2"/>
</record>
<record model="ir.values" id="ir_partner_structure">
<field name="key2" eval="'client_action_multi'"/>
<field name="model" eval="'res.partner'"/>
<field name="name">Company Architecture</field>
<field name="value" eval="'ir.actions.act_window,'+str(action2)"/>
<field name="object" eval="True"/>
</record>
<!--
======================
Categories
======================
-->
<record model="ir.ui.view" id="view_partner_category_form">
<field name="name">res.partner.category.form</field>
<field name="model">res.partner.category</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partner Categories">
<field name="name" select="1"/>
<field name="active" select="1" />
<field name="type_id" select="1" />
<field name="parent_id"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_partner_category_list">
<field name="name">res.partner.category.list</field>
<field name="model">res.partner.category</field>
<field name="type">tree</field>
<field name="priority" eval="6"/>
<field name="arch" type="xml">
<tree string="Partner Categories">
<field name="complete_name"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_partner_category_tree">
<field name="name">res.partner.category.tree</field>
<field name="model">res.partner.category</field>
<field name="type">tree</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Partner Categories">
<field name="name"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_category">
<field name="name">res.partner.category</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.category</field>
<field name="view_type">tree</field>
<field name="view_id" ref="view_partner_category_tree"/>
<field name="domain">[('parent_id','=',False)]</field>
</record>
<menuitem name="Partners/Configuration/Categories" action="action_partner_category" id="menu_partner_category"/>
<record model="ir.actions.act_window" id="action_partner_category_form">
<field name="name">res.partner.category</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.category</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_partner_category_form"/>
</record>
<menuitem name="Partners/Configuration/Categories/Edit Categories" action="action_partner_category_form" id="menu_partner_category_form"/>
<record model="ir.ui.view" id="view_partner_category_type_form">
<field name="name">res.partner.category.type.form</field>
<field name="model">res.partner.category.type</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partner Type of Categories">
<field name="name" select="1"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_partner_category_type_form">
<field name="name">res.partner.category.type.form</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.category.type</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Partners/Configuration/Categories/Type of Categories" groups="admin" action="action_partner_category_type_form" id="menu_partner_category_type_form"/>
# Admin config
<menuitem name="Administration/Configuration/Partner" sequence="3"/>
<record model="ir.actions.act_window" id="open_module_type_partenaire">
<field name="name">res.partner.category</field>
<field name="res_model">res.partner.category</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Administration/Configuration/Partner/Define Partners categories" action="open_module_type_partenaire" sequence="1" id="menu_type_partenaire"/>
<record model="ir.actions.act_window" id="open_module_def_partenaire">
<field name="name">res.partner</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Administration/Configuration/Partner/Define Partners" action="open_module_def_partenaire" sequence="2" id="menu_partenaire_def"/>
</data>
</terp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<terp>
<data>
<wizard string="Send SMS" model="res.partner" name="res.partner.sms_send"/>
<wizard string="Mass Mailing" model="res.partner" name="res.partner.spam_send"/>
<!--
<wizard string="Check EAN13" model="res.partner" name="res.partner.ean13"/>
<wizard string="Clear IDs" model="res.partner" name="res.partner.clear_ids"/>
-->
</data>
</terp>

View File

@ -0,0 +1,32 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
#from report import report_sxw
#report_sxw.report_sxw('report.partner.list', 'res.partner', 'addons/base/res/partner/report/partner_list.rml')

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<addresses>
<address type="fields" name="id">
<name type="field" name="name"/>
<role type="field" name="title"/>
<phone type="field" name="phone"/>
<email type="field" name="email"/>
<mobile type="field" name="mobile"/>
<company>Tiny sprl</company>
<street>Rue du Vieux Chateau, 21</street>
<zip>BE-1457</zip>
<city>Walhain</city>
<website>http://tiny.be</website>
</address>
</addresses>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:variable name="initial_bottom_pos">20.5</xsl:variable>
<xsl:variable name="initial_left_pos">0.5</xsl:variable>
<xsl:variable name="height_increment">5.5</xsl:variable>
<xsl:variable name="width_increment">8.5</xsl:variable>
<xsl:variable name="frame_height">5.5cm</xsl:variable>
<xsl:variable name="frame_width">8.5cm</xsl:variable>
<xsl:variable name="number_columns">3</xsl:variable>
<xsl:variable name="max_cards">8</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="addresses"/>
</xsl:template>
<xsl:template match="addresses">
<document>
<template leftMargin="2.0cm" rightMargin="2.0cm" topMargin="2.0cm" bottomMargin="2.0cm" title="Address list" author="Generated by Tiny ERP, Fabien Pinckaers">
<pageTemplate id="all">
<pageGraphics/>
<xsl:apply-templates select="address" mode="frames"/>
</pageTemplate>
</template>
<stylesheet>
<paraStyle name="nospace" fontName="Courier" fontSize="12" spaceBefore="0" spaceAfter="0"/>
</stylesheet>
<story>
<xsl:apply-templates select="address" mode="story"/>
</story>
</document>
</xsl:template>
<xsl:template match="address" mode="frames">
<xsl:if test="position() &lt; $max_frames + 1">
<frame>
<xsl:attribute name="width">
<xsl:value-of select="$frame_width"/>
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of select="$frame_height"/>
</xsl:attribute>
<xsl:attribute name="x1">
<xsl:value-of select="$initial_left_pos + ((position()-1) mod $number_columns) * $width_increment"/>
<xsl:text>cm</xsl:text>
</xsl:attribute>
<xsl:attribute name="y1">
<xsl:value-of select="$initial_bottom_pos - floor((position()-1) div $number_columns) * $height_increment"/>
<xsl:text>cm</xsl:text>
</xsl:attribute>
</frame>
</xsl:if>
</xsl:template>
<xsl:template match="address" mode="story">
<drawCentredString x="105mm" y="28cm" t="1">PICKINGLIST</drawCentredString>
<image x="5mm" y="5m" file="addons/base/report/logo-tiny.png"/>
<blockTable colWidths="3cm,3cm" style="infos">
<tr>
<td>Logo</td>
<td/>
</tr><tr>
<td><para><xsl:value-of select="client-id"/></para></td>
<td><para><xsl:value-of select="shipping-id"/></para></td>
<td><para><xsl:value-of select="picking-date"/></para></td>
<td><para><xsl:value-of select="expedition-date"/></para></td>
<td><para><xsl:value-of select="command-number"/></para></td>
</tr>
</blockTable>
<para style="nospace"><xsl:value-of select="company"/></para>
<para style="nospace"><xsl:value-of select="partner_name"/></para>
<para style="nospace"><xsl:value-of select="street"/></para>
<para style="nospace"><xsl:value-of select="zip"/><xsl:text> </xsl:text><xsl:value-of select="city"/></para>
<para style="nospace"><xsl:value-of select="country"/></para>
<nextFrame/>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<addresses>
<address type="fields" name="id">
<company-title type="field" name="title"/>
<company-name type="field" name="name"/>
<contact type="zoom" name="address">
<type type="field" name="type"/>
<title type="field" name="title"/>
<name type="field" name="name"/>
<street type="field" name="street"/>
<street2 type="field" name="street2"/>
<zip type="field" name="zip"/>
<city type="field" name="city"/>
<state type="field" name="state_id.name"/>
<country type="field" name="country_id.name"/>
</contact>
</address>
</addresses>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:variable name="initial_bottom_pos">20.5</xsl:variable>
<xsl:variable name="initial_left_pos">1</xsl:variable>
<xsl:variable name="height_increment">6.5</xsl:variable>
<xsl:variable name="width_increment">10</xsl:variable>
<xsl:variable name="frame_height">5.5cm</xsl:variable>
<xsl:variable name="frame_width">10cm</xsl:variable>
<xsl:variable name="number_columns">2</xsl:variable>
<xsl:variable name="max_frames">8</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="addresses"/>
</xsl:template>
<xsl:template match="addresses">
<document>
<template leftMargin="2.0cm" rightMargin="2.0cm" topMargin="2.0cm" bottomMargin="2.0cm" title="Address list" author="Generated by Tiny ERP">
<pageTemplate id="all">
<pageGraphics/>
<xsl:apply-templates select="address" mode="frames"/>
</pageTemplate>
</template>
<stylesheet>
<paraStyle name="nospace" fontName="Courier" fontSize="12" spaceBefore="0" spaceAfter="0"/>
</stylesheet>
<story>
<xsl:apply-templates select="address" mode="story">
<xsl:sort select="contact/country"/>
<xsl:sort select="contact/zip"/>
<xsl:sort select="company-name"/>
</xsl:apply-templates>
</story>
</document>
</xsl:template>
<xsl:template match="address" mode="frames">
<xsl:if test="position() &lt; $max_frames + 1">
<frame>
<xsl:attribute name="width">
<xsl:value-of select="$frame_width"/>
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of select="$frame_height"/>
</xsl:attribute>
<xsl:attribute name="x1">
<xsl:value-of select="$initial_left_pos + ((position()-1) mod $number_columns) * $width_increment"/>
<xsl:text>cm</xsl:text>
</xsl:attribute>
<xsl:attribute name="y1">
<xsl:value-of select="$initial_bottom_pos - floor((position()-1) div $number_columns) * $height_increment"/>
<xsl:text>cm</xsl:text>
</xsl:attribute>
</frame>
</xsl:if>
</xsl:template>
<xsl:template match="address" mode="story">
<para style="nospace"><xsl:value-of select="company-title"/><xsl:text> </xsl:text><xsl:value-of select="company-name"/></para>
<xsl:choose>
<xsl:when test="count(contact[type='default']) >= 1">
<!-- apply the first 'contact' node with the type 'default' -->
<xsl:apply-templates select="contact[type='default'][1]"/>
</xsl:when>
<xsl:when test="count(contact[type='']) >= 1">
<!-- apply the first 'contact' node with an empty type -->
<xsl:apply-templates select="contact[type=''][1]"/>
</xsl:when>
<xsl:otherwise>
<!-- apply the first 'contact' node -->
<xsl:apply-templates select="contact[1]"/>
</xsl:otherwise>
</xsl:choose>
<nextFrame/>
</xsl:template>
<xsl:template match="contact">
<para style="nospace"><xsl:value-of select="title"/><xsl:text> </xsl:text><xsl:value-of select="name"/></para>
<para style="nospace"><xsl:value-of select="street"/></para>
<para style="nospace"><xsl:value-of select="street2"/></para>
<para style="nospace"><xsl:value-of select="zip"/><xsl:text> </xsl:text><xsl:value-of select="city"/></para>
<para style="nospace"><xsl:value-of select="state"/></para>
<para style="nospace"><xsl:value-of select="country"/></para>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,32 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard_sms
import wizard_spam
import wizard_clear_ids
import wizard_ean_check

View File

@ -0,0 +1,45 @@
##############################################################################
#
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import netsvc
class wizard_clear_ids(wizard.interface):
def _clear_ids(self, cr, uid, data, context):
service = netsvc.LocalService("object_proxy")
service.execute(cr.dbname, uid, 'res.partner', 'write', data['ids'], {'ref': False})
return {}
states = {
'init': {
'actions': [_clear_ids],
'result': {'type':'state', 'state':'end'}
}
}
wizard_clear_ids('res.partner.clear_ids')

View File

@ -0,0 +1,101 @@
##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import math
from osv import osv
from tools.misc import UpdateableStr
import pooler
def _is_pair(x):
return not x%2
def _get_ean_key(string):
if not string or string=='':
return '0'
if len(string)!=12:
return '0'
sum=0
for i in range(12):
if _is_pair(i):
sum+=int(string[i])
else:
sum+=3*int(string[i])
return str(int(math.ceil(sum/10.0)*10-sum))
#FIXME: this is not concurrency safe !!!!
_check_arch = UpdateableStr()
_check_fields = {}
def _check_key(self, cr, uid, data, context):
partner_table=pooler.get_pool(cr.dbname).get('res.partner')
partners = partner_table.browse(cr, uid, data['ids'])
_check_arch_lst=['<?xml version="1.0"?>', '<form string="Check EAN13">', '<label string=""/>', '<label string=""/>','<label string="Original" />', '<label string="Computed" />']
for partner in partners:
if partner['ean13'] and len(partner['ean13'])>11 and len(partner['ean13'])<14:
_check_arch_lst.append('<label colspan="2" string="%s" />' % partner['ean13']);
key=_get_ean_key(partner['ean13'][:12])
_check_arch_lst.append('<label string=""/>')
if len(partner['ean13'])==12:
_check_arch_lst.append('<label string="" />');
else:
_check_arch_lst.append('<label string="%s" />' % partner['ean13'][12])
_check_arch_lst.append('<label string="%s" />' % key)
_check_arch_lst.append('</form>')
_check_arch.string = '\n'.join(_check_arch_lst)
return {}
def _update_ean(self, cr, uid, data, context):
partner_table = pooler.get_pool(cr.dbname).get('res.partner')
partners = partner_table.browse(cr, uid, data['ids'])
for partner in partners:
partner_table.write(cr, uid, data['ids'], {
'ean13': "%s%s" % (partner['ean13'][:12], _get_ean_key(partner['ean13'][:12]))
})
return {}
class wiz_ean_check(wizard.interface):
states = {
'init': {
'actions': [_check_key],
'result': {
'type': 'form',
'arch': _check_arch,
'fields': _check_fields,
'state': (('end', 'Ignore'), ('correct', 'Correct EAN13'))
}
},
'correct' : {
'actions': [_update_ean],
'result': {
'type': 'state',
'state': 'end'
}
}
}
wiz_ean_check('res.partner.ean13')

View File

@ -0,0 +1,75 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import netsvc
sms_send_form = '''<?xml version="1.0"?>
<form string="%s">
<separator string="%s" colspan="4"/>
<field name="app_id"/>
<newline/>
<field name="user"/>
<field name="password"/>
<newline/>
<field name="text" colspan="3"/>
</form>''' % ('SMS - Gateway: clickatell','Bulk SMS send')
sms_send_fields = {
'app_id': {'string':'API ID', 'type':'char', 'required':True},
'user': {'string':'Login', 'type':'char', 'required':True},
'password': {'string':'Password', 'type':'char', 'required':True},
'text': {'string':'SMS Message', 'type':'text', 'required':True}
}
def _sms_send(self, cr, uid, data, context):
service = netsvc.LocalService("object_proxy")
res = service.execute(cr.dbname, uid, 'res.partner', 'read', data['ids'], ['gsm'])
nbr = 0
for r in res:
to = r['gsm']
if to:
tools.smssend(data['form']['user'], data['form']['password'], data['form']['app_id'], unicode(data['form']['text'], 'utf-8').encode('latin1'), to)
nbr += 1
return {'sms_sent': nbr}
class part_sms(wizard.interface):
states = {
'init': {
'actions': [],
'result': {'type': 'form', 'arch':sms_send_form, 'fields': sms_send_fields, 'state':[('end','Cancel'), ('send','Send SMS')]}
},
'send': {
'actions': [_sms_send],
'result': {'type': 'state', 'state':'end'}
}
}
part_sms('res.partner.sms_send')

View File

@ -0,0 +1,80 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: wizard_spam.py 1005 2005-07-25 08:41:42Z nicoe $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import wizard
import pooler
import tools
email_send_form = '''<?xml version="1.0"?>
<form string="Mass Mailing">
<field name="from"/>
<newline/>
<field name="subject"/>
<newline/>
<field name="text"/>
</form>'''
email_send_fields = {
'from': {'string':"Sender's email", 'type':'char', 'size':64, 'required':True},
'subject': {'string':'Subject', 'type':'char', 'size':64, 'required':True},
'text': {'string':'Message', 'type':'text', 'required':True}
}
# this sends an email to ALL the addresses of the selected partners.
def _mass_mail_send(self, cr, uid, data, context):
nbr = 0
partners = pooler.get_pool(cr.dbname).get('res.partner').browse(cr, uid, data['ids'], context)
for partner in partners:
for adr in partner.address:
if adr.email:
name = adr.name or partner.name
to = '%s <%s>' % (name, adr.email)
#TODO: add some tests to check for invalid email addresses
#CHECKME: maybe we should use res.partner/email_send
tools.email_send(data['form']['from'], [to], data['form']['subject'], data['form']['text'])
nbr += 1
pooler.get_pool(cr.dbname).get('res.partner.event').create(cr, uid,
{'name': 'Email sent through mass mailing',
'partner_id': partner.id,
'description': data['form']['text'], })
#TODO: log number of message sent
return {'email_sent': nbr}
class part_email(wizard.interface):
states = {
'init': {
'actions': [],
'result': {'type': 'form', 'arch': email_send_form, 'fields': email_send_fields, 'state':[('end','Cancel'), ('send','Send Email')]}
},
'send': {
'actions': [_mass_mail_send],
'result': {'type': 'state', 'state':'end'}
}
}
part_email('res.partner.spam_send')

View File

@ -0,0 +1,105 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
import tools
class res_company(osv.osv):
_name = "res.company"
_columns = {
'name': fields.char('Company Name', size=64, required=True),
'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
'child_ids': fields.one2many('res.company', 'parent_id', 'Childs Company'),
'partner_id': fields.many2one('res.partner', 'Partner', required=True),
'rml_header1': fields.char('Report Header', size=200),
'rml_footer1': fields.char('Report Footer 1', size=200),
'rml_footer2': fields.char('Report Footer 2', size=200),
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
}
def _get_child_ids(self, cr, uid, uid2, context={}):
company = self.pool.get('res.users').company_get(cr, uid, uid2)
ids = self._get_company_children(cr, uid, company)
return ids
def _get_company_children(self, cr, uid=None, company=None):
if not company:
return []
ids = self.search(cr, uid, [('parent_id','child_of',[company])])
return ids
_get_company_children = tools.cache()(_get_company_children)
def _get_partner_hierarchy(self, cr, uid, company_id, context={}):
print "Company ID is %s: Looking for parent..." % company_id
if company_id:
parent_id = self.browse(cr, uid, company_id)['parent_id']
if parent_id:
return self._get_partner_hierarchy(cr, uid, parent_id.id, context)
else:
print "No parent: starting descendance search!"
return self._get_partner_descendance(cr, uid, company_id, [], context)
return []
def _get_partner_descendance(self, cr, uid, company_id, descendance, context={}):
descendance.append(self.browse(cr, uid, company_id).partner_id.id)
for child_id in self._get_company_children(cr, uid, company_id):
if child_id != company_id:
print "Hello, I'm %s, child of %s" % (child_id, company_id)
descendance = self._get_partner_descendance(cr, uid, child_id, descendance)
return descendance
def __init__(self, *args, **argv):
return super(res_company, self).__init__(*args, **argv)
#
# This function restart the cache on the _get_company_children method
#
def cache_restart(self, uid=None):
self._get_company_children()
def create(self, *args, **argv):
self.cache_restart()
return super(res_company, self).create(*args, **argv)
def write(self, *args, **argv):
self.cache_restart()
return super(res_company, self).write(*args, **argv)
def _get_euro(self, cr, uid, context={}):
try:
return self.pool.get('res.currency').search(cr, uid, [('rate', '=', 1.0),])[0]
except:
return 1
_defaults = {
'currency_id': _get_euro,
}
res_company()

View File

@ -0,0 +1,70 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: account.py 1005 2005-07-25 08:41:42Z nicoe $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import time
import netsvc
from osv import fields, osv
import ir
from tools.misc import currency
#from _common import rounding
import mx.DateTime
from mx.DateTime import RelativeDateTime, now, DateTime, localtime
class res_currency(osv.osv):
_name = "res.currency"
_description = "Currency"
_columns = {
'name': fields.char('Currency', size=32, required=True),
'code': fields.char('Code', size=3),
'date': fields.date('Last rate update', readonly=True),
'rate': fields.float('Relative Change rate',digits=(12,6)),
#'digits': fields.integer('Displayed Digits'),
'accuracy': fields.integer('Computational Accuracy'),
'rounding': fields.float('Rounding factor'),
'active': fields.boolean('Active'),
}
_defaults = {
'date': lambda *a: time.strftime('%Y-%m-%d'),
'active': lambda *a: 1,
}
_order = "code"
def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount):
if to_currency_id==from_currency_id:
return from_amount
[from_currency]=self.read(cr, uid, [from_currency_id])
[to_currency] = self.read(cr, uid, [to_currency_id])
return currency(from_amount * from_currency['rate']/to_currency['rate'], to_currency['accuracy'], to_currency['rounding'])
res_currency()

View File

@ -0,0 +1,52 @@
<?xml version="1.0"?>
<terp>
<data>
#---------------------------------------------------------
# Currencies
#---------------------------------------------------------
<record model="ir.ui.view" id="view_currency_tree">
<field name="name">res.currency.tree</field>
<field name="model">res.currency</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Currencies">
<field name="name"/>
<field name="code"/>
<field name="rate"/>
<field name="date"/>
<field name="rounding"/>
<field name="accuracy"/>
<field name="active" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_currency_form">
<field name="name">res.currency.form</field>
<field name="model">res.currency</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Currency">
<field name="name" select="1" colspan="3"/>
<field name="code" select="1"/>
<field name="active" select="1"/>
<field name="rate"/>
<field name="date" select="1"/>
<field name="rounding"/>
<field name="accuracy"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_currency_form">
<field name="name">res.currency</field>
<field name="res_model">res.currency</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Partners/Configuration/Localisation/Currencies" action="action_currency_form" sequence="11"/>
<menuitem name="Administration/Configuration/Base/Define Currencies" action="action_currency_form" sequence="1" id="menu_currency_def"/>
</data>
</terp>

View File

@ -0,0 +1,124 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import osv, fields
import time
def _links_get(self, cr, uid, context={}):
obj = self.pool.get('res.request.link')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['object', 'name'], context)
return [(r['object'], r['name']) for r in res]
class res_request(osv.osv):
_name = 'res.request'
def request_send(self, cr, uid, ids, *args):
for id in ids:
cr.execute('update res_request set state=%s,date_sent=%s where id=%d', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id))
cr.execute('select act_from,act_to,body,date_sent from res_request where id=%d', (id,))
values = cr.dictfetchone()
# this will be truncated automatically at creation
values['name'] = values['body'] or '/'
values['req_id'] = id
self.pool.get('res.request.history').create(cr, uid, values)
return True
def request_reply(self, cr, uid, ids, *args):
for id in ids:
cr.execute("update res_request set state='active', act_from=%d, act_to=act_from, trigger_date=NULL, body='' where id=%d", (uid,id))
return True
def request_close(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state':'closed', 'active':False})
return True
def request_get(self, cr, uid):
cr.execute('select id from res_request where act_to=%d and (trigger_date<=%s or trigger_date is null) and active=True', (uid,time.strftime('%Y-%m-%d')))
ids = map(lambda x:x[0], cr.fetchall())
cr.execute('select id from res_request where act_from=%d and (act_to<>%d) and (trigger_date<=%s or trigger_date is null) and active=True', (uid,uid,time.strftime('%Y-%m-%d')))
ids2 = map(lambda x:x[0], cr.fetchall())
return (ids, ids2)
_columns = {
'create_date': fields.datetime('Created date', readonly=True),
'name': fields.char('Subject', states={'waiting':[('readonly',True)],'active':[('readonly',True)],'closed':[('readonly',True)]}, required=True, size=128),
'active': fields.boolean('Active'),
'priority': fields.selection([('0','Low'),('1','Normal'),('2','High')], 'Priority', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, required=True),
'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}),
'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
'body': fields.text('Request', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
'date_sent': fields.datetime('Date', readonly=True),
'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
'ref_partner_id':fields.many2one('res.partner', 'Partner Ref.', states={'closed':[('readonly',True)]}),
'ref_doc1':fields.reference('Document Ref 1', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
'ref_doc2':fields.reference('Document Ref 2', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
'state': fields.selection([('draft','draft'),('waiting','waiting'),('active','active'),('closed','closed')], 'State', required=True, readonly=True),
'history': fields.one2many('res.request.history','req_id', 'History')
}
_defaults = {
'act_from': lambda obj,cr,uid,context={}: uid,
'act_to': lambda obj,cr,uid,context={}: uid,
'state': lambda obj,cr,uid,context={}: 'draft',
'active': lambda obj,cr,uid,context={}: True,
'priority': lambda obj,cr,uid,context={}: '1',
}
_order = 'priority desc, trigger_date, create_date desc'
_table = 'res_request'
res_request()
class res_request_link(osv.osv):
_name = 'res.request.link'
_columns = {
'name': fields.char('Name', size=64, required=True, translate=True),
'object': fields.char('Object', size=64, required=True),
'priority': fields.integer('Priority'),
}
_defaults = {
'priority': lambda *a: 5,
}
_order = 'priority'
res_request_link()
class res_request_history(osv.osv):
_name = 'res.request.history'
_columns = {
'name': fields.char('Summary', size=128, states={'active':[('readonly',True)],'waiting':[('readonly',True)]}, required=True),
'req_id': fields.many2one('res.request', 'Request', required=True, ondelete='cascade', select=True),
'act_from': fields.many2one('res.users', 'From', required=True, readonly=True),
'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)]}),
'body': fields.text('Body', states={'waiting':[('readonly',True)]}),
'date_sent': fields.datetime('Date sent', states={'waiting':[('readonly',True)]}, required=True)
}
_defaults = {
'name': lambda *a: 'NoName',
'act_from': lambda obj,cr,uid,context={}: uid,
'act_to': lambda obj,cr,uid,context={}: uid,
'date_sent': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
}
res_request_history()

View File

@ -0,0 +1,125 @@
<?xml version="1.0"?>
<terp>
<data>
<record model="ir.ui.view" id="res_request_tree-view">
<field name="name">res.request.tree</field>
<field name="model">res.request</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Requests">
<field name="create_date" />
<field name="act_from"/>
<field name="act_to"/>
<field name="name"/>
<!--
<field name="act_title"/>
-->
<field name="priority"/>
<field name="trigger_date"/>
<!--
<field name="ref_partner_id"/>
-->
<field name="state"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="res_request-view">
<field name="name">res.request.form</field>
<field name="model">res.request</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Requests">
<notebook>
<page string="Request">
<separator string="Description" colspan="4"/>
<field name="act_from" select="1"/>
<field name="act_to" select="1"/>
<field name="name" colspan="3" select="1"/>
<newline/>
<field name="body" colspan="4" select="1"/>
<field name="trigger_date" select="1"/>
<group col="2" colspan="2">
<button name="request_send" states="draft,active" string="Send" type="object"/>
<button name="request_reply" states="waiting" string="Reply" type="object"/>
</group>
<separator string="References" colspan="4"/>
<field name="ref_partner_id"/>
<field name="priority" select="1"/>
<field name="ref_doc1" colspan="3"/>
<field name="ref_doc2" colspan="3"/>
<separator string="Status" colspan="4"/>
<field name="state"/>
<group col="3" colspan="2">
<field name="active" select="1"/>
<button name="request_close" states="waiting,draft,active" string="End of Request" type="object"/>
</group>
</page><page string="History">
<field name="history" nolabel="1" colspan="4" widget="one2many_list"/>
</page>
</notebook>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="res_request-act">
<field name="name">res.request.form</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.request</field>
<field name="view_type">form</field>
<field name="view_id" ref="res_request-view"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Requests/All Requests" action="res_request-act"/>
<record model="ir.ui.view" id="res_request_link-view">
<field name="name">res.request.link.form</field>
<field name="model">res.request.link</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Request Link">
<field name="name" select="1"/>
<field name="object" select="1"/>
<field name="priority"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="res_request_link-act">
<field name="name">res.request.link.form</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.request.link</field>
<field name="view_type">form</field>
<field name="view_id" ref="res_request_link-view"/>
</record>
<menuitem name="Administration/Custom/Low level/Base/Requests/Request Links" action="res_request_link-act"/>
<record model="ir.ui.view" id="res_request_history_tree-view">
<field name="name">res.request.history.tree</field>
<field name="model">res.request.history</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Request History">
<field name="act_from"/>
<field name="act_to"/>
<field name="date_sent"/>
<field name="name"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="res_request_history_form-view">
<field name="name">res.request.history.form</field>
<field name="model">res.request.history</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Request History">
<field name="act_from"/>
<field name="act_to"/>
<field name="date_sent"/>
<newline/>
<field name="body" colspan="3"/>
</form>
</field>
</record>
</data>
</terp>

View File

@ -0,0 +1,122 @@
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
# Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import fields,osv
import tools
class groups(osv.osv):
_name = "res.groups"
_columns = {
'name': fields.char('Group Name', size=64, required=True),
}
groups()
class roles(osv.osv):
_name = "res.roles"
_columns = {
'name': fields.char('Role Name', size=64, required=True),
'parent_id': fields.many2one('res.roles', 'Parent', select=True),
'child_id': fields.one2many('res.roles', 'parent_id', 'Childs')
}
_defaults = {
}
def check(self, cr, uid, ids, role_id):
if role_id in ids:
return True
cr.execute('select parent_id from res_roles where id=%d', (role_id,))
roles = cr.fetchone()[0]
if roles:
return self.check(cr, uid, ids, roles[0])
return False
roles()
class lang(osv.osv):
_name = "res.lang"
_columns = {
'name': fields.char('Name', size=64, required=True),
'code': fields.char('Code', size=5, required=True),
'translatable': fields.boolean('Translatable'),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a: 1,
'translatable': lambda *a: 0,
}
lang()
class users(osv.osv):
_name = "res.users"
_log_access = False
_columns = {
'name': fields.char('Name', size=64, required=True, select=True),
'login': fields.char('Login', size=64, required=True),
'password': fields.char('Password', size=64, invisible=True),
'signature': fields.text('Signature', size=64),
'address_id': fields.many2one('res.partner.address', 'Address'),
'active': fields.boolean('Active'),
'action_id': fields.many2one('ir.actions.actions', 'Action'),
'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'groups'),
'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
'company_id': fields.many2one('res.company', 'Company'),
}
_sql_constraints = [
('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !')
]
_defaults = {
'password' : lambda obj,cr,uid,context={} : '',
'active' : lambda obj,cr,uid,context={} : True,
}
def company_get(self, cr, uid, uid2):
company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
return company_id
company_get = tools.cache()(company_get)
def write(self, cr, uid, *args, **argv):
res = super(users, self).write(cr, uid, *args, **argv)
# Restart the cache on the company_get method
self.company_get()
return res
def unlink(self, cr, uid, ids):
if 1 in ids:
raise osv.except_osv('Can not remove root user !', 'You can not remove the root user as it is used internally for resources created by Tiny ERP (updates, module installation, ...)')
return super(users, self).unlink(cr, uid, ids)
def name_search(self, cr, user, name, args=[], operator='ilike', context={}):
ids = self.search(cr, user, [('login','=',name)]+ args)
if not ids:
ids = self.search(cr, user, [('name',operator,name)]+ args)
return self.name_get(cr, user, ids)
def copy(self, cr, uid, id, default=None, context={}):
login = self.read(cr, uid, [id], ['login'])[0]['login']
default.update({'login': login+' (copy)'})
return super(users, self).copy(cr, uid, id, default, context)
users()

3
bin/addons/gen_graph.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
./module_graph.py | dot -Tpng -o > module_graph.png

View File

@ -0,0 +1,12 @@
#!/usr/bin/python
import os
print 'digraph G {'
for f in os.listdir('.'):
if os.path.isfile(os.path.join(f,"__terp__.py")):
info=eval(file(os.path.join(f,"__terp__.py")).read())
if info.get('active', True):
for name in info['depends']:
print '\t%s -> %s;' % (f, name)
print '}'

278
bin/gpl.txt Normal file
View File

@ -0,0 +1,278 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

6
bin/i18n/VERSION Normal file
View File

@ -0,0 +1,6 @@
Files downloaded on
2006-08-07
from
http://tinyforge.org/softwaremap/trove_list.php?form_cat=309&discrim=309

4014
bin/i18n/cs_CZ.csv Normal file

File diff suppressed because it is too large Load Diff

4577
bin/i18n/de_DE.csv Normal file

File diff suppressed because it is too large Load Diff

4016
bin/i18n/es_AR.csv Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More