You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

__init__.py 17 KiB

13 vuotta sitten
13 vuotta sitten
13 vuotta sitten
14 vuotta sitten
14 vuotta sitten
14 vuotta sitten
14 vuotta sitten
14 vuotta sitten
14 vuotta sitten
13 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. # util __init__.py
  23. import webnotes
  24. user_time_zone = None
  25. month_name = ['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
  26. month_name_full = ['','January','February','March','April','May','June','July','August','September','October','November','December']
  27. no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable', 'Button', 'Image', 'Graph']
  28. default_fields = ['doctype','name','owner','creation','modified','modified_by','parent','parentfield','parenttype','idx','docstatus']
  29. def getCSVelement(v):
  30. """
  31. Returns the CSV value of `v`, For example:
  32. * apple becomes "apple"
  33. * hi"there becomes "hi""there"
  34. """
  35. v = cstr(v)
  36. if not v: return ''
  37. if (',' in v) or ('\n' in v) or ('"' in v):
  38. if '"' in v: v = v.replace('"', '""')
  39. return '"'+v+'"'
  40. else: return v or ''
  41. def get_fullname(profile):
  42. """get the full name (first name + last name) of the user from Profile"""
  43. p = webnotes.conn.sql("""select first_name, last_name from `tabProfile`
  44. where name=%s""", profile, as_dict=1)
  45. if p:
  46. p = p[0]
  47. full_name = (p['first_name'] and (p['first_name'] + ' ') or '') + (p['last_name'] or '')
  48. return full_name or profile
  49. else:
  50. return profile
  51. def extract_email_id(s):
  52. """
  53. Extract email id from email header format
  54. """
  55. if '<' in s:
  56. s = s.split('<')[1].split('>')[0]
  57. if s:
  58. s = s.strip().lower()
  59. return s
  60. def validate_email_add(email_str):
  61. """
  62. Validates the email string
  63. """
  64. s = extract_email_id(email_str)
  65. import re
  66. #return re.match("^[a-zA-Z0-9._%-]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email_str)
  67. return re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", s)
  68. def sendmail(recipients, sender='', msg='', subject='[No Subject]', parts=[], cc=[], attach=[]):
  69. """
  70. Send an email. For more details see :func:`email_lib.sendmail`
  71. """
  72. import webnotes.utils.email_lib
  73. return email_lib.sendmail(recipients, sender, msg, subject, parts, cc, attach)
  74. def generate_hash():
  75. """
  76. Generates random hash for session id
  77. """
  78. import hashlib, time
  79. return hashlib.sha224(str(time.time())).hexdigest()
  80. def random_string(length):
  81. """generate a random string"""
  82. import string
  83. from random import choice
  84. return ''.join([choice(string.letters + string.digits) for i in range(length)])
  85. def db_exists(dt, dn):
  86. return webnotes.conn.sql('select name from `tab%s` where name="%s"' % (dt, dn))
  87. def load_json(arg):
  88. # already a dictionary?
  89. if not isinstance(arg, basestring):
  90. return arg
  91. import json
  92. return json.loads(arg, encoding='utf-8')
  93. # Get Traceback
  94. # ==============================================================================
  95. def getTraceback():
  96. """
  97. Returns the traceback of the Exception
  98. """
  99. import sys, traceback, string
  100. type, value, tb = sys.exc_info()
  101. body = "Traceback (innermost last):\n"
  102. list = traceback.format_tb(tb, None) + traceback.format_exception_only(type, value)
  103. body = body + "%-20s %s" % (string.join(list[:-1], ""), list[-1])
  104. if webnotes.logger:
  105. webnotes.logger.error('Db:'+(webnotes.conn and webnotes.conn.cur_db_name or '') + ' - ' + body)
  106. return body
  107. # Log
  108. # ==============================================================================
  109. def log(event, details):
  110. webnotes.logger.info(details)
  111. # Date and Time
  112. # ==============================================================================
  113. def getdate(string_date):
  114. """
  115. Coverts string date (yyyy-mm-dd) to datetime.date object
  116. """
  117. import datetime
  118. if type(string_date)==unicode:
  119. string_date = str(string_date)
  120. if type(string_date) in (datetime.datetime, datetime.date):
  121. return string_date
  122. if ' ' in string_date:
  123. string_date = string_date.split(' ')[0]
  124. t = string_date.split('-')
  125. if len(t)==3:
  126. return datetime.date(cint(t[0]), cint(t[1]), cint(t[2]))
  127. else:
  128. return ''
  129. def add_days(date, days, format='string'):
  130. """
  131. Adds `days` to the given `string_date`
  132. """
  133. import datetime
  134. if not date:
  135. date = now_datetime()
  136. if type(date) not in (datetime.datetime, datetime.date):
  137. date = getdate(date)
  138. dt = date + datetime.timedelta(days)
  139. if format=='string':
  140. return dt.strftime('%Y-%m-%d')
  141. else:
  142. return dt
  143. def add_months(string_date, months):
  144. import datetime
  145. return webnotes.conn.sql("select DATE_ADD('%s',INTERVAL '%s' MONTH)" % (getdate(string_date),months))[0][0]
  146. def add_years(string_date, years):
  147. import datetime
  148. return webnotes.conn.sql("select DATE_ADD('%s',INTERVAL '%s' YEAR)" % (getdate(string_date),years))[0][0]
  149. def date_diff(string_ed_date, string_st_date=None):
  150. import datetime
  151. return webnotes.conn.sql("SELECT DATEDIFF('%s','%s')" %(getdate(string_ed_date), getdate(string_st_date)))[0][0]
  152. def now_datetime():
  153. global user_time_zone
  154. from datetime import datetime
  155. from pytz import timezone
  156. # get localtime
  157. if not user_time_zone:
  158. user_time_zone = webnotes.conn.get_value('Control Panel', None, 'time_zone') \
  159. or 'Asia/Calcutta'
  160. # convert to UTC
  161. utcnow = timezone('UTC').localize(datetime.utcnow())
  162. # convert to user time zone
  163. return utcnow.astimezone(timezone(user_time_zone))
  164. def now():
  165. """return current datetime as yyyy-mm-dd hh:mm:ss"""
  166. return now_datetime().strftime('%Y-%m-%d %H:%M:%S')
  167. def nowdate():
  168. """return current date as yyyy-mm-dd"""
  169. return now_datetime().strftime('%Y-%m-%d')
  170. def nowtime():
  171. """return current time in hh:mm"""
  172. return now_datetime().strftime('%H:%M')
  173. def get_first_day(dt, d_years=0, d_months=0):
  174. """
  175. Returns the first day of the month for the date specified by date object
  176. Also adds `d_years` and `d_months` if specified
  177. """
  178. import datetime
  179. # d_years, d_months are "deltas" to apply to dt
  180. y, m = dt.year + d_years, dt.month + d_months
  181. a, m = divmod(m-1, 12)
  182. return datetime.date(y+a, m+1, 1)
  183. def get_last_day(dt):
  184. """
  185. Returns last day of the month using:
  186. `get_first_day(dt, 0, 1) + datetime.timedelta(-1)`
  187. """
  188. import datetime
  189. return get_first_day(dt, 0, 1) + datetime.timedelta(-1)
  190. user_format = None
  191. """
  192. User format specified in :term:`Control Panel`
  193. Examples:
  194. * dd-mm-yyyy
  195. * mm-dd-yyyy
  196. * dd/mm/yyyy
  197. """
  198. def formatdate(string_date):
  199. """
  200. Convers the given string date to :data:`user_format`
  201. """
  202. global user_format
  203. if not user_format:
  204. user_format = webnotes.conn.get_value('Control Panel', None, 'date_format')
  205. d = string_date.split('-');
  206. out = user_format
  207. return out.replace('dd', ('%.2i' % cint(d[2]))).replace('mm', ('%.2i' % cint(d[1]))).replace('yyyy', d[0])
  208. def dict_to_str(args, sep='&'):
  209. """
  210. Converts a dictionary to URL
  211. """
  212. import urllib
  213. t = []
  214. for k in args.keys():
  215. t.append(str(k)+'='+urllib.quote(str(args[k] or '')))
  216. return sep.join(t)
  217. def timestamps_equal(t1, t2):
  218. """Returns true if same the two string timestamps are same"""
  219. scrub = lambda x: x.replace(':', ' ').replace('-',' ').split()
  220. t1, t2 = scrub(t1), scrub(t2)
  221. if len(t1) != len(t2):
  222. return
  223. for i in range(len(t1)):
  224. if t1[i]!=t2[i]:
  225. return
  226. return 1
  227. def global_date_format(date):
  228. """returns date as 1 January 2012"""
  229. import datetime
  230. if isinstance(date, basestring):
  231. date = getdate(date)
  232. return date.strftime('%d') + ' ' + month_name_full[int(date.strftime('%m'))] \
  233. + ' ' + date.strftime('%Y')
  234. # Datatype
  235. # ==============================================================================
  236. def isNull(v):
  237. """
  238. Returns true if v='' or v is `None`
  239. """
  240. return (v=='' or v==None)
  241. def has_common(l1, l2):
  242. """
  243. Returns true if there are common elements in lists l1 and l2
  244. """
  245. for l in l1:
  246. if l in l2:
  247. return 1
  248. return 0
  249. def flt(s):
  250. """
  251. Convert to float (ignore commas)
  252. """
  253. if isinstance(s, basestring): # if string
  254. s = s.replace(',','')
  255. try: tmp = float(s)
  256. except: tmp = 0
  257. return tmp
  258. def cint(s):
  259. """
  260. Convert to integer
  261. """
  262. try: tmp = int(float(s))
  263. except: tmp = 0
  264. return tmp
  265. def cstr(s):
  266. """
  267. Convert to string
  268. """
  269. if isinstance(s, basestring):
  270. return s
  271. elif s==None:
  272. return ''
  273. else:
  274. return str(s)
  275. def str_esc_quote(s):
  276. """
  277. Escape quotes
  278. """
  279. if s==None:return ''
  280. return s.replace("'","\'")
  281. def replace_newlines(s):
  282. """
  283. Replace newlines by '<br>'
  284. """
  285. if s==None:return ''
  286. return s.replace("\n","<br>")
  287. # ==============================================================================
  288. def parse_val(v):
  289. """
  290. Converts to simple datatypes from SQL query results
  291. """
  292. import datetime
  293. if type(v)==datetime.date:
  294. v = str(v)
  295. elif type(v)==datetime.timedelta:
  296. v = ':'.join(str(v).split(':')[:2])
  297. elif type(v)==datetime.datetime:
  298. v = str(v)
  299. elif type(v)==long: v=int(v)
  300. return v
  301. # ==============================================================================
  302. def fmt_money(amount, fmt = '%.2f'):
  303. """
  304. Convert to string with commas for thousands, millions etc
  305. """
  306. curr = webnotes.conn.get_value('Control Panel', None, 'currency_format') or 'Millions'
  307. val = 2
  308. if curr == 'Millions': val = 3
  309. if cstr(amount).find('.') == -1: temp = '00'
  310. else: temp = cstr(amount).split('.')[1]
  311. l = []
  312. minus = ''
  313. if flt(amount) < 0: minus = '-'
  314. amount = ''.join(cstr(amount).split(','))
  315. amount = cstr(abs(flt(amount))).split('.')[0]
  316. # main logic
  317. if len(cstr(amount)) > 3:
  318. nn = amount[len(amount)-3:]
  319. l.append(nn)
  320. amount = amount[0:len(amount)-3]
  321. while len(cstr(amount)) > val:
  322. nn = amount[len(amount)-val:]
  323. l.insert(0,nn)
  324. amount = amount[0:len(amount)-val]
  325. if len(amount) > 0: l.insert(0,amount)
  326. amount = ','.join(l)+'.'+temp
  327. amount = minus + amount
  328. return amount
  329. #
  330. # convet currency to words
  331. #
  332. def money_in_words(number, main_currency = None, fraction_currency=None):
  333. """
  334. Returns string in words with currency and fraction currency.
  335. """
  336. d = get_defaults()
  337. if not main_currency:
  338. main_currency = d.get('currency', 'INR')
  339. if not fraction_currency:
  340. fraction_currency = d.get('fraction_currency', 'paise')
  341. n = "%.2f" % flt(number)
  342. main, fraction = n.split('.')
  343. if len(fraction)==1: fraction += '0'
  344. out = main_currency + ' ' + in_words(main).title()
  345. if cint(fraction):
  346. out = out + ' and ' + in_words(fraction).title() + ' ' + fraction_currency
  347. return out + ' only.'
  348. #
  349. # convert number to words
  350. #
  351. def in_words(integer):
  352. """
  353. Returns string in words for the given integer.
  354. """
  355. in_million = webnotes.conn.get_default('currency_format')=='Millions' and 1 or 0
  356. n=int(integer)
  357. known = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
  358. 11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen',
  359. 19: 'nineteen', 20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}
  360. def psn(n, known, xpsn):
  361. import sys;
  362. if n in known: return known[n]
  363. bestguess, remainder = str(n), 0
  364. if n<=20:
  365. print >>sys.stderr, n, "How did this happen?"
  366. assert 0
  367. elif n < 100:
  368. bestguess= xpsn((n//10)*10, known, xpsn) + '-' + xpsn(n%10, known, xpsn)
  369. return bestguess
  370. elif n < 1000:
  371. bestguess= xpsn(n//100, known, xpsn) + ' ' + 'hundred'
  372. remainder = n%100
  373. else:
  374. if in_million:
  375. if n < 1000000:
  376. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  377. remainder = n%1000
  378. elif n < 1000000000:
  379. bestguess= xpsn(n//1000000, known, xpsn) + ' ' + 'million'
  380. remainder = n%1000000
  381. else:
  382. bestguess= xpsn(n//1000000000, known, xpsn) + ' ' + 'billion'
  383. remainder = n%1000000000
  384. else:
  385. if n < 100000:
  386. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  387. remainder = n%1000
  388. elif n < 10000000:
  389. bestguess= xpsn(n//100000, known, xpsn) + ' ' + 'lakh'
  390. remainder = n%100000
  391. else:
  392. bestguess= xpsn(n//10000000, known, xpsn) + ' ' + 'crore'
  393. remainder = n%10000000
  394. if remainder:
  395. if remainder >= 100:
  396. comma = ','
  397. else:
  398. comma = ''
  399. return bestguess + comma + ' ' + xpsn(remainder, known, xpsn)
  400. else:
  401. return bestguess
  402. return psn(n, known, psn)
  403. # Get Defaults
  404. # ==============================================================================
  405. def get_defaults(key=None):
  406. """
  407. Get dictionary of default values from the :term:`Control Panel`, or a value if key is passed
  408. """
  409. return webnotes.conn.get_defaults(key)
  410. def set_default(key, val):
  411. """
  412. Set / add a default value to :term:`Control Panel`
  413. """
  414. return webnotes.conn.set_default(key, val)
  415. #
  416. # Clear recycle bin
  417. #
  418. def clear_recycle_bin():
  419. sql = webnotes.conn.sql
  420. tl = sql('show tables')
  421. total_deleted = 0
  422. for t in tl:
  423. fl = [i[0] for i in sql('desc `%s`' % t[0])]
  424. if 'name' in fl:
  425. total_deleted += sql("select count(*) from `%s` where name like '__overwritten:%%'" % t[0])[0][0]
  426. sql("delete from `%s` where name like '__overwritten:%%'" % t[0])
  427. if 'parent' in fl:
  428. total_deleted += sql("select count(*) from `%s` where parent like '__oldparent:%%'" % t[0])[0][0]
  429. sql("delete from `%s` where parent like '__oldparent:%%'" % t[0])
  430. total_deleted += sql("select count(*) from `%s` where parent like 'oldparent:%%'" % t[0])[0][0]
  431. sql("delete from `%s` where parent like 'oldparent:%%'" % t[0])
  432. total_deleted += sql("select count(*) from `%s` where parent like 'old_parent:%%'" % t[0])[0][0]
  433. sql("delete from `%s` where parent like 'old_parent:%%'" % t[0])
  434. return "%s records deleted" % str(int(total_deleted))
  435. # Dictionary utils
  436. # ==============================================================================
  437. def remove_blanks(d):
  438. """
  439. Returns d with empty ('' or None) values stripped
  440. """
  441. empty_keys = []
  442. for key in d:
  443. if d[key]=='' or d[key]==None:
  444. # del d[key] raises runtime exception, using a workaround
  445. empty_keys.append(key)
  446. for key in empty_keys:
  447. del d[key]
  448. return d
  449. def pprint_dict(d, level=1, no_blanks=True):
  450. """
  451. Pretty print a dictionary with indents
  452. """
  453. if no_blanks:
  454. remove_blanks(d)
  455. # make indent
  456. indent, ret = '', ''
  457. for i in range(0,level): indent += '\t'
  458. # add lines
  459. comment, lines = '', []
  460. kl = d.keys()
  461. kl.sort()
  462. # make lines
  463. for key in kl:
  464. if key != '##comment':
  465. tmp = {key: d[key]}
  466. lines.append(indent + str(tmp)[1:-1] )
  467. # add comment string
  468. if '##comment' in kl:
  469. ret = ('\n' + indent) + '# ' + d['##comment'] + '\n'
  470. # open
  471. ret += indent + '{\n'
  472. # lines
  473. ret += indent + ',\n\t'.join(lines)
  474. # close
  475. ret += '\n' + indent + '}'
  476. return ret
  477. def get_common(d1,d2):
  478. """
  479. returns (list of keys) the common part of two dicts
  480. """
  481. return [p for p in d1 if p in d2 and d1[p]==d2[p]]
  482. def get_common_dict(d1, d2):
  483. """
  484. return common dictionary of d1 and d2
  485. """
  486. ret = {}
  487. for key in d1:
  488. if key in d2 and d2[key]==d1[key]:
  489. ret[key] = d1[key]
  490. return ret
  491. def get_diff_dict(d1, d2):
  492. """
  493. return common dictionary of d1 and d2
  494. """
  495. diff_keys = set(d2.keys()).difference(set(d1.keys()))
  496. ret = {}
  497. for d in diff_keys: ret[d] = d2[d]
  498. return ret
  499. def get_file_timestamp(fn):
  500. """
  501. Returns timestamp of the given file
  502. """
  503. import os
  504. from webnotes.utils import cint
  505. try:
  506. return str(cint(os.stat(fn).st_mtime))
  507. except OSError, e:
  508. if e.args[0]!=2:
  509. raise e
  510. else:
  511. return None
  512. # to be deprecated
  513. def make_esc(esc_chars):
  514. """
  515. Function generator for Escaping special characters
  516. """
  517. return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
  518. # esc / unescape characters -- used for command line
  519. def esc(s, esc_chars):
  520. """
  521. Escape special characters
  522. """
  523. for c in esc_chars:
  524. esc_str = '\\' + c
  525. s = s.replace(c, esc_str)
  526. return s
  527. def unesc(s, esc_chars):
  528. """
  529. UnEscape special characters
  530. """
  531. for c in esc_chars:
  532. esc_str = '\\' + c
  533. s = s.replace(esc_str, c)
  534. return s
  535. def get_doctype_label(dt=None):
  536. """
  537. Gets label of a doctype
  538. """
  539. if dt:
  540. res = webnotes.conn.sql("""\
  541. SELECT name, dt_label FROM `tabDocType Label`
  542. WHERE name=%s""", dt)
  543. return res and res[0][0] or dt
  544. else:
  545. res = webnotes.conn.sql("SELECT name, dt_label FROM `tabDocType Label`")
  546. dt_label_dict = {}
  547. for r in res:
  548. dt_label_dict[r[0]] = r[1]
  549. return dt_label_dict
  550. def get_label_doctype(label):
  551. """
  552. Gets doctype from its label
  553. """
  554. res = webnotes.conn.sql("""\
  555. SELECT name FROM `tabDocType Label`
  556. WHERE dt_label=%s""", label)
  557. return res and res[0][0] or label