<commit_before># Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe import msgprint, _, throw
from frappe.model.document import Document

status_map = {
	"Contact": [
		["Replied", "communication_sent"],
		["Open", "communication_received"]
	],
	"Job Applicant": [
		["Replied", "communication_sent"],
		["Open", "communication_received"]
	],
	"Lead": [
		["Replied", "communication_sent"],
		["Converted", "has_customer"],
		["Opportunity", "has_opportunity"],
		["Open", "communication_received"],
	],
	"Opportunity": [
		["Draft", None],
		["Submitted", "eval:self.docstatus==1"],
		["Lost", "eval:self.status=='Lost'"],
		["Quotation", "has_quotation"],
		["Replied", "communication_sent"],
		["Cancelled", "eval:self.docstatus==2"],
		["Open", "communication_received"],
	],
	"Quotation": [
		["Draft", None],
		["Submitted", "eval:self.docstatus==1"],
		["Lost", "eval:self.status=='Lost'"],
		["Ordered", "has_sales_order"],
		["Replied", "communication_sent"],
		["Cancelled", "eval:self.docstatus==2"],
		["Open", "communication_received"],
	],
	"Sales Order": [
		["Draft", None],
		["Submitted", "eval:self.docstatus==1"],
		["Stopped", "eval:self.status=='Stopped'"],
		["Cancelled", "eval:self.docstatus==2"],
	],
	"Support Ticket": [
		["Replied", "communication_sent"],
		["Open", "communication_received"]
	],
}

class StatusUpdater(Document):
	"""
		Updates the status of the calling records
		Delivery Note: Update Delivered Qty, Update Percent and Validate over delivery
		Sales Invoice: Update Billed Amt, Update Percent and Validate over billing
		Installation Note: Update Installed Qty, Update Percent Qty and Validate over installation
	"""

	def update_prevdoc_status(self):
		self.update_qty()
		self.validate_qty()

	def set_status(self, update=False):
		if self.get("__islocal"):
			return

		if self.doctype in status_map:
			sl = status_map[self.doctype][:]
			sl.reverse()
			for s in sl:
				if not s[1]:
					self.status = s[0]
					break
				elif s[1].startswith("eval:"):
					if eval(s[1][5:]):
						self.status = s[0]
						break
				elif getattr(self, s[1])():
					self.status = s[0]
					break

			if update:
				frappe.db.set_value(self.doctype, self.name, "status", self.status)

	def on_communication(self):
		if not self.get("communications"): return
		self.communication_set = True
		self.get("communications").sort(key=lambda d: d.creation)
		self.set_status(update=True)
		del self.communication_set

	def communication_received(self):
		if getattr(self, "communication_set", False):
			last_comm = self.get("communications")
			if last_comm:
				return last_comm[-1].sent_or_received == "Received"

	def communication_sent(self):
		if getattr(self, "communication_set", False):
			last_comm = self.get("communications")
			if last_comm:
				return last_comm[-1].sent_or_received == "Sent"

	def validate_qty(self):
		"""
			Validates qty at row level
		"""
		self.tolerance = {}
		self.global_tolerance = None

		for args in self.status_updater:
			# get unique transactions to update
			for d in self.get_all_children():
				if d.doctype == args['source_dt'] and d.get(args["join_field"]):
					args['name'] = d.get(args['join_field'])

					# get all qty where qty > target_field
					item = frappe.db.sql("""select item_code, `{target_ref_field}`,
						`{target_field}`, parenttype, parent from `tab{target_dt}`
						where `{target_ref_field}` < `{target_field}`
						and name=%s and docstatus=1""".format(**args),
						args['name'], as_dict=1)
					if item:
						item = item[0]
						item['idx'] = d.idx
						item['target_ref_field'] = args['target_ref_field'].replace('_', ' ')

						if not item[args['target_ref_field']]:
							msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code))
						elif args.get('no_tolerance'):
							item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']]
							if item['reduce_by'] > .01:
								msgprint(_("Allowance for over-{0} crossed for Item {1}")
									.format(args["overflow_type"], item.item_code))
								throw(_("{0} must be reduced by {1} or you should increase overflow tolerance")
									.format(_(item.target_ref_field.title()), item["reduce_by"]))

						else:
							self.check_overflow_with_tolerance(item, args)

	def check_overflow_with_tolerance(self, item, args):
		"""
			Checks if there is overflow condering a relaxation tolerance
		"""
		# check if overflow is within tolerance
		tolerance, self.tolerance, self.global_tolerance = get_tolerance_for(item['item_code'],
			self.tolerance, self.global_tolerance)

		overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
		 	item[args['target_ref_field']]) * 100
		print overflow_percent - tolerance
		if overflow_percent - tolerance > 0.01:
			item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100)
			item['reduce_by'] = item[args['target_field']] - item['max_allowed']

			msgprint(_("Allowance for over-{0} crossed for Item {1}.")
				.format(args["overflow_type"], item["item_code"]))
			throw(_("{0} must be reduced by {1} or you should increase overflow tolerance")
				.format(_(item["target_ref_field"].title()), item["reduce_by"]))

	def update_qty(self, change_modified=True):
		"""
			Updates qty at row level
		"""
		for args in self.status_updater:
			# condition to include current record (if submit or no if cancel)
			if self.docstatus == 1:
				args['cond'] = ' or parent="%s"' % self.name.replace('"', '\"')
			else:
				args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')

			args['modified_cond'] = ''
			if change_modified:
				args['modified_cond'] = ', modified = now()'

			# update quantities in child table
			for d in self.get_all_children():
				if d.doctype == args['source_dt']:<commit_msg>Fixes overflow tolerance<commit_after># Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe import msgprint, _, throw
from frappe.model.document import Document

status_map = {
	"Contact": [
		["Replied", "communication_sent"],
		["Open", "communication_received"]
	],
	"Job Applicant": [
		["Replied", "communication_sent"],
		["Open", "communication_received"]
	],
	"Lead": [
		["Replied", "communication_sent"],
		["Converted", "has_customer"],
		["Opportunity", "has_opportunity"],
		["Open", "communication_received"],
	],
	"Opportunity": [
		["Draft", None],
		["Submitted", "eval:self.docstatus==1"],
		["Lost", "eval:self.status=='Lost'"],
		["Quotation", "has_quotation"],
		["Replied", "communication_sent"],
		["Cancelled", "eval:self.docstatus==2"],
		["Open", "communication_received"],
	],
	"Quotation": [
		["Draft", None],
		["Submitted", "eval:self.docstatus==1"],
		["Lost", "eval:self.status=='Lost'"],
		["Ordered", "has_sales_order"],
		["Replied", "communication_sent"],
		["Cancelled", "eval:self.docstatus==2"],
		["Open", "communication_received"],
	],
	"Sales Order": [
		["Draft", None],
		["Submitted", "eval:self.docstatus==1"],
		["Stopped", "eval:self.status=='Stopped'"],
		["Cancelled", "eval:self.docstatus==2"],
	],
	"Support Ticket": [
		["Replied", "communication_sent"],
		["Open", "communication_received"]
	],
}

class StatusUpdater(Document):
	"""
		Updates the status of the calling records
		Delivery Note: Update Delivered Qty, Update Percent and Validate over delivery
		Sales Invoice: Update Billed Amt, Update Percent and Validate over billing
		Installation Note: Update Installed Qty, Update Percent Qty and Validate over installation
	"""

	def update_prevdoc_status(self):
		self.update_qty()
		self.validate_qty()

	def set_status(self, update=False):
		if self.get("__islocal"):
			return

		if self.doctype in status_map:
			sl = status_map[self.doctype][:]
			sl.reverse()
			for s in sl:
				if not s[1]:
					self.status = s[0]
					break
				elif s[1].startswith("eval:"):
					if eval(s[1][5:]):
						self.status = s[0]
						break
				elif getattr(self, s[1])():
					self.status = s[0]
					break

			if update:
				frappe.db.set_value(self.doctype, self.name, "status", self.status)

	def on_communication(self):
		if not self.get("communications"): return
		self.communication_set = True
		self.get("communications").sort(key=lambda d: d.creation)
		self.set_status(update=True)
		del self.communication_set

	def communication_received(self):
		if getattr(self, "communication_set", False):
			last_comm = self.get("communications")
			if last_comm:
				return last_comm[-1].sent_or_received == "Received"

	def communication_sent(self):
		if getattr(self, "communication_set", False):
			last_comm = self.get("communications")
			if last_comm:
				return last_comm[-1].sent_or_received == "Sent"

	def validate_qty(self):
		"""
			Validates qty at row level
		"""
		self.tolerance = {}
		self.global_tolerance = None

		for args in self.status_updater:
			# get unique transactions to update
			for d in self.get_all_children():
				if d.doctype == args['source_dt'] and d.get(args["join_field"]):
					args['name'] = d.get(args['join_field'])

					# get all qty where qty > target_field
					item = frappe.db.sql("""select item_code, `{target_ref_field}`,
						`{target_field}`, parenttype, parent from `tab{target_dt}`
						where `{target_ref_field}` < `{target_field}`
						and name=%s and docstatus=1""".format(**args),
						args['name'], as_dict=1)
					if item:
						item = item[0]
						item['idx'] = d.idx
						item['target_ref_field'] = args['target_ref_field'].replace('_', ' ')

						if not item[args['target_ref_field']]:
							msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code))
						elif args.get('no_tolerance'):
							item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']]
							if item['reduce_by'] > .01:
								msgprint(_("Allowance for over-{0} crossed for Item {1}")
									.format(args["overflow_type"], item.item_code))
								throw(_("{0} must be reduced by {1} or you should increase overflow tolerance")
									.format(_(item.target_ref_field.title()), item["reduce_by"]))

						else:
							self.check_overflow_with_tolerance(item, args)

	def check_overflow_with_tolerance(self, item, args):
		"""
			Checks if there is overflow condering a relaxation tolerance
		"""
		# check if overflow is within tolerance
		tolerance, self.tolerance, self.global_tolerance = get_tolerance_for(item['item_code'],
			self.tolerance, self.global_tolerance)

		overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
		 	item[args['target_ref_field']]) * 100

		if overflow_percent - tolerance > 0.01:
			item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100)
			item['reduce_by'] = item[args['target_field']] - item['max_allowed']

			msgprint(_("Allowance for over-{0} crossed for Item {1}.")
				.format(args["overflow_type"], item["item_code"]))
			throw(_("{0} must be reduced by {1} or you should increase overflow tolerance")
				.format(_(item["target_ref_field"].title()), item["reduce_by"]))

	def update_qty(self, change_modified=True):
		"""
			Updates qty at row level
		"""
		for args in self.status_updater:
			# condition to include current record (if submit or no if cancel)
			if self.docstatus == 1:
				args['cond'] = ' or parent="%s"' % self.name.replace('"', '\"')
			else:
				args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')

			args['modified_cond'] = ''
			if change_modified:
				args['modified_cond'] = ', modified = now()'

			# update quantities in child table
			for d in self.get_all_children():
				if d.doctype == args['source_dt']:
{'fraction_non_alphanumeric': 0.16150974699294898, 'fraction_numerical': 0.008129406885109913, 'mean_word_length': 4.379741186970103, 'pattern_counts': {'":': 14, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1441389', 'n_tokens_mistral': 4766, 'n_tokens_neox': 3985, 'n_words': 936}