示例#1
0
    def validate_item(self, item_code, row_num):
        from erpnext.stock.doctype.item.item import validate_end_of_life, \
         validate_is_stock_item, validate_cancelled_item

        # using try except to catch all validation msgs and display together

        try:
            item = frappe.get_doc("Item", item_code)

            # end of life and stock item
            validate_end_of_life(item_code,
                                 item.end_of_life,
                                 item.disabled,
                                 verbose=0)
            validate_is_stock_item(item_code, item.is_stock_item, verbose=0)

            # item should not be serialized
            if item.has_serial_no == 1:
                raise frappe.ValidationError(
                    _("Serialized Item {0} cannot be updated using Stock Reconciliation, please use Stock Entry"
                      ).format(item_code))

            # item managed batch-wise not allowed
            if item.has_batch_no == 1:
                raise frappe.ValidationError(
                    _("Batched Item {0} cannot be updated using Stock Reconciliation, instead use Stock Entry"
                      ).format(item_code))

            # docstatus should be < 2
            validate_cancelled_item(item_code, item.docstatus, verbose=0)

        except Exception as e:
            self.validation_messages.append(
                _("Row # ") + ("%d: " % (row_num)) + cstr(e))
示例#2
0
    def validate_item(self, item_code, row):
        from erpnext.stock.doctype.item.item import validate_end_of_life, \
         validate_is_stock_item, validate_cancelled_item

        # using try except to catch all validation msgs and display together

        try:
            item = frappe.get_doc("Item", item_code)

            # end of life and stock item
            validate_end_of_life(item_code,
                                 item.end_of_life,
                                 item.disabled,
                                 verbose=0)
            validate_is_stock_item(item_code, item.is_stock_item, verbose=0)

            # item should not be serialized
            if item.has_serial_no and not row.serial_no and not item.serial_no_series:
                raise frappe.ValidationError(
                    _("Serial no(s) required for serialized item {0}").format(
                        item_code))

            # item managed batch-wise not allowed
            if item.has_batch_no and not row.batch_no and not item.create_new_batch:
                raise frappe.ValidationError(
                    _("Batch no is required for batched item {0}").format(
                        item_code))

            # docstatus should be < 2
            validate_cancelled_item(item_code, item.docstatus, verbose=0)

        except Exception as e:
            self.validation_messages.append(
                _("Row # ") + ("%d: " % (row.idx)) + cstr(e))
 def get_access_token(self):
     if not self.refresh_token:
         raise frappe.ValidationError(_("GCalendar is not configured."))
     data = {
         'client_id':
         self.client_id,
         'client_secret':
         self.get_password(fieldname='client_secret',
                           raise_exception=False),
         'refresh_token':
         self.get_password(fieldname='refresh_token',
                           raise_exception=False),
         'grant_type':
         "refresh_token",
         'scope':
         SCOPES
     }
     try:
         r = requests.post('https://www.googleapis.com/oauth2/v4/token',
                           data=data).json()
     except requests.exceptions.HTTPError:
         frappe.throw(
             _("Something went wrong during the token generation. Please request again an authorization code."
               ))
     return r.get('access_token')
示例#4
0
	def check_docstatus_transition(self, docstatus):
		"""Ensures valid `docstatus` transition.
		Valid transitions are (number in brackets is `docstatus`):

		- Save (0) > Save (0)
		- Save (0) > Submit (1)
		- Submit (1) > Submit (1)
		- Submit (1) > Cancel (2)

		"""
		if not self.docstatus:
			self.docstatus = 0
		if docstatus==0:
			if self.docstatus==0:
				self._action = "save"
			elif self.docstatus==1:
				self._action = "submit"
				self.check_permission("submit")
			else:
				raise frappe.DocstatusTransitionError(_("Cannot change docstatus from 0 to 2"))

		elif docstatus==1:
			if self.docstatus==1:
				self._action = "update_after_submit"
				self.check_permission("submit")
			elif self.docstatus==2:
				self._action = "cancel"
				self.check_permission("cancel")
			else:
				raise frappe.DocstatusTransitionError(_("Cannot change docstatus from 1 to 0"))

		elif docstatus==2:
			raise frappe.ValidationError(_("Cannot edit cancelled document"))
示例#5
0
def get_context(context):
    enterprise = frappe.form_dict.enterprise
    if frappe.form_dict.user:
        add_user(frappe.form_dict.user, enterprise)

    user = frappe.session.user

    if not enterprise:
        raise frappe.ValidationError(_("You need specified IOT Enterprise"))

    user_roles = frappe.get_roles(frappe.session.user)
    if 'IOT User' not in user_roles or frappe.session.user == 'Guest':
        raise frappe.PermissionError("Your account is not an IOT User!")

    if not (is_enterprise_admin(user, enterprise)
            or 'IOT Manager' in user_roles):
        raise frappe.PermissionError

    context.no_cache = 1
    context.show_sidebar = True

    possible_users = list_possible_users(enterprise)

    context.parents = [{
        "label": enterprise,
        "route": "/iot_enterprises/" + enterprise
    }]
    context.doc = {"enterprise": enterprise, "possible_users": possible_users}
示例#6
0
def get_context(context):
    company = frappe.form_dict.company
    if frappe.form_dict.user:
        add_employee(frappe.form_dict.user, company)
        frappe.local.flags.redirect_location = "/cloud_add_user?company=" + company
        raise frappe.Redirect

    user = frappe.session.user

    if not company:
        raise frappe.ValidationError(_("You need specified Cloud Enterprise"))

    user_roles = frappe.get_roles(frappe.session.user)
    if 'Company Admin' not in user_roles or frappe.session.user == 'Guest':
        raise frappe.PermissionError("Your account is not an Cloud User!")

    if not (is_company_admin(user, company) or 'Company Admin' in user_roles):
        raise frappe.PermissionError

    context.no_cache = 1
    context.show_sidebar = True

    possible_users = list_possible_users(company)

    context.parents = [{
        "title": company,
        "route": "/cloud_companies/" + company
    }]
    context.doc = {"company": company, "possible_users": possible_users}
示例#7
0
def get_token(user, pwd, expires_in=3600, expire_on=None, device=None):
    """
  Get the JWT Token
  :param user: The user in ctx
  :param pwd: Pwd to auth
  :param expires_in: number of seconds till expiry
  :param expire_on: yyyy-mm-dd HH:mm:ss to specify the expiry (deprecated)
  :param device: The device in ctx
  """
    if not frappe.db.exists("User", user):
        raise frappe.ValidationError(_("Invalide User"))

    from frappe.sessions import clear_sessions
    login = LoginManager()
    login.check_if_enabled(user)
    if not check_password(user, pwd):
        login.fail('Incorrect password', user=user)
    login.login_as(user)
    login.resume = False
    login.run_trigger('on_session_creation')
    _expires_in = 3600
    if cint(expires_in):
        _expires_in = cint(expires_in)
    elif expire_on:
        _expires_in = (get_datetime(expire_on) -
                       get_datetime()).total_seconds()

    token = get_bearer_token(user=user, expires_in=_expires_in)
    frappe.local.response["token"] = token["access_token"]
    frappe.local.response.update(token)
示例#8
0
	def get_access_token(self):
		import requests

		google_settings = frappe.get_doc("Google Settings")

		if not google_settings.enable:
			frappe.throw(_("Google Integration is disabled."))

		if not self.indexing_refresh_token:
			button_label = frappe.bold(_("Allow API Indexing Access"))
			raise frappe.ValidationError(_("Click on {0} to generate Refresh Token.").format(button_label))

		data = {
			"client_id": google_settings.client_id,
			"client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False),
			"refresh_token": self.get_password(fieldname="indexing_refresh_token", raise_exception=False),
			"grant_type": "refresh_token",
			"scope": INDEXING_SCOPES
		}

		try:
			res = requests.post(get_auth_url(), data=data).json()
		except requests.exceptions.HTTPError:
			button_label = frappe.bold(_("Allow Google Indexing Access"))
			frappe.throw(_("Something went wrong during the token generation. Click on {0} to generate a new one.").format(button_label))

		return res.get("access_token")
示例#9
0
 def before_insert(self):
     if frappe.db.count("Translated Message", {
             "source": self.source,
             "language": self.language
     }):
         raise frappe.ValidationError(
             "Translated Message for this source message already exists")
示例#10
0
    def get_access_token(self):
        google_settings = self.validate()

        if not self.refresh_token:
            button_label = frappe.bold(_("Allow Google Calendar Access"))
            raise frappe.ValidationError(
                _("Click on {0} to generate Refresh Token.").format(
                    button_label))

        data = {
            "client_id":
            google_settings.client_id,
            "client_secret":
            google_settings.get_password(fieldname="client_secret",
                                         raise_exception=False),
            "refresh_token":
            self.get_password(fieldname="refresh_token",
                              raise_exception=False),
            "grant_type":
            "refresh_token",
            "scope":
            SCOPES
        }

        try:
            r = requests.post(get_auth_url(), data=data).json()
        except requests.exceptions.HTTPError:
            button_label = frappe.bold(_("Allow Google Calendar Access"))
            frappe.throw(
                _("Something went wrong during the token generation. Click on {0} to generate a new one."
                  ).format(button_label))

        return r.get("access_token")
 def validate_address(self, address):
     for field, label in {"country":"Country", "country_code":"Country Code", "pincode":"Pin Code", \
         "phone":"Phone", "email_id":"Email ID", "city":"City", "address_line1":"Address Lines"}.items():
         if not address.get(field):
             raise frappe.ValidationError(
                 "Please specify {1} in Address {0}".format(
                     address.get("name"), label))
示例#12
0
	def check_docstatus_transition(self, docstatus):
		"""Ensures valid `docstatus` transition.
		Valid transitions are (number in brackets is `docstatus`):

		- Save (0) > Save (0)
		- Save (0) > Submit (1)
		- Submit (1) > Submit (1)
		- Submit (1) > Cancel (2)

		"""
		if not self.docstatus:
			self.docstatus = 0
		if docstatus==0:
			if self.docstatus==0:
				self._action = "save"
			elif self.docstatus==1:
				self._action = "submit"
				self.check_permission("submit")
			else:
				raise frappe.DocstatusTransitionError(_("Draft Document cannot be cancelled. Please {0} the selected document before cancelling it.").format(frappe.bold(_("Submit"))))

		elif docstatus==1:
			if self.docstatus==1:
				self._action = "update_after_submit"
				self.check_permission("submit")
			elif self.docstatus==2:
				self._action = "cancel"
				self.check_permission("cancel")
			else:
				raise frappe.DocstatusTransitionError(_("Cannot change Document Status from Submitted to Draft."))

		elif docstatus==2:
			raise frappe.ValidationError(_("Cancelled Document cannot be edited."))
示例#13
0
	def validate_data(self):
		def _get_msg(row_num, msg):
			return _("Row # {0}: ").format(row_num+1) + msg

		self.validation_messages = []
		item_warehouse_combinations = []

		default_currency = frappe.db.get_default("currency")

		for row_num, row in enumerate(self.items):
			# find duplicates
			if [row.item_code, row.warehouse] in item_warehouse_combinations:
				self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
			else:
				item_warehouse_combinations.append([row.item_code, row.warehouse])

			self.validate_item(row.item_code, row_num+1)

			# validate warehouse
			if not frappe.db.get_value("Warehouse", row.warehouse):
				self.validation_messages.append(_get_msg(row_num, _("Warehouse not found in the system")))

			# if both not specified
			if row.qty in ["", None] and row.valuation_rate in ["", None]:
				self.validation_messages.append(_get_msg(row_num,
					_("Please specify either Quantity or Valuation Rate or both")))

			# do not allow negative quantity
			if flt(row.qty) < 0:
				self.validation_messages.append(_get_msg(row_num,
					_("Negative Quantity is not allowed")))

			# do not allow negative valuation
			if flt(row.valuation_rate) < 0:
				self.validation_messages.append(_get_msg(row_num,
					_("Negative Valuation Rate is not allowed")))

			if row.qty and not row.valuation_rate:
				row.valuation_rate = get_stock_balance(row.item_code, row.warehouse,
							self.posting_date, self.posting_time, with_valuation_rate=True)[1]
				if not row.valuation_rate:
					# try if there is a buying price list in default currency
					buying_rate = frappe.db.get_value("Item Price", {"item_code": row.item_code,
						"buying": 1, "currency": default_currency}, "price_list_rate")
					if buying_rate:
						row.valuation_rate = buying_rate

					else:
						# get valuation rate from Item
						row.valuation_rate = frappe.get_value('Item', row.item_code, 'valuation_rate')

		# throw all validation messages
		if self.validation_messages:
			for msg in self.validation_messages:
				msgprint(msg)

			raise frappe.ValidationError(self.validation_messages)
示例#14
0
    def get_next_mapping_name(self):
        mappings = [m for m in self.get_plan().mappings if m.enabled]
        if not self.current_mapping:
            # first
            return mappings[0].mapping
        for i, d in enumerate(mappings):
            if i == len(mappings) - 1:
                # last
                return None
            if d.mapping == self.current_mapping:
                return mappings[i + 1].mapping

        raise frappe.ValidationError('Mapping Broken')
示例#15
0
def update(message, source, translated, language):
    if message:
        message = frappe.get_doc("Translated Message", message)
        message.translated = translated
        message.save(ignore_permissions=1)
    elif source:
        message = frappe.new_doc("Translated Message")
        message.translated = translated
        message.language = language
        message.source = source
        message.save(ignore_permissions=1)
    else:
        raise frappe.ValidationError("Message not found")
示例#16
0
    def is_valid_from_to_dates(self):
        if self.from_date and self.to_date:
            from_date = dt.strptime(self.from_date, "%Y-%m-%d")
            to_date = dt.strptime(self.to_date, "%Y-%m-%d")
            date_diff = to_date - from_date

            if (from_date.strftime("%a")
                    == "Fri") and (to_date.strftime("%a")
                                   == "Thu") and (date_diff.days == 6):
                return True
            else:
                raise frappe.ValidationError("Invalid From Date and To Date")
        else:
            raise frappe.MandatoryError(
                "From Date and To Date fields are mandatory")
示例#17
0
def get_token(user, pwd, expire_on=None, device=None):
  if not frappe.db.exists("User", user):
    raise frappe.ValidationError(_("Invalide User"))

  from frappe.sessions import clear_sessions
  login = LoginManager()
  login.check_if_enabled(user)
  if not check_password(user, pwd):
    login.fail('Incorrect password', user=user)
  login.login_as(user)
  login.resume = False
  login.run_trigger('on_session_creation')
  clear_sessions(user, True, device)
  if expire_on:
    frappe.flags.jwt_expire_on = expire_on
def reset_pin():
    pwd, apwd = None, None
    if frappe.session.user != "Guest":
        pwd = frappe.form_dict.get('pwd')
        apwd = frappe.form_dict.get('apwd')

    if pwd and apwd:
        set_encrypted_password("User",
                               frappe.session.user,
                               pwd,
                               fieldname="pin")
        frappe.db.commit()
        return "SUCCESS"
    else:
        raise frappe.ValidationError(
            "Passwords does not match or key is missing")
示例#19
0
def _get_access(sitemap_page, profile):
    lft, rgt, public_read, public_write, page_or_generator = frappe.db.get_value(
        "Website Route", sitemap_page,
        ["lft", "rgt", "public_read", "public_write", "page_or_generator"])

    read = write = admin = private_read = 0

    if page_or_generator == "Generator":

        if not (lft and rgt):
            raise frappe.ValidationError("Please rebuild Website Route Tree")

        if profile == "Guest":
            return {"read": public_read, "write": 0, "admin": 0}

        if public_write:
            read = write = 1
        elif public_read:
            read = 1

        for perm in frappe.db.sql(
                """select wsp.`read`, wsp.`write`, wsp.`admin`, 
			ws.lft, ws.rgt, ws.name
			from `tabWebsite Route Permission` wsp, `tabWebsite Route` ws
			where wsp.profile = %s and wsp.website_route = ws.name 
			order by lft asc""", (profile, ),
                as_dict=True):
            if perm.lft <= lft and perm.rgt >= rgt:
                if not (public_read or private_read): private_read = perm.read
                if not read: read = perm.read
                if not write: write = perm.write
                if not admin: admin = perm.admin
                if write: read = write

            if read and write and admin:
                break

    else:
        read = write = admin = private_read = 1

    return {
        "read": read,
        "write": write,
        "admin": admin,
        "private_read": private_read
    }
示例#20
0
def get_access_token():
	if not refresh_token:
		raise frappe.ValidationError(_("GCalendar is not configured."))
	data = {
		'client_id': client_id,
		'client_secret': client_secret,
		'refresh_token': refresh_token,
		'grant_type': "refresh_token",
		'scope': SCOPES
	}
	try:
		r = requests.post('https://www.googleapis.com/oauth2/v4/token', data=data).json()
	except requests.exceptions.HTTPError:
		frappe.throw(_("Something went wrong during the token generation. Please request again an authorization code."))
	if r.get('access_token'):
		frappe.db.set_value("Booking Settings", None, "access_token", cstr(r.get('access_token')))
		frappe.db.commit()
	return r.get('access_token')
def reset_password():
    pwd = frappe.form_dict.get('pwd')
    apwd = frappe.form_dict.get('apwd')
    key = frappe.form_dict.get('key')

    if pwd and key and pwd == apwd:
        res = _get_user_for_update_password(key, None)
        if res.get('message'):
            frappe.local.response.http_status_code = 410
            return res['message']
        else:
            user = res['user']

        _update_password(user, pwd, logout_all_sessions=1)
        return "SUCCESS"
    else:
        raise frappe.ValidationError(
            "Passwords does not match or key is missing")
示例#22
0
def get_token(user, pwd, expire_on=None, device=None):
    """
  Get the JWT Token
  :param user: The user in ctx
  :param pwd: Pwd to auth
  :param expire_on: yyyy-mm-dd HH:mm:ss to specify the expiry
  :param device: The device in ctx
  """
    if not frappe.db.exists("User", user):
        raise frappe.ValidationError(_("Invalide User"))

    from frappe.sessions import clear_sessions
    login = LoginManager()
    login.check_if_enabled(user)
    if not check_password(user, pwd):
        login.fail('Incorrect password', user=user)
    login.login_as(user)
    login.resume = False
    login.run_trigger('on_session_creation')
    clear_sessions(user, True, device)
    if expire_on:
        frappe.flags.jwt_expire_on = expire_on
    def set_shipper_info(self, shipper_id, shipment):
        shipper_details = frappe.db.get_value("Address",
                                              shipper_id,
                                              "*",
                                              as_dict=True)
        self.validate_address(shipper_details)
        tin_no = frappe.db.get_value("Company", shipper_details.get("company"),
                                     "tin_no")

        shipment.RequestedShipment.Shipper.AccountNumber = self.config_obj.account_number
        shipment.RequestedShipment.Shipper.Contact.PersonName = shipper_details.get(
            "address_title")
        shipment.RequestedShipment.Shipper.Contact.CompanyName = shipper_details.get(
            "company")
        shipment.RequestedShipment.Shipper.Contact.PhoneNumber = shipper_details.get(
            "phone")
        shipment.RequestedShipment.Shipper.Address.StreetLines = [shipper_details.get("address_line1"),\
                        shipper_details.get("address_line2")]
        shipment.RequestedShipment.Shipper.Address.City = shipper_details.get(
            "city")
        shipment.RequestedShipment.Shipper.Address.StateOrProvinceCode = shipper_details.get(
            "state_code")
        shipment.RequestedShipment.Shipper.Address.PostalCode = shipper_details.get(
            "pincode")
        shipment.RequestedShipment.Shipper.Address.CountryCode = shipper_details.get(
            "country_code")
        shipment.RequestedShipment.Shipper.Address.Residential = True if shipper_details.get("is_residential_address") \
                      else False
        if not tin_no:
            raise frappe.ValidationError(
                "Please set TIN no in company {0}".format(
                    shipper_details.get("company")))
        tin_details = shipment.create_wsdl_object_of_type(
            'TaxpayerIdentification')
        tin_details.TinType.value = "BUSINESS_NATIONAL"
        tin_details.Number = tin_no
        shipment.RequestedShipment.Shipper.Tins = [tin_details]
        return shipper_details
示例#24
0
    def get_payment_url(self, **kwargs):
        snap = midtransclient.Snap(is_production=bool(self.is_production),
                                   server_key=self.server_key,
                                   client_key=self.client_key)
        param = {}
        param.update({
            "transaction_details": {
                "order_id": kwargs['reference_docname'],
                "gross_amount": kwargs['amount']
            },
            "credit_card": {
                "secure": True
            }
        })
        try:
            trans = snap.create_transaction(param)
            payment_url = trans['redirect_url']
            doc = frappe.get_doc("Midtrans Settings")
            md5 = hashlib.md5()
            md5.update(
                ("{}-{}".format(doc.merchant_id,
                                kwargs['reference_docname']).encode("utf8")))
            token = md5.hexdigest()

            # kwargs.update({
            # 	"token": token
            # })

            create_request_log(kwargs, "Remote", "Midtrans", token)

            print("Payment url : {}".format(payment_url))
            frappe.msgprint("Payment url : {}".format(payment_url))

            return payment_url

        except Exception as e:
            # frappe.msgprint(_(str(e)), raise_exception=1, indicator='red')
            raise frappe.ValidationError(str(e))
示例#25
0
    def __init__(self):
        super(JSInterpreter, self).__init__()

        # load javascript path
        for app in frappe.get_installed_apps():
            for hook in frappe.get_hooks('studio_library_path', app_name=app):
                self.loader.register_path(frappe.get_app_path(app, hook))

        # load functions
        _gbl = tree()
        replacements = {}
        for attr in frappe.get_hooks('studio_functions', []):
            paths = []
            if isinstance(attr, dict):
                for key, value in attr.items():
                    attr, expand = get_attr(value)
                    if not expand:
                        paths.append(key)
                        self.export_function(key, attr)
                    else:
                        base_path = key
                        for fn, item in inspect.getmembers(
                                attr, is_module_function(base_path)):
                            key = '{0}.{1}'.format(base_path, fn)
                            self.export_function(key, item)
                            paths.append(key)

            elif isinstance(attr, (list, tuple, set)):
                raise frappe.ValidationError(
                    'Invalid hook format {}, should be ("list" or "dict") not "{}"'
                    .format(frappe.as_json(list(attr)),
                            type(attr).__name__))
            else:
                obj, expand = get_attr(attr)

                if not expand:
                    paths.append(attr)
                    self.export_function(attr, obj)
                else:
                    base_path = attr
                    for fn, item in inspect.getmembers(
                            obj, is_module_function(base_path)):
                        attr = '{0}.{1}'.format(base_path, fn)
                        self.export_function(key, item)
                        paths.append(attr)

            for path in paths:
                parts = path.split('.')
                fn = parts.pop()
                actual = None
                for part in parts:
                    actual = (actual or _gbl)[part]
                actual[fn] = '{{{0}}}'.format(path.replace('.', '_'))
                replacements[path.replace(
                    '.', '_'
                )] = '''function() {{ return call_python("{0}", as_list(arguments)); }}'''.format(
                    path)

        self.evaljs('''
			function as_list(a){ var args = []; for(var i = 0; i < a.length; i++){ args.push(a[i]); } return args; }
			function enable_document_syncronization(){ ctx.enabled_document_syncronization = true; }
			function disable_document_syncronization(){ ctx.enabled_document_syncronization = false; }
			function add_child(field, child){
				if (!ctx.enabled_document_syncronization) return;
				var df = frappe.utils.filter_dict(ctx.meta.fields, {'fieldname': field, 'fieldtype': 'Table'});
				if (!df) return;
				df = df[0];
				if (!Array.isArray(doc[df.fieldname])) doc[df.fieldname] = [];
				if (!child.doctype) child.doctype = df.options;
				if (!child.parenttype) child.parenttype = doc.doctype;
				if (!child.paerentfield) child.parentfield = df.fieldname;
				doc[df.fieldname].push(child);
			}
		''')

        JS_GLOBALS = []

        for k in _gbl.keys():
            JS_GLOBALS_PART = k + ' = ' + json.dumps(_gbl[k], indent=2) + ';'

            for rk, v in replacements.items():
                if not rk.startswith(k + '_'):
                    continue
                JS_GLOBALS_PART = JS_GLOBALS_PART.replace('"{' + rk + '}"', v)
        JS_GLOBALS.append(JS_GLOBALS_PART)
        #frappe.msgprint('<pre>{0}</pre>'.format('\n'.join(JS_GLOBALS)))
        self.evaljs('\n'.join(JS_GLOBALS))
示例#26
0
def _msgprint(msg, verbose):
    if verbose:
        msgprint(msg, raise_exception=True)
    else:
        raise frappe.ValidationError(msg)
示例#27
0
	def validate_data(self):
		def _get_msg(row_num, msg):
			return _("Row # {0}: ").format(row_num+1) + msg

		self.validation_messages = []
		item_warehouse_combinations = []

		default_currency = frappe.db.get_default("currency")

		for row_num, row in enumerate(self.items):
			# find duplicates
			if [row.item_code, row.warehouse, row.batch_no] in item_warehouse_combinations:#JDLP - 2017-01-30 - batch_no
				self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
			else:
				item_warehouse_combinations.append([row.item_code, row.warehouse, row.batch_no])#JDLP - 2017-01-30 - batch_no

			self.validate_item(row.item_code, row_num+1)

			# validate warehouse
			if not frappe.db.get_value("Warehouse", row.warehouse):
				self.validation_messages.append(_get_msg(row_num, _("Warehouse not found in the system")))

			# if both not specified
			if row.qty in ["", None] and row.valuation_rate in ["", None]:
				self.validation_messages.append(_get_msg(row_num,
					_("Please specify either Quantity or Valuation Rate or both")))

			# do not allow negative quantity
			if flt(row.qty) < 0:
				self.validation_messages.append(_get_msg(row_num,
					_("Negative Quantity is not allowed")))

			# do not allow negative valuation
			if flt(row.valuation_rate) < 0:
				self.validation_messages.append(_get_msg(row_num,
					_("Negative Valuation Rate is not allowed")))

			if row.qty and not row.valuation_rate:
				row.valuation_rate = get_stock_balance(row.item_code, row.warehouse,
							self.posting_date, self.posting_time, with_valuation_rate=True)[1]
				if not row.valuation_rate:
					# try if there is a buying price list in default currency
					buying_rate = frappe.db.get_value("Item Price", {"item_code": row.item_code,
						"buying": 1, "currency": default_currency}, "price_list_rate")
					if buying_rate:
						row.valuation_rate = buying_rate
						
			#JDLP - 2017-01-30 - batch_no
			# if batch_no is required and not provided.
			has_batch_no = frappe.db.get_value("Item", {"item_code": row.item_code}, "has_batch_no")
			if has_batch_no == 1 and row.batch_no is None:
				self.validation_messages.append(_get_msg(row_num,
					_("Batch number is required")))
				#raise frappe.ValidationError, _("Item: {0} managed batch-wise, batch number is required").format(item_code)

			if has_batch_no == 0 and row.batch_no is not None:
				self.validation_messages.append(_get_msg(row_num,
					_("Batch number should be empty")))
				#raise frappe.ValidationError, _("Item: {0} is not managed batch-wise, batch number should be empty").format(item_code)
			#JDLP - 2017-01-30 - batch_no
			
		# throw all validation messages
		if self.validation_messages:
			for msg in self.validation_messages:
				msgprint(msg)

			raise frappe.ValidationError(self.validation_messages)