diff --git a/core/doctype/profile/test_profile.py b/core/doctype/profile/test_profile.py index a0bd3f5fec..2f7610b477 100644 --- a/core/doctype/profile/test_profile.py +++ b/core/doctype/profile/test_profile.py @@ -40,6 +40,17 @@ class TestProfile(unittest.TestCase): webnotes.conn.set_value("Control Panel", "Control Panel", "_test", "_test_val") self.assertEquals(webnotes.conn.get_value("Control Panel", None, "_test"), "_test_val") self.assertEquals(webnotes.conn.get_value("Control Panel", "Control Panel", "_test"), "_test_val") + + def test_doclist(self): + p_meta = webnotes.get_doctype("Profile") + + self.assertEquals(len(p_meta.get({"doctype": "DocField", "parent": "Profile", "fieldname": "first_name"})), 1) + self.assertEquals(len(p_meta.get({"doctype": "DocField", "parent": "Profile", "fieldname": "^first"})), 1) + self.assertEquals(len(p_meta.get({"fieldname": ["!=", "first_name"]})), len(p_meta) - 1) + self.assertEquals(len(p_meta.get({"fieldname": ["in", ["first_name", "last_name"]]})), 2) + self.assertEquals(len(p_meta.get({"fieldname": ["not in", ["first_name", "last_name"]]})), len(p_meta) - 2) + + test_records = [[{ "doctype":"Profile", diff --git a/webnotes/__init__.py b/webnotes/__init__.py index bbb89ec67c..a4ac818479 100644 --- a/webnotes/__init__.py +++ b/webnotes/__init__.py @@ -389,4 +389,7 @@ def map_doclist(from_to_list, from_docname, to_doclist=None): mapper = get_obj("DocType Mapper", "-".join(from_to_list[0])) to_doclist = mapper.dt_map(from_doctype, to_doctype, from_docname, to_doclist[0], to_doclist, from_to_list) return to_doclist - \ No newline at end of file + +def compare(val1, condition, val2): + import webnotes.utils + return webnotes.utils.compare(val1, condition, val2) \ No newline at end of file diff --git a/webnotes/model/code.py b/webnotes/model/code.py index 7271a27507..bd795bb193 100644 --- a/webnotes/model/code.py +++ b/webnotes/model/code.py @@ -37,10 +37,11 @@ methods in following modules are imported for backward compatibility custom_class = ''' import webnotes -from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, now, nowdate, sendmail, set_default, user_format, validate_email_add +from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, now, nowdate, set_default, user_format, validate_email_add from webnotes.model import db_exists from webnotes.model.doc import Document, addchild, getchildren from webnotes.model.utils import getlist +from webnotes.utils.email_lib import sendmail from webnotes.model.code import get_obj, get_server_obj, run_server_obj from webnotes import session, form, msgprint, errprint @@ -56,7 +57,8 @@ class CustomDocType(DocType): def execute(code, doc=None, doclist=[]): # functions used in server script of DocTypes # -------------------------------------------------- - from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, now, nowdate, sendmail, set_default, user_format, validate_email_add + from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, now, nowdate, set_default, user_format, validate_email_add + from webnotes.utils.email_lib import sendmail from webnotes.model import db_exists from webnotes.model.doc import Document, addchild, getchildren from webnotes.model.utils import getlist diff --git a/webnotes/model/controller.py b/webnotes/model/controller.py index 38c1fd3d73..9f31f9decc 100644 --- a/webnotes/model/controller.py +++ b/webnotes/model/controller.py @@ -22,6 +22,20 @@ from __future__ import unicode_literals import webnotes +from webnotes import msgprint, _ +from webnotes.utils import flt, cint, cstr + +error_coniditon_map = { + "=": "!=", + "!=": "=", + "<": ">=", + ">": "<=", + ">=": "<", + "<=": ">", + "in": _("not in"), + "not in": _("in"), + "^": _("cannot start with"), +} class DocListController(object): def __init__(self, doc, doclist): @@ -34,3 +48,25 @@ class DocListController(object): if not hasattr(self, "_meta"): self._meta = webnotes.get_doctype(self.doc.doctype) return self._meta + + def validate_value(self, fieldname, condition, val2, doc=None): + if not doc: + doc = self.doc + + df = self.meta.get_field(fieldname, parent=doc.doctype) + + val1 = doc.fields.get(fieldname) + if df.fieldtype in ("Currency", "Float"): + val1 = flt(val1) + elif df.fieldtype in ("Int", "Check"): + val1 = cint(val1) + + if not webnotes.compare(val1, condition, val2): + msg = _("Error: ") + if doc.parentfield: + msg += _("Row") + (" # %d: " % doc.idx) + + msg += _(self.meta.get_label(fieldname, parent=doc.doctype)) \ + + " " + error_coniditon_map.get(condition, "") + " " + cstr(val2) + + msgprint(msg, raise_exception=True) diff --git a/webnotes/model/doclist.py b/webnotes/model/doclist.py index 82007c19fe..ca42e82f8a 100644 --- a/webnotes/model/doclist.py +++ b/webnotes/model/doclist.py @@ -30,14 +30,7 @@ class DocList(list): """pass filters as: {"key": "val", "key": ["!=", "val"], "key": ["in", "val"], "key": ["not in", "val"], "key": "^val"}""" - # map reverse operations to set add = False - import operator - ops_map = { - "!=": lambda (a, b): operator.ne(a, b), - "in": lambda (a, b): operator.contains(b, a), - "not in": lambda (a, b): not operator.contains(b, a) - } - + out = [] for doc in self: @@ -45,16 +38,14 @@ class DocList(list): add = True for f in filters: fval = filters[f] - - if isinstance(fval, list): - if fval[0] in ops_map and not ops_map[fval[0]]((d.get(f), fval[1])): - add = False - break - elif isinstance(fval, basestring) and fval.startswith("^"): - if not (d.get(f) or "").startswith(fval[1:]): - add = False - break - elif d.get(f)!=fval: + + if not isinstance(fval, list): + if isinstance(fval, basestring) and fval.startswith("^"): + fval = ["^", fval[1:]] + else: + fval = ["=", fval] + + if not webnotes.compare(d.get(f), fval[0], fval[1]): add = False break diff --git a/webnotes/utils/__init__.py b/webnotes/utils/__init__.py index 59bd58c9c9..2f938e361b 100644 --- a/webnotes/utils/__init__.py +++ b/webnotes/utils/__init__.py @@ -81,11 +81,6 @@ def validate_email_add(email_str): import re 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()) -def sendmail(recipients, sender='', msg='', subject='[No Subject]'): - """Send an email. For more details see :func:`email_lib.sendmail`""" - import webnotes.utils.email_lib - return email_lib.sendmail(recipients, sender, msg, subject) - def get_request_site_address(full_address=False): """get app url from request""" import os @@ -93,7 +88,7 @@ def get_request_site_address(full_address=False): return 'HTTPS' in os.environ.get('SERVER_PROTOCOL') and 'https://' or 'http://' \ + os.environ.get('HTTP_HOST')\ + (full_address and (os.environ.get("REQUEST_URI")) or "") - except TypeError, e: + except TypeError: return 'http://localhost' def random_string(length): @@ -117,7 +112,7 @@ def getTraceback(): """ Returns the traceback of the Exception """ - import sys, traceback, string + import sys, traceback exc_type, value, tb = sys.exc_info() trace_list = traceback.format_tb(tb, None) + \ @@ -151,7 +146,7 @@ def getdate(string_date): try: return datetime.datetime.strptime(string_date, "%Y-%m-%d").date() - except ValueError, e: + except ValueError: webnotes.msgprint("Cannot understand date - '%s'" % \ (string_date,), raise_exception=1) @@ -325,7 +320,7 @@ def flt(s, precision=None): num = float(s) if precision: num = round(num, precision) - except Exception, e: + except Exception: num = 0 return num @@ -375,7 +370,7 @@ def fmt_money(amount, precision=None): """ Convert to string with commas for thousands, millions etc """ - import webnotes, re + import webnotes from webnotes import _ curr = webnotes.conn.get_value('Control Panel', None, @@ -743,7 +738,7 @@ def pretty_date(iso_datetime): def execute_in_shell(cmd, verbose=0): # using Popen instead of os.system - as recommended by python docs - from subprocess import Popen, PIPE + from subprocess import Popen import tempfile with tempfile.TemporaryFile() as stdout: @@ -798,4 +793,28 @@ def get_url_to_form(doctype, name, base_url=None, label=None): if not label: label = name - return """%(label)s""" % locals() \ No newline at end of file + return """%(label)s""" % locals() + +import operator +operator_map = { + # startswith + "^": lambda (a, b): (a or "").startswith(b), + + # in or not in a list + "in": lambda (a, b): operator.contains(b, a), + "not in": lambda (a, b): not operator.contains(b, a), + + # comparison operators + "=": lambda (a, b): operator.eq(a, b), + "!=": lambda (a, b): operator.ne(a, b), + ">": lambda (a, b): operator.gt(a, b), + "<": lambda (a, b): operator.lt(a, b), + ">=": lambda (a, b): operator.ge(a, b), + "<=": lambda (a, b): operator.le(a, b), +} + +def compare(val1, condition, val2): + if condition in operator_map: + return operator_map[condition]((val1, val2)) + + return False \ No newline at end of file