Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pirms 13 gadiem
pirms 13 gadiem
pirms 13 gadiem
pirms 12 gadiem
pirms 14 gadiem
pirms 14 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 12 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  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. from __future__ import unicode_literals
  24. import webnotes
  25. user_time_zone = None
  26. user_format = None
  27. no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable',
  28. 'Button', 'Image', 'Graph']
  29. default_fields = ['doctype', 'name', 'owner', 'creation', 'modified', 'modified_by',
  30. 'parent', 'parentfield', 'parenttype', 'idx', 'docstatus']
  31. # used in import_docs.py
  32. # TODO: deprecate it
  33. def getCSVelement(v):
  34. """
  35. Returns the CSV value of `v`, For example:
  36. * apple becomes "apple"
  37. * hi"there becomes "hi""there"
  38. """
  39. v = cstr(v)
  40. if not v: return ''
  41. if (',' in v) or ('\n' in v) or ('"' in v):
  42. if '"' in v: v = v.replace('"', '""')
  43. return '"'+v+'"'
  44. else: return v or ''
  45. def get_fullname(profile):
  46. """get the full name (first name + last name) of the user from Profile"""
  47. p = webnotes.conn.sql("""select first_name, last_name from `tabProfile`
  48. where name=%s""", profile, as_dict=1)
  49. if p:
  50. profile = " ".join(filter(None,
  51. [p[0].get('first_name'), p[0].get('last_name')])) or profile
  52. return profile
  53. def get_formatted_email(user):
  54. """get email id of user formatted as: John Doe <johndoe@example.com>"""
  55. if user == "Administrator":
  56. return user
  57. from email.utils import formataddr
  58. fullname = get_fullname(user)
  59. return formataddr((fullname, user))
  60. def extract_email_id(email):
  61. """fetch only the email part of the email id"""
  62. from email.utils import parseaddr
  63. if ',' in email and email.count("@")==1:
  64. email = email.split(",")[-1]
  65. fullname, email_id = parseaddr(email)
  66. return email_id
  67. def validate_email_add(email_str):
  68. """Validates the email string"""
  69. email = extract_email_id(email_str)
  70. import re
  71. 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])?", email.lower())
  72. def get_request_site_address(full_address=False):
  73. """get app url from request"""
  74. import os, conf
  75. if hasattr(conf, "host_name"):
  76. return conf.host_name
  77. else:
  78. try:
  79. protocol = 'HTTPS' in os.environ.get('SERVER_PROTOCOL') and 'https://' or 'http://'
  80. host = os.environ.get('HTTP_HOST')
  81. if full_address:
  82. return protocol + host + os.environ.get("REQUEST_URI")
  83. else:
  84. return protocol + host
  85. except TypeError:
  86. return 'http://localhost'
  87. def random_string(length):
  88. """generate a random string"""
  89. import string
  90. from random import choice
  91. return ''.join([choice(string.letters + string.digits) for i in range(length)])
  92. def load_json(arg):
  93. # already a dictionary?
  94. if not isinstance(arg, basestring):
  95. return arg
  96. import json
  97. return json.loads(arg, encoding='utf-8')
  98. # Get Traceback
  99. # ==============================================================================
  100. def getTraceback():
  101. """
  102. Returns the traceback of the Exception
  103. """
  104. import sys, traceback
  105. exc_type, value, tb = sys.exc_info()
  106. trace_list = traceback.format_tb(tb, None) + \
  107. traceback.format_exception_only(exc_type, value)
  108. body = "Traceback (innermost last):\n" + "%-20s %s" % \
  109. (unicode((b"").join(trace_list[:-1]), 'utf-8'), unicode(trace_list[-1], 'utf-8'))
  110. if webnotes.logger:
  111. webnotes.logger.error('Db:'+(webnotes.conn and webnotes.conn.cur_db_name or '') \
  112. + ' - ' + body)
  113. return body
  114. def log(event, details):
  115. webnotes.logger.info(details)
  116. # datetime functions
  117. def getdate(string_date):
  118. """
  119. Coverts string date (yyyy-mm-dd) to datetime.date object
  120. """
  121. import datetime
  122. if isinstance(string_date, datetime.date):
  123. return string_date
  124. elif isinstance(string_date, datetime.datetime):
  125. return datetime.date()
  126. if " " in string_date:
  127. string_date = string_date.split(" ")[0]
  128. try:
  129. return datetime.datetime.strptime(string_date, "%Y-%m-%d").date()
  130. except ValueError:
  131. webnotes.msgprint("Cannot understand date - '%s'" % \
  132. (string_date,), raise_exception=1)
  133. def add_to_date(date, years=0, months=0, days=0):
  134. """Adds `days` to the given date"""
  135. format = isinstance(date, basestring)
  136. if date:
  137. date = getdate(date)
  138. else:
  139. raise Exception, "Start date required"
  140. from dateutil.relativedelta import relativedelta
  141. date += relativedelta(years=years, months=months, days=days)
  142. if format:
  143. return date.strftime("%Y-%m-%d")
  144. else:
  145. return date
  146. def add_days(date, days):
  147. return add_to_date(date, days=days)
  148. def add_months(date, months):
  149. return add_to_date(date, months=months)
  150. def add_years(date, years):
  151. return add_to_date(date, years=years)
  152. def date_diff(string_ed_date, string_st_date):
  153. return (getdate(string_ed_date) - getdate(string_st_date)).days
  154. def time_diff(string_ed_date, string_st_date):
  155. return get_datetime(string_ed_date) - get_datetime(string_st_date)
  156. def time_diff_in_seconds(string_ed_date, string_st_date):
  157. return time_diff(string_ed_date, string_st_date).seconds
  158. def time_diff_in_hours(string_ed_date, string_st_date):
  159. return round(float(time_diff(string_ed_date, string_st_date).seconds) / 3600, 6)
  160. def now_datetime():
  161. from datetime import datetime
  162. return convert_utc_to_user_timezone(datetime.utcnow())
  163. def get_user_time_zone():
  164. global user_time_zone
  165. if not user_time_zone:
  166. user_time_zone = webnotes.cache().get_value("time_zone")
  167. if not user_time_zone:
  168. user_time_zone = webnotes.conn.get_value('Control Panel', None, 'time_zone') \
  169. or 'Asia/Calcutta'
  170. webnotes.cache().set_value("time_zone", user_time_zone)
  171. return user_time_zone
  172. def convert_utc_to_user_timezone(utc_timestamp):
  173. from pytz import timezone
  174. utcnow = timezone('UTC').localize(utc_timestamp)
  175. return utcnow.astimezone(timezone(get_user_time_zone()))
  176. def now():
  177. """return current datetime as yyyy-mm-dd hh:mm:ss"""
  178. return now_datetime().strftime('%Y-%m-%d %H:%M:%S')
  179. def nowdate():
  180. """return current date as yyyy-mm-dd"""
  181. return now_datetime().strftime('%Y-%m-%d')
  182. def today():
  183. return nowdate()
  184. def nowtime():
  185. """return current time in hh:mm"""
  186. return now_datetime().strftime('%H:%M')
  187. def get_first_day(dt, d_years=0, d_months=0):
  188. """
  189. Returns the first day of the month for the date specified by date object
  190. Also adds `d_years` and `d_months` if specified
  191. """
  192. import datetime
  193. dt = getdate(dt)
  194. # d_years, d_months are "deltas" to apply to dt
  195. overflow_years, month = divmod(dt.month + d_months - 1, 12)
  196. year = dt.year + d_years + overflow_years
  197. return datetime.date(year, month + 1, 1)
  198. def get_last_day(dt):
  199. """
  200. Returns last day of the month using:
  201. `get_first_day(dt, 0, 1) + datetime.timedelta(-1)`
  202. """
  203. import datetime
  204. return get_first_day(dt, 0, 1) + datetime.timedelta(-1)
  205. def get_datetime(datetime_str):
  206. from datetime import datetime
  207. if isinstance(datetime_str, datetime):
  208. return datetime_str.replace(microsecond=0, tzinfo=None)
  209. return datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
  210. def get_datetime_str(datetime_obj):
  211. if isinstance(datetime_obj, basestring):
  212. datetime_obj = get_datetime(datetime_obj)
  213. return datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
  214. def formatdate(string_date=None):
  215. """
  216. Convers the given string date to :data:`user_format`
  217. User format specified in :term:`Control Panel`
  218. Examples:
  219. * dd-mm-yyyy
  220. * mm-dd-yyyy
  221. * dd/mm/yyyy
  222. """
  223. if string_date:
  224. string_date = getdate(string_date)
  225. else:
  226. string_date = now_datetime().date()
  227. global user_format
  228. if not user_format:
  229. user_format = webnotes.conn.get_default("date_format")
  230. out = user_format
  231. return out.replace("dd", string_date.strftime("%d"))\
  232. .replace("mm", string_date.strftime("%m"))\
  233. .replace("yyyy", string_date.strftime("%Y"))
  234. def global_date_format(date):
  235. """returns date as 1 January 2012"""
  236. formatted_date = getdate(date).strftime("%d %B %Y")
  237. return formatted_date.startswith("0") and formatted_date[1:] or formatted_date
  238. def dict_to_str(args, sep='&'):
  239. """
  240. Converts a dictionary to URL
  241. """
  242. import urllib
  243. t = []
  244. for k in args.keys():
  245. t.append(str(k)+'='+urllib.quote(str(args[k] or '')))
  246. return sep.join(t)
  247. def timestamps_equal(t1, t2):
  248. """Returns true if same the two string timestamps are same"""
  249. scrub = lambda x: x.replace(':', ' ').replace('-',' ').split()
  250. t1, t2 = scrub(t1), scrub(t2)
  251. if len(t1) != len(t2):
  252. return
  253. for i in range(len(t1)):
  254. if t1[i]!=t2[i]:
  255. return
  256. return 1
  257. def has_common(l1, l2):
  258. """Returns truthy value if there are common elements in lists l1 and l2"""
  259. return set(l1) & set(l2)
  260. def flt(s, precision=None):
  261. """Convert to float (ignore commas)"""
  262. if isinstance(s, basestring):
  263. s = s.replace(',','')
  264. try:
  265. num = float(s)
  266. if precision is not None:
  267. num = round(num, precision)
  268. except Exception:
  269. num = 0
  270. return num
  271. def cint(s):
  272. """Convert to integer"""
  273. try: num = int(float(s))
  274. except: num = 0
  275. return num
  276. def cstr(s):
  277. if isinstance(s, unicode):
  278. return s
  279. elif s==None:
  280. return ''
  281. elif isinstance(s, basestring):
  282. return unicode(s, 'utf-8')
  283. else:
  284. return unicode(s)
  285. def encode(obj, encoding="utf-8"):
  286. if isinstance(obj, list):
  287. out = []
  288. for o in obj:
  289. if isinstance(o, unicode):
  290. out.append(o.encode(encoding))
  291. else:
  292. out.append(o)
  293. return out
  294. elif isinstance(obj, unicode):
  295. return obj.encode(encoding)
  296. else:
  297. return obj
  298. def parse_val(v):
  299. """Converts to simple datatypes from SQL query results"""
  300. import datetime
  301. if isinstance(v, (datetime.date, datetime.datetime)):
  302. v = unicode(v)
  303. elif isinstance(v, datetime.timedelta):
  304. v = ":".join(unicode(v).split(":")[:2])
  305. elif isinstance(v, long):
  306. v = int(v)
  307. return v
  308. def fmt_money(amount, precision=None, currency=None):
  309. """
  310. Convert to string with commas for thousands, millions etc
  311. """
  312. number_format = webnotes.conn.get_default("number_format") or "#,###.##"
  313. decimal_str, comma_str, precision = get_number_format_info(number_format)
  314. amount = '%.*f' % (precision, flt(amount))
  315. if amount.find('.') == -1:
  316. decimals = ''
  317. else:
  318. decimals = amount.split('.')[1]
  319. parts = []
  320. minus = ''
  321. if flt(amount) < 0:
  322. minus = '-'
  323. amount = cstr(abs(flt(amount))).split('.')[0]
  324. if len(amount) > 3:
  325. parts.append(amount[-3:])
  326. amount = amount[:-3]
  327. val = number_format=="#,##,###.##" and 2 or 3
  328. while len(amount) > val:
  329. parts.append(amount[-val:])
  330. amount = amount[:-val]
  331. parts.append(amount)
  332. parts.reverse()
  333. amount = comma_str.join(parts) + (precision and (decimal_str + decimals) or "")
  334. amount = minus + amount
  335. if currency:
  336. symbol = webnotes.conn.get_value("Currency", currency, "symbol")
  337. if symbol:
  338. amount = symbol + " " + amount
  339. return amount
  340. number_format_info = {
  341. "#.###": ("", ".", 0),
  342. "#,###": ("", ",", 0),
  343. "#,###.##": (".", ",", 2),
  344. "#,##,###.##": (".", ",", 2),
  345. "#.###,##": (",", ".", 2),
  346. "# ###.##": (".", " ", 2),
  347. "#,###.###": (".", ",", 3),
  348. }
  349. def get_number_format_info(format):
  350. return number_format_info.get(format) or (".", ",", 2)
  351. #
  352. # convet currency to words
  353. #
  354. def money_in_words(number, main_currency = None, fraction_currency=None):
  355. """
  356. Returns string in words with currency and fraction currency.
  357. """
  358. d = get_defaults()
  359. if not main_currency:
  360. main_currency = d.get('currency', 'INR')
  361. if not fraction_currency:
  362. fraction_currency = webnotes.conn.get_value("Currency", main_currency, "fraction") or "Cent"
  363. n = "%.2f" % flt(number)
  364. main, fraction = n.split('.')
  365. if len(fraction)==1: fraction += '0'
  366. number_format = webnotes.conn.get_value("Currency", main_currency, "number_format") or \
  367. webnotes.conn.get_default("number_format") or "#,###.##"
  368. in_million = True
  369. if number_format == "#,##,###.##": in_million = False
  370. out = main_currency + ' ' + in_words(main, in_million).title()
  371. if cint(fraction):
  372. out = out + ' and ' + in_words(fraction, in_million).title() + ' ' + fraction_currency
  373. return out + ' only.'
  374. #
  375. # convert number to words
  376. #
  377. def in_words(integer, in_million=True):
  378. """
  379. Returns string in words for the given integer.
  380. """
  381. n=int(integer)
  382. known = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
  383. 11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen',
  384. 19: 'nineteen', 20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}
  385. def psn(n, known, xpsn):
  386. import sys;
  387. if n in known: return known[n]
  388. bestguess, remainder = str(n), 0
  389. if n<=20:
  390. webnotes.errprint(sys.stderr)
  391. webnotes.errprint(n)
  392. webnotes.errprint("How did this happen?")
  393. assert 0
  394. elif n < 100:
  395. bestguess= xpsn((n//10)*10, known, xpsn) + '-' + xpsn(n%10, known, xpsn)
  396. return bestguess
  397. elif n < 1000:
  398. bestguess= xpsn(n//100, known, xpsn) + ' ' + 'hundred'
  399. remainder = n%100
  400. else:
  401. if in_million:
  402. if n < 1000000:
  403. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  404. remainder = n%1000
  405. elif n < 1000000000:
  406. bestguess= xpsn(n//1000000, known, xpsn) + ' ' + 'million'
  407. remainder = n%1000000
  408. else:
  409. bestguess= xpsn(n//1000000000, known, xpsn) + ' ' + 'billion'
  410. remainder = n%1000000000
  411. else:
  412. if n < 100000:
  413. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  414. remainder = n%1000
  415. elif n < 10000000:
  416. bestguess= xpsn(n//100000, known, xpsn) + ' ' + 'lakh'
  417. remainder = n%100000
  418. else:
  419. bestguess= xpsn(n//10000000, known, xpsn) + ' ' + 'crore'
  420. remainder = n%10000000
  421. if remainder:
  422. if remainder >= 100:
  423. comma = ','
  424. else:
  425. comma = ''
  426. return bestguess + comma + ' ' + xpsn(remainder, known, xpsn)
  427. else:
  428. return bestguess
  429. return psn(n, known, psn)
  430. # Get Defaults
  431. # ==============================================================================
  432. def get_defaults(key=None):
  433. """
  434. Get dictionary of default values from the :term:`Control Panel`, or a value if key is passed
  435. """
  436. return webnotes.conn.get_defaults(key)
  437. def set_default(key, val):
  438. """
  439. Set / add a default value to :term:`Control Panel`
  440. """
  441. return webnotes.conn.set_default(key, val)
  442. def remove_blanks(d):
  443. """
  444. Returns d with empty ('' or None) values stripped
  445. """
  446. empty_keys = []
  447. for key in d:
  448. if d[key]=='' or d[key]==None:
  449. # del d[key] raises runtime exception, using a workaround
  450. empty_keys.append(key)
  451. for key in empty_keys:
  452. del d[key]
  453. return d
  454. def pprint_dict(d, level=1, no_blanks=True):
  455. """
  456. Pretty print a dictionary with indents
  457. """
  458. if no_blanks:
  459. remove_blanks(d)
  460. # make indent
  461. indent, ret = '', ''
  462. for i in range(0,level): indent += '\t'
  463. # add lines
  464. comment, lines = '', []
  465. kl = d.keys()
  466. kl.sort()
  467. # make lines
  468. for key in kl:
  469. if key != '##comment':
  470. tmp = {key: d[key]}
  471. lines.append(indent + str(tmp)[1:-1] )
  472. # add comment string
  473. if '##comment' in kl:
  474. ret = ('\n' + indent) + '# ' + d['##comment'] + '\n'
  475. # open
  476. ret += indent + '{\n'
  477. # lines
  478. ret += indent + ',\n\t'.join(lines)
  479. # close
  480. ret += '\n' + indent + '}'
  481. return ret
  482. def get_common(d1,d2):
  483. """
  484. returns (list of keys) the common part of two dicts
  485. """
  486. return [p for p in d1 if p in d2 and d1[p]==d2[p]]
  487. def get_common_dict(d1, d2):
  488. """
  489. return common dictionary of d1 and d2
  490. """
  491. ret = {}
  492. for key in d1:
  493. if key in d2 and d2[key]==d1[key]:
  494. ret[key] = d1[key]
  495. return ret
  496. def get_diff_dict(d1, d2):
  497. """
  498. return common dictionary of d1 and d2
  499. """
  500. diff_keys = set(d2.keys()).difference(set(d1.keys()))
  501. ret = {}
  502. for d in diff_keys: ret[d] = d2[d]
  503. return ret
  504. def get_file_timestamp(fn):
  505. """
  506. Returns timestamp of the given file
  507. """
  508. import os
  509. from webnotes.utils import cint
  510. try:
  511. return str(cint(os.stat(fn).st_mtime))
  512. except OSError, e:
  513. if e.args[0]!=2:
  514. raise e
  515. else:
  516. return None
  517. # to be deprecated
  518. def make_esc(esc_chars):
  519. """
  520. Function generator for Escaping special characters
  521. """
  522. return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
  523. # esc / unescape characters -- used for command line
  524. def esc(s, esc_chars):
  525. """
  526. Escape special characters
  527. """
  528. if not s:
  529. return ""
  530. for c in esc_chars:
  531. esc_str = '\\' + c
  532. s = s.replace(c, esc_str)
  533. return s
  534. def unesc(s, esc_chars):
  535. """
  536. UnEscape special characters
  537. """
  538. for c in esc_chars:
  539. esc_str = '\\' + c
  540. s = s.replace(esc_str, c)
  541. return s
  542. def strip_html(text):
  543. """
  544. removes anything enclosed in and including <>
  545. """
  546. import re
  547. return re.compile(r'<.*?>').sub('', text)
  548. def escape_html(text):
  549. html_escape_table = {
  550. "&": "&amp;",
  551. '"': "&quot;",
  552. "'": "&apos;",
  553. ">": "&gt;",
  554. "<": "&lt;",
  555. }
  556. return "".join(html_escape_table.get(c,c) for c in text)
  557. def get_doctype_label(dt=None):
  558. """
  559. Gets label of a doctype
  560. """
  561. if dt:
  562. res = webnotes.conn.sql("""\
  563. SELECT name, dt_label FROM `tabDocType Label`
  564. WHERE name=%s""", dt)
  565. return res and res[0][0] or dt
  566. else:
  567. res = webnotes.conn.sql("SELECT name, dt_label FROM `tabDocType Label`")
  568. dt_label_dict = {}
  569. for r in res:
  570. dt_label_dict[r[0]] = r[1]
  571. return dt_label_dict
  572. def get_label_doctype(label):
  573. """
  574. Gets doctype from its label
  575. """
  576. res = webnotes.conn.sql("""\
  577. SELECT name FROM `tabDocType Label`
  578. WHERE dt_label=%s""", label)
  579. return res and res[0][0] or label
  580. def pretty_date(iso_datetime):
  581. """
  582. Takes an ISO time and returns a string representing how
  583. long ago the date represents.
  584. Ported from PrettyDate by John Resig
  585. """
  586. if not iso_datetime: return ''
  587. from datetime import datetime
  588. import math
  589. if isinstance(iso_datetime, basestring):
  590. iso_datetime = datetime.strptime(iso_datetime, '%Y-%m-%d %H:%M:%S')
  591. now_dt = datetime.strptime(now(), '%Y-%m-%d %H:%M:%S')
  592. dt_diff = now_dt - iso_datetime
  593. # available only in python 2.7+
  594. # dt_diff_seconds = dt_diff.total_seconds()
  595. dt_diff_seconds = dt_diff.days * 86400.0 + dt_diff.seconds
  596. dt_diff_days = math.floor(dt_diff_seconds / 86400.0)
  597. # differnt cases
  598. if dt_diff_seconds < 60.0:
  599. return 'just now'
  600. elif dt_diff_seconds < 120.0:
  601. return '1 minute ago'
  602. elif dt_diff_seconds < 3600.0:
  603. return '%s minutes ago' % cint(math.floor(dt_diff_seconds / 60.0))
  604. elif dt_diff_seconds < 7200.0:
  605. return '1 hour ago'
  606. elif dt_diff_seconds < 86400.0:
  607. return '%s hours ago' % cint(math.floor(dt_diff_seconds / 3600.0))
  608. elif dt_diff_days == 1.0:
  609. return 'Yesterday'
  610. elif dt_diff_days < 7.0:
  611. return '%s days ago' % cint(dt_diff_days)
  612. elif dt_diff_days < 31.0:
  613. return '%s week(s) ago' % cint(math.ceil(dt_diff_days / 7.0))
  614. elif dt_diff_days < 365.0:
  615. return '%s months ago' % cint(math.ceil(dt_diff_days / 30.0))
  616. else:
  617. return 'more than %s year(s) ago' % cint(math.floor(dt_diff_days / 365.0))
  618. def execute_in_shell(cmd, verbose=0):
  619. # using Popen instead of os.system - as recommended by python docs
  620. from subprocess import Popen
  621. import tempfile
  622. with tempfile.TemporaryFile() as stdout:
  623. with tempfile.TemporaryFile() as stderr:
  624. p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
  625. p.wait()
  626. stdout.seek(0)
  627. out = stdout.read()
  628. stderr.seek(0)
  629. err = stderr.read()
  630. if verbose:
  631. if err: print err
  632. if out: print out
  633. return err, out
  634. def comma_or(some_list):
  635. return comma_sep(some_list, " or ")
  636. def comma_and(some_list):
  637. return comma_sep(some_list, " and ")
  638. def comma_sep(some_list, sep):
  639. if isinstance(some_list, (list, tuple)):
  640. # list(some_list) is done to preserve the existing list
  641. some_list = [unicode(s) for s in list(some_list)]
  642. if not some_list:
  643. return ""
  644. elif len(some_list) == 1:
  645. return some_list[0]
  646. else:
  647. some_list = ["'%s'" % s for s in some_list]
  648. return ", ".join(some_list[:-1]) + sep + some_list[-1]
  649. else:
  650. return some_list
  651. def filter_strip_join(some_list, sep):
  652. """given a list, filter None values, strip spaces and join"""
  653. return (cstr(sep)).join((cstr(a).strip() for a in filter(None, some_list)))
  654. def get_path(*path):
  655. import os
  656. return os.path.join(get_base_path(), *path)
  657. def get_base_path():
  658. import conf
  659. import os
  660. return os.path.dirname(os.path.abspath(conf.__file__))
  661. def get_url_to_form(doctype, name, base_url=None, label=None):
  662. if not base_url:
  663. try:
  664. from startup import get_url
  665. base_url = get_url()
  666. except ImportError:
  667. base_url = get_request_site_address()
  668. if not label: label = name
  669. return """<a href="%(base_url)s/app.html#!Form/%(doctype)s/%(name)s">%(label)s</a>""" % locals()
  670. import operator
  671. operator_map = {
  672. # startswith
  673. "^": lambda (a, b): (a or "").startswith(b),
  674. # in or not in a list
  675. "in": lambda (a, b): operator.contains(b, a),
  676. "not in": lambda (a, b): not operator.contains(b, a),
  677. # comparison operators
  678. "=": lambda (a, b): operator.eq(a, b),
  679. "!=": lambda (a, b): operator.ne(a, b),
  680. ">": lambda (a, b): operator.gt(a, b),
  681. "<": lambda (a, b): operator.lt(a, b),
  682. ">=": lambda (a, b): operator.ge(a, b),
  683. "<=": lambda (a, b): operator.le(a, b),
  684. "not None": lambda (a, b): a and True or False,
  685. "None": lambda (a, b): (not a) and True or False
  686. }
  687. def compare(val1, condition, val2):
  688. if condition in operator_map:
  689. return operator_map[condition]((val1, val2))
  690. return False