2
##############################################################################
4
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
6
# $Id: misc.py 1304 2005-09-08 14:35:42Z nicoe $
8
# WARNING: This program as such is intended to be used by professional
9
# programmers who take the whole responsability of assessing all potential
10
# consequences resulting from its eventual inadequacies and bugs
11
# End users who are looking for a ready-to-use solution with commercial
12
# garantees and support are strongly adviced to contract a Free Software
15
# This program is Free Software; you can redistribute it and/or
16
# modify it under the terms of the GNU General Public License
17
# as published by the Free Software Foundation; either version 2
18
# of the License, or (at your option) any later version.
20
# This program is distributed in the hope that it will be useful,
21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
# GNU General Public License for more details.
25
# You should have received a copy of the GNU General Public License
26
# along with this program; if not, write to the Free Software
27
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
##############################################################################
32
Miscelleanous tools used by tiny ERP.
40
from config import config
43
if sys.version_info[:2] < (2, 4):
44
from threadinglocal import local
46
from threading import local
48
# initialize a database with base/base.sql
50
f = os.path.join(config['addons_path'], 'base/base.sql')
51
for line in file(f).read().split(';'):
52
if (len(line)>0) and (not line.isspace()):
57
ad = config['addons_path']
59
for i in os.listdir(ad):
60
terp_file = opj(ad, i, '__terp__.py')
61
if os.path.isfile(terp_file):
62
info = eval(file(terp_file).read())
63
categs = info.get('category', 'Uncategorized').split('/')
67
cr.execute('select id from ir_module_category where name=%s and parent_id=%d', (categs[0], p_id))
69
cr.execute('select id from ir_module_category where name=%s and parent_id is NULL', (categs[0],))
72
cr.execute('select nextval(\'ir_module_category_id_seq\')')
73
c_id = cr.fetchone()[0]
74
cr.execute('insert into ir_module_category (id, name, parent_id) values (%d, %s, %d)', (c_id, categs[0], p_id))
80
active = info.get('active', True)
81
installable = info.get('installable', True)
88
state = 'uninstallable'
89
cr.execute('select nextval(\'ir_module_module_id_seq\')')
91
cr.execute('insert into ir_module_module (id, author, latest_version, website, name, shortdesc, description, category_id, state) values (%d, %s, %s, %s, %s, %s, %s, %d, %s)', (
93
info.get('author', ''),
94
info.get('version', ''),
95
info.get('website', ''),
97
info.get('name', False),
98
info.get('description', ''),
101
dependencies = info.get('depends', [])
102
for d in dependencies:
103
cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (id, d))
106
def find_in_path(name):
107
path = [dir for dir in os.environ['PATH'].split(':')
108
if os.path.isdir(dir)]
110
if name in os.listdir(dir):
111
return os.path.join(dir, name)
114
def find_pg_tool(name):
115
if config['pg_path'] and config['pg_path'] != 'None':
116
return os.path.join(config['pg_path'], name)
118
return find_in_path(name)
120
def exec_pg_command(name, *args):
121
prog = find_pg_tool(name)
122
args2 = (os.path.basename(prog),) + args
123
return os.spawnv(os.P_WAIT, prog, args2)
124
# os.spawnv(os.P_WAIT, prog, ([os.path.basename(prog)] + args))
126
def exec_pg_command_pipe(name, *args):
127
prog = find_pg_tool(name)
129
cmd = '"' + prog + '" ' + ' '.join(args)
131
cmd = prog + ' ' + ' '.join(args)
132
return os.popen2(cmd, 'b')
134
#----------------------------------------------------------
136
#----------------------------------------------------------
137
#file_path_root = os.getcwd()
138
#file_path_addons = os.path.join(file_path_root, 'addons')
140
def file_open(name, mode="r", subdir='addons'):
141
"""Open a file from the Tiny ERP root, using a subdir folder."""
142
name = os.path.join(config['root_path'], subdir, name)
143
return file(name, mode)
145
#----------------------------------------------------------
147
#----------------------------------------------------------
148
def email_send(email_from, email_to, subject, body, email_cc=[], email_bcc=[], on_error=False, reply_to=False):
151
from email.MIMEText import MIMEText
152
from email.MIMEMultipart import MIMEMultipart
153
from email.Header import Header
154
from email.Utils import formatdate, COMMASPACE
156
msg = MIMEText(body or '', _charset='utf-8')
157
msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
158
msg['From'] = email_from
160
msg['Reply-To'] = msg['From']+', '+reply_to
161
msg['To'] = COMMASPACE.join(email_to)
163
msg['Cc'] = COMMASPACE.join(email_cc)
165
msg['Bcc'] = COMMASPACE.join(email_bcc)
166
msg['Date'] = formatdate(localtime=True)
169
s.connect(config['smtp_server'])
170
s.sendmail(email_from, email_to + email_cc + email_bcc, msg.as_string())
174
logging.getLogger().info(str(e))
177
#----------------------------------------------------------
179
#----------------------------------------------------------
180
# text must be latin-1 encoded
181
def sms_send(user, password, api_id, text, to):
183
params = urllib.urlencode({'user': user, 'password': password, 'api_id': api_id, 'text': text, 'to':to})
184
#print "http://api.clickatell.com/http/sendmsg", params
185
#f = urllib.urlopen("http://api.clickatell.com/http/sendmsg", params)
186
print "http://196.7.150.220/http/sendmsg", params
187
f = urllib.urlopen("http://196.7.150.220/http/sendmsg", params)
191
#---------------------------------------------------------
192
# Class that stores an updateable string (used in wizards)
193
#---------------------------------------------------------
194
class UpdateableStr(local):
196
def __init__(self, string=''):
200
return str(self.string)
203
return str(self.string)
205
def __nonzero__(self):
206
return bool(self.string)
208
class currency(float):
210
def __init__(self, value, accuracy=2, rounding=None):
212
rounding=10**-accuracy
213
self.rounding=rounding
214
self.accuracy=accuracy
216
def __new__(cls, value, accuracy=2, rounding=None):
217
return float.__new__(cls, round(value, accuracy))
220
# display_value = int(self*(10**(-self.accuracy))/self.rounding)*self.rounding/(10**(-self.accuracy))
221
# return str(display_value)
225
# Use it as a decorator of the function you plan to cache
226
# Timeout: 0 = no timeout, otherwise in seconds
229
def __init__(self, timeout=10000, skiparg=2):
230
self.timeout = timeout
233
def __call__(self, fn):
234
arg_names = inspect.getargspec(fn)[0][2:]
235
def cached_result(self2, cr=None, *args, **kwargs):
240
# Update named arguments with positional argument values
241
kwargs.update(dict(zip(arg_names, args)))
242
kwargs = kwargs.items()
245
# Work out key as a tuple of ('argname', value) pairs
246
key = (('dbname', cr.dbname),) + tuple(kwargs)
248
# Check cache and return cached value if possible
249
if key in self.cache:
250
(value, last_time) = self.cache[key]
251
mintime = time.time() - self.timeout
252
if self.timeout <= 0 or mintime <= last_time:
257
# Clear Cache at this point ?
260
# Work out new value, cache it and return it
261
# Should copy() this value to avoid futur modf of the cacle ?
262
result = fn(self2,cr,**dict(kwargs))
264
self.cache[key] = (result, time.time())
270
'zh_CN': 'Chinese (CN)',
271
'zh_TW': 'Chinese (TW)',
274
'es_AR': 'Español (Argentina)',
275
'es_ES': 'Español (España)',
277
'fr_CH': 'Français (Suisse)',
278
'en_EN': 'English (default)',
279
'hu_HU': 'Hungarian',
281
'pt_BR': 'Portugese (Brasil)',
282
'pt_PT': 'Portugese (Portugal)',
283
'nl_NL': 'Nederlands',
290
def scan_languages():
292
file_list = [os.path.splitext(os.path.basename(f))[0] for f in glob.glob(os.path.join(config['root_path'], 'i18n', '*.csv'))]
293
lang_dict = get_languages()
294
return [(lang, lang_dict.get(lang, lang)) for lang in file_list]