Example #1
1
def get_transitions(doc, workflow = None):
	'''Return list of possible transitions for the given doc'''
	doc = frappe.get_doc(frappe.parse_json(doc))

	if doc.is_new():
		return []

	frappe.has_permission(doc, 'read', throw=True)
	roles = frappe.get_roles()

	if not workflow:
		workflow = get_workflow(doc.doctype)
	current_state = doc.get(workflow.workflow_state_field)

	if not current_state:
		frappe.throw(_('Workflow State not set'), WorkflowStateError)

	transitions = []
	for transition in workflow.transitions:
		if transition.state == current_state and transition.allowed in roles:
			if transition.condition:
				# if condition, evaluate
				# access to frappe.db.get_value and frappe.db.get_list
				success = frappe.safe_eval(transition.condition,
					dict(frappe = frappe._dict(
						db = frappe._dict(get_value = frappe.db.get_value, get_list=frappe.db.get_list),
						session = frappe.session
					)),
					dict(doc = doc))
				if not success:
					continue
			transitions.append(transition.as_dict())

	return transitions
Example #2
0
def get_item_map(item_code):
	"""Optimization: get only the item doc and re_order_levels table"""

	condition = ""
	if item_code:
		condition = 'and item_code = "{0}"'.format(frappe.db.escape(item_code, percent=False))

	items = frappe.db.sql("""select * from `tabItem` item
		where is_stock_item = 1
		and disabled=0
		{condition}
		and (end_of_life > %(today)s or end_of_life is null or end_of_life='0000-00-00')
		and exists (select name from `tabBin` bin where bin.item_code=item.name)"""\
		.format(condition=condition), {"today": today()}, as_dict=True)

	condition = ""
	if item_code:
		condition = 'where parent="{0}"'.format(frappe.db.escape(item_code, percent=False))

	reorder_levels = frappe._dict()
	for ir in frappe.db.sql("""select * from `tabItem Reorder` {condition}""".format(condition=condition), as_dict=1):
		if ir.parent not in reorder_levels:
			reorder_levels[ir.parent] = []

		reorder_levels[ir.parent].append(ir)

	item_map = frappe._dict()
	for item in items:
		item["reorder_levels"] = reorder_levels.get(item.name) or []
		item_map[item.name] = item

	return item_map
Example #3
0
def get_columns_dict(columns):
	"""Returns a dict with column docfield values as dict
		The keys for the dict are both idx and fieldname,
		so either index or fieldname can be used to search for a column's docfield properties
	"""
	columns_dict = frappe._dict()
	for idx, col in enumerate(columns):
		col_dict = frappe._dict()

		# string
		if isinstance(col, string_types):
			col = col.split(":")
			if len(col) > 1:
				if "/" in col[1]:
					col_dict["fieldtype"], col_dict["options"] = col[1].split("/")
				else:
					col_dict["fieldtype"] = col[1]

			col_dict["label"] = col[0]
			col_dict["fieldname"] = frappe.scrub(col[0])

		# dict
		else:
			col_dict.update(col)
			if "fieldname" not in col_dict:
				col_dict["fieldname"] = frappe.scrub(col_dict["label"])

		columns_dict[idx] = col_dict
		columns_dict[col_dict["fieldname"]] = col_dict

	return columns_dict
Example #4
0
def get_invoice_so_dn_map(invoice_list):
    si_items = frappe.db.sql(
        """select parent, sales_order, delivery_note, so_detail
		from `tabSales Invoice Item` where parent in (%s)
		and (ifnull(sales_order, '') != '' or ifnull(delivery_note, '') != '')"""
        % ", ".join(["%s"] * len(invoice_list)),
        tuple([inv.name for inv in invoice_list]),
        as_dict=1,
    )

    invoice_so_dn_map = {}
    for d in si_items:
        if d.sales_order:
            invoice_so_dn_map.setdefault(d.parent, frappe._dict()).setdefault("sales_order", []).append(d.sales_order)

        delivery_note_list = None
        if d.delivery_note:
            delivery_note_list = [d.delivery_note]
        elif d.sales_order:
            delivery_note_list = frappe.db.sql_list(
                """select distinct parent from `tabDelivery Note Item`
				where docstatus=1 and so_detail=%s""",
                d.so_detail,
            )

        if delivery_note_list:
            invoice_so_dn_map.setdefault(d.parent, frappe._dict()).setdefault("delivery_note", delivery_note_list)

    return invoice_so_dn_map
Example #5
0
def check_for_update():
	updates = frappe._dict(major=[], minor=[], patch=[])
	apps = get_versions()

	for app in apps:
		app_details = check_release_on_github(app)
		if not app_details: continue

		github_version, org_name = app_details
		# Get local instance's current version or the app

		branch_version = apps[app]['branch_version'].split(' ')[0] if apps[app].get('branch_version', '') else ''
		instance_version = Version(branch_version or apps[app].get('version'))
		# Compare and popup update message
		for update_type in updates:
			if github_version.__dict__[update_type] > instance_version.__dict__[update_type]:
				updates[update_type].append(frappe._dict(
					current_version   = str(instance_version),
					available_version = str(github_version),
					org_name          = org_name,
					app_name          = app,
					title             = apps[app]['title'],
				))
				break
			if github_version.__dict__[update_type] < instance_version.__dict__[update_type]: break

	add_message_to_redis(updates)
Example #6
0
def update_event(args, field_map):
	args = frappe._dict(json.loads(args))
	field_map = frappe._dict(json.loads(field_map))
	w = frappe.get_doc(args.doctype, args.name)
	w.set(field_map.start, args[field_map.start])
	w.set(field_map.end, args.get(field_map.end))
	w.save()
Example #7
0
def get_default_df(fieldname):
    if fieldname in default_fields:
        if fieldname in ("creation", "modified"):
            return frappe._dict(fieldname=fieldname, fieldtype="Datetime")

        else:
            return frappe._dict(fieldname=fieldname, fieldtype="Data")
def get_asset_costs(assets, filters):
	asset_costs = frappe._dict()
	for d in assets:
		asset_costs.setdefault(d.asset_category, frappe._dict({
			"cost_as_on_from_date": 0,
			"cost_of_new_purchase": 0,
			"cost_of_sold_asset": 0,
			"cost_of_scrapped_asset": 0
		}))
		
		costs = asset_costs[d.asset_category]
		
		if getdate(d.purchase_date) < getdate(filters.from_date):
			if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date):
				costs.cost_as_on_from_date += flt(d.gross_purchase_amount)
		else:
			costs.cost_of_new_purchase += flt(d.gross_purchase_amount)
			
			if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \
					and getdate(d.disposal_date) <= getdate(filters.to_date):
				if d.status == "Sold":
					costs.cost_of_sold_asset += flt(d.gross_purchase_amount)
				elif d.status == "Scrapped":
					costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount)
			
	return asset_costs
	def calculate_component_amounts(self):
		if not getattr(self, '_salary_structure_doc', None):
			self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure)

		data = self.get_data_for_eval()

		for key in ('earnings', 'deductions'):
			for struct_row in self._salary_structure_doc.get(key):
				amount = self.eval_condition_and_formula(struct_row, data)
				if amount and struct_row.statistical_component == 0 and struct_row.variable_based_on_taxable_salary != 1:
					self.update_component_row(struct_row, amount, key)

				if key=="earnings" and struct_row.is_flexible_benefit == 1:
					self.add_employee_flexi_benefits(struct_row)

		additional_components = get_additional_salary_component(self.employee, self.start_date, self.end_date)
		if additional_components:
			for additional_component in additional_components:
				additional_component = frappe._dict(additional_component)
				amount = additional_component.amount
				key = "earnings"
				if additional_component.type == "Deduction":
					key = "deductions"
				self.update_component_row(frappe._dict(additional_component.struct_row), amount, key)

		self.get_last_payroll_period_benefit()

		# Calculate variable_based_on_taxable_salary after all components updated in salary slip
		for struct_row in self._salary_structure_doc.get("deductions"):
			if struct_row.variable_based_on_taxable_salary == 1:
				tax_row, amount = self.calculate_variable_based_on_taxable_salary(struct_row.salary_component)
				if tax_row and amount:
					self.update_component_row(frappe._dict(tax_row), amount, "deductions")
	def get_partywise_total(self, party_naming_by, args):
		party_total = frappe._dict()
		for d in self.get_voucherwise_data(party_naming_by, args):
			party_total.setdefault(d.party,
				frappe._dict({
					"invoiced_amt": 0,
					"paid_amt": 0,
					"credit_amt": 0,
					"outstanding_amt": 0,
					"range1": 0,
					"range2": 0,
					"range3": 0,
					"range4": 0,
					"sales_person": []
				})
			)
			for k in list(party_total[d.party]):
				if k not in ["currency", "sales_person"]:
					party_total[d.party][k] += flt(d.get(k, 0))

			party_total[d.party].currency = d.currency

			if d.sales_person:
				party_total[d.party].sales_person.append(d.sales_person)

		return party_total
Example #11
0
def get_invoice_po_pr_map(invoice_list):
	pi_items = frappe.db.sql("""select parent, purchase_order, purchase_receipt, po_detail,
		project from `tabPurchase Invoice Item` where parent in (%s)
		and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')""" %
		', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)

	invoice_po_pr_map = {}
	for d in pi_items:
		if d.purchase_order:
			invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault(
				"purchase_order", []).append(d.purchase_order)

		pr_list = None
		if d.purchase_receipt:
			pr_list = [d.purchase_receipt]
		elif d.po_detail:
			pr_list = frappe.db.sql_list("""select distinct parent from `tabPurchase Receipt Item`
				where docstatus=1 and prevdoc_detail_docname=%s""", d.po_detail)

		if pr_list:
			invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault("purchase_receipt", pr_list)

		if d.project:
			invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault(
				"project", []).append(d.project)

	return invoice_po_pr_map
def execute(filters=None):
	if not filters: filters = {}

	employee_filters = filters.get("company") and \
		[["Employee", "company", "=", filters.get("company")]] or None
	employees = runreport(doctype="Employee", fields=["name", "employee_name", "department"],
		filters=employee_filters)

	if not employees:
		frappe.throw(_("No employee found!"))

	leave_types = frappe.db.sql_list("select name from `tabLeave Type`")

	if filters.get("fiscal_year"):
		fiscal_years = [filters["fiscal_year"]]
	else:
		fiscal_years = frappe.db.sql_list("select name from `tabFiscal Year` order by name desc")

	allocations = frappe.db.sql("""select employee, fiscal_year, leave_type, total_leaves_allocated
	 	from `tabLeave Allocation`
		where docstatus=1 and employee in (%s)""" %
		','.join(['%s']*len(employees)), employees, as_dict=True)

	applications = frappe.db.sql("""select employee, fiscal_year, leave_type,
			SUM(total_leave_days) as leaves
		from `tabLeave Application`
		where status="Approved" and docstatus = 1 and employee in (%s)
		group by employee, fiscal_year, leave_type""" %
			','.join(['%s']*len(employees)), employees, as_dict=True)

	columns = [
		"Fiscal Year", "Employee:Link/Employee:150", "Employee Name::200", "Department::150"
	]

	for leave_type in leave_types:
		columns.append(leave_type + " Allocated:Float")
		columns.append(leave_type + " Taken:Float")
		columns.append(leave_type + " Balance:Float")

	data = {}
	for d in allocations:
		data.setdefault((d.fiscal_year, d.employee,
			d.leave_type), frappe._dict()).allocation = d.total_leaves_allocated

	for d in applications:
		data.setdefault((d.fiscal_year, d.employee,
			d.leave_type), frappe._dict()).leaves = d.leaves

	result = []
	for fiscal_year in fiscal_years:
		for employee in employees:
			row = [fiscal_year, employee.name, employee.employee_name, employee.department]
			result.append(row)
			for leave_type in leave_types:
				tmp = data.get((fiscal_year, employee.name, leave_type), frappe._dict())
				row.append(tmp.allocation or 0)
				row.append(tmp.leaves or 0)
				row.append((tmp.allocation or 0) - (tmp.leaves or 0))

	return columns, result
Example #13
0
def validate_space_limit(file_size):
    """Stop from writing file if max space limit is reached"""
    from frappe.utils.file_manager import MaxFileSizeReachedError

    limits = get_limits()
    if not limits.space:
        return

        # to MB
    space_limit = flt(limits.space * 1024.0, 2)

    # in MB
    usage = frappe._dict(limits.space_usage or {})
    if not usage:
        # first time
        usage = frappe._dict(update_space_usage())

    file_size = file_size / (1024.0 ** 2)

    if flt(flt(usage.total) + file_size, 2) > space_limit:
        # Stop from attaching file
        frappe.throw(
            _("You have exceeded the max space of {0} for your plan. {1}.").format(
                "<b>{0}MB</b>".format(cint(space_limit))
                if (space_limit < 1024)
                else "<b>{0}GB</b>".format(limits.space),
                '<a href="#usage-info">{0}</a>'.format(_("Click here to check your usage or upgrade to a higher plan")),
            ),
            MaxFileSizeReachedError,
        )

        # update files size in frappe subscription
    usage.files_size = flt(usage.files_size) + file_size
    update_limits({"space_usage": usage})
Example #14
0
	def get_item_list(self):
		il = []
		for d in self.get("items"):
			if d.qty is None:
				frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx))

			if self.has_product_bundle(d.item_code):
				for p in self.get("packed_items"):
					if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
						# the packing details table's qty is already multiplied with parent's qty
						il.append(frappe._dict({
							'warehouse': p.warehouse or d.warehouse,
							'item_code': p.item_code,
							'qty': flt(p.qty),
							'uom': p.uom,
							'batch_no': cstr(p.batch_no).strip(),
							'serial_no': cstr(p.serial_no).strip(),
							'name': d.name,
							'target_warehouse': p.target_warehouse
						}))
			else:
				il.append(frappe._dict({
					'warehouse': d.warehouse,
					'item_code': d.item_code,
					'qty': d.stock_qty,
					'uom': d.uom,
					'stock_uom': d.stock_uom,
					'conversion_factor': d.conversion_factor,
					'batch_no': cstr(d.get("batch_no")).strip(),
					'serial_no': cstr(d.get("serial_no")).strip(),
					'name': d.name,
					'target_warehouse': d.target_warehouse
				}))
		return il
Example #15
0
def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
	"""returns last purchase details in stock uom"""
	# get last purchase order item details
	last_purchase_order = frappe.db.sql("""\
		select po.name, po.transaction_date, po.conversion_rate,
			po_item.conversion_factor, po_item.base_price_list_rate,
			po_item.discount_percentage, po_item.base_rate
		from `tabPurchase Order` po, `tabPurchase Order Item` po_item
		where po.docstatus = 1 and po_item.item_code = %s and po.name != %s and
			po.name = po_item.parent
		order by po.transaction_date desc, po.name desc
		limit 1""", (item_code, cstr(doc_name)), as_dict=1)

	# get last purchase receipt item details
	last_purchase_receipt = frappe.db.sql("""\
		select pr.name, pr.posting_date, pr.posting_time, pr.conversion_rate,
			pr_item.conversion_factor, pr_item.base_price_list_rate, pr_item.discount_percentage,
			pr_item.base_rate
		from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
		where pr.docstatus = 1 and pr_item.item_code = %s and pr.name != %s and
			pr.name = pr_item.parent
		order by pr.posting_date desc, pr.posting_time desc, pr.name desc
		limit 1""", (item_code, cstr(doc_name)), as_dict=1)

	purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date \
		or "1900-01-01")
	purchase_receipt_date = getdate(last_purchase_receipt and \
		last_purchase_receipt[0].posting_date or "1900-01-01")

	if (purchase_order_date > purchase_receipt_date) or \
			(last_purchase_order and not last_purchase_receipt):
		# use purchase order
		last_purchase = last_purchase_order[0]
		purchase_date = purchase_order_date

	elif (purchase_receipt_date > purchase_order_date) or \
			(last_purchase_receipt and not last_purchase_order):
		# use purchase receipt
		last_purchase = last_purchase_receipt[0]
		purchase_date = purchase_receipt_date

	else:
		return frappe._dict()

	conversion_factor = flt(last_purchase.conversion_factor)
	out = frappe._dict({
		"base_price_list_rate": flt(last_purchase.base_price_list_rate) / conversion_factor,
		"base_rate": flt(last_purchase.base_rate) / conversion_factor,
		"discount_percentage": flt(last_purchase.discount_percentage),
		"purchase_date": purchase_date
	})

	conversion_rate = flt(conversion_rate) or 1.0
	out.update({
		"price_list_rate": out.base_price_list_rate / conversion_rate,
		"rate": out.base_rate / conversion_rate,
		"base_rate": out.base_rate
	})

	return out
def validate_conversion_rate(args, meta):
	from erpnext.controllers.accounts_controller import validate_conversion_rate

	if (not args.conversion_rate
		and args.currency==frappe.db.get_value("Company", args.company, "default_currency")):
		args.conversion_rate = 1.0

	# validate currency conversion rate
	validate_conversion_rate(args.currency, args.conversion_rate,
		meta.get_label("conversion_rate"), args.company)

	args.conversion_rate = flt(args.conversion_rate,
		get_field_precision(meta.get_field("conversion_rate"),
			frappe._dict({"fields": args})))

	# validate price list currency conversion rate
	if not args.get("price_list_currency"):
		throw(_("Price List Currency not selected"))
	else:
		validate_conversion_rate(args.price_list_currency, args.plc_conversion_rate,
			meta.get_label("plc_conversion_rate"), args.company)

		args.plc_conversion_rate = flt(args.plc_conversion_rate,
			get_field_precision(meta.get_field("plc_conversion_rate"),
			frappe._dict({"fields": args})))
Example #17
0
def get_itemised_tax(taxes, with_tax_account=False):
	itemised_tax = {}
	for tax in taxes:
		if getattr(tax, "category", None) and tax.category=="Valuation":
			continue

		item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {}
		if item_tax_map:
			for item_code, tax_data in item_tax_map.items():
				itemised_tax.setdefault(item_code, frappe._dict())

				tax_rate = 0.0
				tax_amount = 0.0

				if isinstance(tax_data, list):
					tax_rate = flt(tax_data[0])
					tax_amount = flt(tax_data[1])
				else:
					tax_rate = flt(tax_data)

				itemised_tax[item_code][tax.description] = frappe._dict(dict(
					tax_rate = tax_rate,
					tax_amount = tax_amount
				))

				if with_tax_account:
					itemised_tax[item_code][tax.description].tax_account = tax.account_head

	return itemised_tax
Example #18
0
	def build_field_columns(dt):
		meta = frappe.get_meta(dt)

		tablecolumns = filter(None,
			[(meta.get_field(f[0]) or None) for f in frappe.db.sql('desc `tab%s`' % dt)])

		tablecolumns.sort(lambda a, b: a.idx - b.idx)

		if dt==doctype:
			column_start_end[dt] = frappe._dict({"start": 0})
		else:
			column_start_end[dt] = frappe._dict({"start": len(columns)})

			append_field_column(frappe._dict({
				"fieldname": "name",
				"label": "ID",
				"fieldtype": "Data",
				"reqd": 1,
				"idx": 0,
				"info": _("Leave blank for new records")
			}), True)

		for docfield in tablecolumns:
			append_field_column(docfield, True)

		# all non mandatory fields
		for docfield in tablecolumns:
			append_field_column(docfield, False)

		# append DocType name
		tablerow[column_start_end[dt].start + 1] = dt
		if dt!=doctype:
			tablerow[column_start_end[dt].start + 2] = doctype_parentfield[dt]

		column_start_end[dt].end = len(columns) + 1
def get_field_currency(df, doc=None):
	"""get currency based on DocField options and fieldvalue in doc"""
	currency = None

	if not df.get("options"):
		return None

	if not doc:
		return None

	if not getattr(frappe.local, "field_currency", None):
		frappe.local.field_currency = frappe._dict()

	if not frappe.local.field_currency.get((doc.doctype, doc.parent or doc.name), {}).get(df.fieldname):
		if ":" in cstr(df.get("options")):
			split_opts = df.get("options").split(":")
			if len(split_opts)==3:
				currency = frappe.db.get_value(split_opts[0], doc.get(split_opts[1]), split_opts[2])
		else:
			currency = doc.get(df.get("options"))
			if not currency and doc.parent:
				currency = frappe.db.get_value(doc.parenttype, doc.parent, df.get("options"))

		if currency:
			frappe.local.field_currency.setdefault((doc.doctype, doc.parent or doc.name), frappe._dict())\
				.setdefault(df.fieldname, currency)

	return frappe.local.field_currency.get((doc.doctype, doc.parent or doc.name), {}).get(df.fieldname)
Example #20
0
def get_children_data(doctype, meta):
	"""
		Get all records from all the child tables of a doctype

		all_children = {
			"parent1": {
				"child_doctype1": [
					{
						"field1": val1,
						"field2": val2
					}
				]
			}
		}

	"""
	all_children = frappe._dict()
	child_search_fields = frappe._dict()

	for child in meta.get_table_fields():
		child_meta = frappe.get_meta(child.options)
		search_fields = child_meta.get_global_search_fields()
		if search_fields:
			child_search_fields.setdefault(child.options, search_fields)
			child_fieldnames = get_selected_fields(child_meta, search_fields)
			child_records = frappe.get_all(child.options, fields=child_fieldnames, filters={
				"docstatus": ["!=", 1],
				"parenttype": doctype
			})

			for record in child_records:
				all_children.setdefault(record.parent, frappe._dict())\
					.setdefault(child.options, []).append(record)

	return all_children, child_search_fields
Example #21
0
def get_list_context(context, doctype):
	from frappe.modules import load_doctype_module
	module = load_doctype_module(doctype)
	if hasattr(module, "get_list_context"):
		return frappe._dict(module.get_list_context(context) or {})

	return frappe._dict()
def get_salesperson_item_month_map(filters):
	import datetime
	salesperson_details = get_salesperson_details(filters)
	tdd = get_target_distribution_details(filters)
	item_groups = get_item_groups()
	sales_persons = get_sales_persons()

	sales_person_achievement_dict = {}
	for sd in salesperson_details:
		achieved_details = get_achieved_details(filters, sd.name, sales_persons, sd.item_group, item_groups)

		for month_id in range(1, 13):
			month = datetime.date(2013, month_id, 1).strftime('%B')
			sales_person_achievement_dict.setdefault(sd.name, {}).setdefault(sd.item_group, {})\
					.setdefault(month, frappe._dict({
							"target": 0.0, "achieved": 0.0
						}))

			sales_target_achieved = sales_person_achievement_dict[sd.name][sd.item_group][month]
			month_percentage = tdd.get(sd.distribution_id, {}).get(month, 0) \
				if sd.distribution_id else 100.0/12

			if (filters["target_on"] == "Quantity"):
				sales_target_achieved.target = flt(sd.target_qty) * month_percentage / 100
			else:
				sales_target_achieved.target = flt(sd.target_amount) * month_percentage / 100

			sales_target_achieved.achieved = achieved_details.get(month, frappe._dict())\
				.get(filters["target_on"].lower())

	return sales_person_achievement_dict
	def precision(self, fieldname, parentfield=None):
		"""Returns float precision for a particular field (or get global default).

		:param fieldname: Fieldname for which precision is required.
		:param parentfield: If fieldname is in child table."""
		from frappe.model.meta import get_field_precision

		if parentfield and not isinstance(parentfield, basestring):
			parentfield = parentfield.parentfield

		cache_key = parentfield or "main"

		if not hasattr(self, "_precision"):
			self._precision = frappe._dict()

		if cache_key not in self._precision:
			self._precision[cache_key] = frappe._dict()

		if fieldname not in self._precision[cache_key]:
			self._precision[cache_key][fieldname] = None

			doctype = self.meta.get_field(parentfield).options if parentfield else self.doctype
			df = frappe.get_meta(doctype).get_field(fieldname)

			if df.fieldtype in ("Currency", "Float", "Percent"):
				self._precision[cache_key][fieldname] = get_field_precision(df, self)

		return self._precision[cache_key][fieldname]
Example #24
0
def get_itemised_tax_breakup_data(doc):
	itemised_tax = get_itemised_tax(doc.taxes)

	itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
	
	if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
		return itemised_tax, itemised_taxable_amount

	item_hsn_map = frappe._dict()
	for d in doc.items:
		item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))

	hsn_tax = {}
	for item, taxes in itemised_tax.items():
		hsn_code = item_hsn_map.get(item)
		hsn_tax.setdefault(hsn_code, frappe._dict())
		for tax_account, tax_detail in taxes.items():
			hsn_tax[hsn_code].setdefault(tax_account, {"tax_rate": 0, "tax_amount": 0})
			hsn_tax[hsn_code][tax_account]["tax_rate"] = tax_detail.get("tax_rate")
			hsn_tax[hsn_code][tax_account]["tax_amount"] += tax_detail.get("tax_amount")

	# set taxable amount
	hsn_taxable_amount = frappe._dict()
	for item, taxable_amount in itemised_taxable_amount.items():
		hsn_code = item_hsn_map.get(item)
		hsn_taxable_amount.setdefault(hsn_code, 0)
		hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item)

	return hsn_tax, hsn_taxable_amount
def get_data(filters, leave_types):
	user = frappe.session.user
	allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
	allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)

	active_employees = frappe.get_all("Employee", 
		filters = { "status": "Active", "company": filters.company}, 
		fields = ["name", "employee_name", "department", "user_id"])
	
	data = []
	for employee in active_employees:
		leave_approvers = [l.leave_approver for l in frappe.db.sql("""select leave_approver from `tabEmployee Leave Approver` where parent = %s""",
							(employee.name),as_dict=True)]
		if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
			row = [employee.name, employee.employee_name, employee.department]

			for leave_type in leave_types:
				# leaves taken
				leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
					filters.from_date, filters.to_date)

				# opening balance
				opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
					allocation_records_based_on_from_date.get(employee.name, frappe._dict()))

				# closing balance
				closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
					allocation_records_based_on_to_date.get(employee.name, frappe._dict()))

				row += [opening, leaves_taken, closing]
			
			data.append(row)
		
	return data
Example #26
0
def request(context, args=None, path=None):
	"Run a request as an admin"
	import frappe.handler
	import frappe.api
	for site in context.sites:
		try:
			frappe.init(site=site)
			frappe.connect()
			if args:
				if "?" in args:
					frappe.local.form_dict = frappe._dict([a.split("=") for a in args.split("?")[-1].split("&")])
				else:
					frappe.local.form_dict = frappe._dict()

				if args.startswith("/api/method"):
					frappe.local.form_dict.cmd = args.split("?")[0].split("/")[-1]
			elif path:
				with open(os.path.join('..', path), 'r') as f:
					args = json.loads(f.read())

				frappe.local.form_dict = frappe._dict(args)

			frappe.handler.execute_cmd(frappe.form_dict.cmd)

			print(frappe.response)
		finally:
			frappe.destroy()
def get_achieved_details(filters, sales_person, item_groups):
	start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:]

	lft, rgt = frappe.get_value("Sales Person", sales_person, ["lft", "rgt"])

	item_details = frappe.db.sql("""
		select
			soi.item_code, sum(soi.qty * (st.allocated_percentage/100)) as qty,
			sum(soi.base_net_amount * (st.allocated_percentage/100)) as amount,
			st.sales_person, MONTHNAME(so.transaction_date) as month_name
		from
			`tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st
		where
			soi.parent=so.name and so.docstatus=1 and st.parent=so.name
			and so.transaction_date>=%s and so.transaction_date<=%s
			and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person)
		group by
			sales_person, item_code, month_name
			""",
		(start_date, end_date, lft, rgt), as_dict=1)

	item_actual_details = {}
	for d in item_details:
		item_group = item_groups[d.item_code]
		item_actual_details.setdefault(item_group, frappe._dict()).setdefault(d.month_name,\
			frappe._dict({
				"quantity" : 0,
				"amount" : 0
			}))

		value_dict = item_actual_details[item_group][d.month_name]
		value_dict.quantity += flt(d.qty)
		value_dict.amount += flt(d.amount)

	return item_actual_details
Example #28
0
def get_itemised_tax(taxes):
	itemised_tax = {}
	for tax in taxes:
		if getattr(tax, "category", None) and tax.category=="Valuation":
			continue

		tax_amount_precision = tax.precision("tax_amount")
		tax_rate_precision = tax.precision("rate")
		
		item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {}
		
		for item_code, tax_data in item_tax_map.items():
			itemised_tax.setdefault(item_code, frappe._dict())
			
			if isinstance(tax_data, list):
				precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision
				
				itemised_tax[item_code][tax.description] = frappe._dict(dict(
					tax_rate=flt(tax_data[0]),
					tax_amount=flt(tax_data[1])
				))
			else:
				itemised_tax[item_code][tax.description] = frappe._dict(dict(
					tax_rate=flt(tax_data),
					tax_amount=0.0
				))

	return itemised_tax
Example #29
0
def get_list_context(context, doctype):
	from frappe.modules import load_doctype_module
	from frappe.website.doctype.web_form.web_form import get_web_form_list

	list_context = context or frappe._dict()
	meta = frappe.get_meta(doctype)

	if not meta.custom:
		# custom doctypes don't have modules
		module = load_doctype_module(doctype)
		if hasattr(module, "get_list_context"):
			out = frappe._dict(module.get_list_context(list_context) or {})
			if out:
				list_context = out

	# get path from '/templates/' folder of the doctype
	if not list_context.row_template:
		list_context.row_template = meta.get_row_template()

	# is web form, show the default web form filters
	# which is only the owner
	if frappe.form_dict.web_form_name:
		list_context.web_form_name = frappe.form_dict.web_form_name
		if not list_context.get("get_list"):
			list_context.get_list = get_web_form_list

		if not frappe.flags.web_form:
			# update list context from web_form
			frappe.flags.web_form = frappe.get_doc('Web Form', frappe.form_dict.web_form_name)

		if frappe.flags.web_form.is_standard:
			frappe.flags.web_form.update_list_context(list_context)

	return list_context
Example #30
0
def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None):
	from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
	if mode_of_payment:
		account = get_bank_cash_account(mode_of_payment, company).get("account")

	if not account:
		if account_type=="Bank":
			account = frappe.db.get_value("Company", company, "default_bank_account")
			if not account:
				account = frappe.db.get_value("Account",
					{"company": company, "account_type": "Bank", "is_group": 0})

		elif account_type=="Cash":
			account = frappe.db.get_value("Company", company, "default_cash_account")
			if not account:
				account = frappe.db.get_value("Account",
					{"company": company, "account_type": "Cash", "is_group": 0})

	if account:
		account_details = frappe.db.get_value("Account", account,
			["account_currency", "account_type"], as_dict=1)
			
		return frappe._dict({
			"account": account,
			"balance": get_balance_on(account),
			"account_currency": account_details.account_currency,
			"account_type": account_details.account_type
		})
	else: return frappe._dict()
Example #31
0
 def get_supplier_parent_child_map(self):
     self.parent_child_map = frappe._dict(
         frappe.db.sql(
             """ select name, supplier_group from `tabSupplier`"""))
Example #32
0
def accept(web_form, data, for_payment=False):
    '''Save the web form'''
    data = frappe._dict(json.loads(data))
    files = []
    files_to_delete = []

    web_form = frappe.get_doc("Web Form", web_form)
    if data.doctype != web_form.doc_type:
        frappe.throw(_("Invalid Request"))

    elif data.name and not web_form.allow_edit:
        frappe.throw(_("You are not allowed to update this Web Form Document"))

    frappe.flags.in_web_form = True

    if data.name:
        # update
        doc = frappe.get_doc(data.doctype, data.name)
    else:
        # insert
        doc = frappe.new_doc(data.doctype)

    # set values
    for fieldname, value in iteritems(data):
        if value and isinstance(value, dict):
            try:
                if "__file_attachment" in value:
                    files.append((fieldname, value))
                    continue
                if '__no_attachment' in value:
                    files_to_delete.append(doc.get(fieldname))
                    value = ''

            except ValueError:
                pass

        doc.set(fieldname, str(jinja2.escape(value)))

    if for_payment:
        web_form.validate_mandatory(doc)
        doc.run_method('validate_payment')

    if doc.name:
        if has_web_form_permission(doc.doctype, doc.name, "write"):
            doc.save(ignore_permissions=True)
        else:
            # only if permissions are present
            doc.save()

    else:
        # insert
        if web_form.login_required and frappe.session.user == "Guest":
            frappe.throw(_("You must login to submit this form"))

        doc.insert(ignore_permissions=True)

    # add files
    if files:
        for f in files:
            fieldname, filedata = f

            # remove earlier attached file (if exists)
            if doc.get(fieldname):
                remove_file_by_url(doc.get(fieldname), doc.doctype, doc.name)

            # save new file
            filedoc = save_file(filedata["filename"],
                                filedata["dataurl"],
                                doc.doctype,
                                doc.name,
                                decode=True)

            # update values
            doc.set(fieldname, filedoc.file_url)

        doc.save()

    if files_to_delete:
        for f in files_to_delete:
            if f:
                remove_file_by_url(f, doc.doctype, doc.name)

    frappe.flags.web_form_doc = doc

    if for_payment:
        return web_form.get_payment_gateway_url(doc)
    else:
        return doc.name
Example #33
0
class WebForm(WebsiteGenerator):
    website = frappe._dict(no_cache=1)

    def onload(self):
        super(WebForm, self).onload()
        if self.is_standard and not frappe.conf.developer_mode:
            self.use_meta_fields()

    def validate(self):
        super(WebForm, self).validate()

        if not self.module:
            self.module = frappe.db.get_value('DocType', self.doc_type,
                                              'module')

        if (not (frappe.flags.in_install or frappe.flags.in_patch
                 or frappe.flags.in_test or frappe.flags.in_fixtures)
                and self.is_standard and not frappe.conf.developer_mode):
            frappe.throw(
                _("You need to be in developer mode to edit a Standard Web Form"
                  ))

        if not frappe.flags.in_import:
            self.validate_fields()

        if self.accept_payment:
            self.validate_payment_amount()

    def validate_fields(self):
        '''Validate all fields are present'''
        from frappe.model import no_value_fields
        missing = []
        meta = frappe.get_meta(self.doc_type)
        for df in self.web_form_fields:
            if df.fieldname and (df.fieldtype not in no_value_fields
                                 and not meta.has_field(df.fieldname)):
                missing.append(df.fieldname)

        if missing:
            frappe.throw(
                _('Following fields are missing:') + '<br>' +
                '<br>'.join(missing))

    def validate_payment_amount(self):
        if self.amount_based_on_field and not self.amount_field:
            frappe.throw(_("Please select a Amount Field."))
        elif not self.amount_based_on_field and not self.amount > 0:
            frappe.throw(_("Amount must be greater than 0."))

    def reset_field_parent(self):
        '''Convert link fields to select with names as options'''
        for df in self.web_form_fields:
            df.parent = self.doc_type

    def use_meta_fields(self):
        '''Override default properties for standard web forms'''
        meta = frappe.get_meta(self.doc_type)

        for df in self.web_form_fields:
            meta_df = meta.get_field(df.fieldname)

            if not meta_df:
                continue

            for prop in docfield_properties:
                if df.fieldtype == meta_df.fieldtype and prop not in (
                        "idx", "reqd", "default", "description", "default",
                        "options", "hidden", "read_only", "label"):
                    df.set(prop, meta_df.get(prop))

            # TODO translate options of Select fields like Country

    # export
    def on_update(self):
        """
			Writes the .txt for this page and if write_content is checked,
			it will write out a .html file
		"""
        path = export_module_json(self, self.is_standard, self.module)

        if path:
            # js
            if not os.path.exists(path + '.js'):
                with open(path + '.js', 'w') as f:
                    f.write("""frappe.ready(function() {
	// bind events here
})""")

            # py
            if not os.path.exists(path + '.py'):
                with open(path + '.py', 'w') as f:
                    f.write("""from __future__ import unicode_literals

import frappe

def get_context(context):
	# do your magic here
	pass
""")

    def get_context(self, context):
        '''Build context to render the `web_form.html` template'''
        self.set_web_form_module()

        context._login_required = False
        if self.login_required and frappe.session.user == "Guest":
            context._login_required = True

        doc, delimeter = make_route_string(frappe.form_dict)
        context.doc = doc
        context.delimeter = delimeter

        # check permissions
        if frappe.session.user == "Guest" and frappe.form_dict.name:
            frappe.throw(
                _("You need to be logged in to access this {0}.").format(
                    self.doc_type), frappe.PermissionError)

        if frappe.form_dict.name and not has_web_form_permission(
                self.doc_type, frappe.form_dict.name):
            frappe.throw(
                _("You don't have the permissions to access this document"),
                frappe.PermissionError)

        self.reset_field_parent()

        if self.is_standard:
            self.use_meta_fields()

        if not context._login_required:
            if self.allow_edit:
                if self.allow_multiple:
                    if not frappe.form_dict.name and not frappe.form_dict.new:
                        self.build_as_list(context)
                else:
                    if frappe.session.user != 'Guest' and not frappe.form_dict.name:
                        frappe.form_dict.name = frappe.db.get_value(
                            self.doc_type, {"owner": frappe.session.user},
                            "name")

                    if not frappe.form_dict.name:
                        # only a single doc allowed and no existing doc, hence new
                        frappe.form_dict.new = 1

        # always render new form if login is not required or doesn't allow editing existing ones
        if not self.login_required or not self.allow_edit:
            frappe.form_dict.new = 1

        self.load_document(context)
        context.parents = self.get_parents(context)

        if self.breadcrumbs:
            context.parents = frappe.safe_eval(self.breadcrumbs, {"_": _})

        context.has_header = ((frappe.form_dict.name or frappe.form_dict.new)
                              and (frappe.session.user != "Guest"
                                   or not self.login_required))

        if context.success_message:
            context.success_message = frappe.db.escape(
                context.success_message.replace("\n", "<br>"))

        self.add_custom_context_and_script(context)
        if not context.max_attachment_size:
            context.max_attachment_size = get_max_file_size() / 1024 / 1024

    def load_document(self, context):
        '''Load document `doc` and `layout` properties for template'''
        if frappe.form_dict.name or frappe.form_dict.new:
            context.layout = self.get_layout()
            context.parents = [{"route": self.route, "label": _(self.title)}]

        if frappe.form_dict.name:
            context.doc = frappe.get_doc(self.doc_type, frappe.form_dict.name)
            context.title = context.doc.get(context.doc.meta.get_title_field())
            context.doc.add_seen()

            context.reference_doctype = context.doc.doctype
            context.reference_name = context.doc.name

            if self.allow_comments:
                context.comment_list = get_comment_list(
                    context.doc.doctype, context.doc.name)

    def build_as_list(self, context):
        '''Web form is a list, show render as list.html'''
        from frappe.www.list import get_context as get_list_context

        # set some flags to make list.py/list.html happy
        frappe.form_dict.web_form_name = self.name
        frappe.form_dict.doctype = self.doc_type
        frappe.flags.web_form = self

        self.update_params_from_form_dict(context)
        self.update_list_context(context)
        get_list_context(context)
        context.is_list = True

    def update_params_from_form_dict(self, context):
        '''Copy params from list view to new view'''
        context.params_from_form_dict = ''

        params = {}
        for key, value in iteritems(frappe.form_dict):
            if frappe.get_meta(self.doc_type).get_field(key):
                params[key] = value

        if params:
            context.params_from_form_dict = '&' + urlencode(params)

    def update_list_context(self, context):
        '''update list context for stanard modules'''
        if hasattr(self, 'web_form_module') and hasattr(
                self.web_form_module, 'get_list_context'):
            self.web_form_module.get_list_context(context)

    def get_payment_gateway_url(self, doc):
        if self.accept_payment:
            controller = get_payment_gateway_controller(self.payment_gateway)

            title = "Payment for {0} {1}".format(doc.doctype, doc.name)
            amount = self.amount
            if self.amount_based_on_field:
                amount = doc.get(self.amount_field)
            payment_details = {
                "amount": amount,
                "title": title,
                "description": title,
                "reference_doctype": doc.doctype,
                "reference_docname": doc.name,
                "payer_email": frappe.session.user,
                "payer_name": frappe.utils.get_fullname(frappe.session.user),
                "order_id": doc.name,
                "currency": self.currency,
                "redirect_to": frappe.utils.get_url(self.route)
            }

            # Redirect the user to this url
            return controller.get_payment_url(**payment_details)

    def add_custom_context_and_script(self, context):
        '''Update context from module if standard and append script'''
        if self.web_form_module:
            new_context = self.web_form_module.get_context(context)

            if new_context:
                context.update(new_context)

            js_path = os.path.join(
                os.path.dirname(self.web_form_module.__file__),
                scrub(self.name) + '.js')
            if os.path.exists(js_path):
                context.script = frappe.render_template(
                    open(js_path, 'r').read().decode('utf-8'), context)

            css_path = os.path.join(
                os.path.dirname(self.web_form_module.__file__),
                scrub(self.name) + '.css')
            if os.path.exists(css_path):
                context.style = open(css_path, 'r').read()

    def get_layout(self):
        layout = []

        def add_page(df=None):
            new_page = {'sections': []}
            layout.append(new_page)
            if df and df.fieldtype == 'Page Break':
                new_page.update(df.as_dict())

            return new_page

        def add_section(df=None):
            new_section = {'columns': []}
            layout[-1]['sections'].append(new_section)
            if df and df.fieldtype == 'Section Break':
                new_section.update(df.as_dict())

            return new_section

        def add_column(df=None):
            new_col = []
            layout[-1]['sections'][-1]['columns'].append(new_col)

            return new_col

        page, section, column = None, None, None
        for df in self.web_form_fields:

            # breaks
            if df.fieldtype == 'Page Break':
                page = add_page(df)
                section, column = None, None

            if df.fieldtype == 'Section Break':
                section = add_section(df)
                column = None

            if df.fieldtype == 'Column Break':
                column = add_column(df)

            # input
            if df.fieldtype not in ('Section Break', 'Column Break',
                                    'Page Break'):
                if not page:
                    page = add_page()
                    section, column = None, None
                if not section:
                    section = add_section()
                    column = None
                if column == None:
                    column = add_column()
                column.append(df)

        return layout

    def get_parents(self, context):
        parents = None

        if context.is_list and not context.parents:
            parents = [{"title": _("My Account"), "name": "me"}]
        elif context.parents:
            parents = context.parents

        return parents

    def set_web_form_module(self):
        '''Get custom web form module if exists'''
        if self.is_standard:
            self.web_form_module = get_doc_module(self.module, self.doctype,
                                                  self.name)
        else:
            self.web_form_module = None

    def validate_mandatory(self, doc):
        '''Validate mandatory web form fields'''
        missing = []
        for f in self.web_form_fields:
            if f.reqd and doc.get(f.fieldname) in (None, [], ''):
                missing.append(f)

        if missing:
            frappe.throw(
                _('Mandatory Information missing:') + '<br><br>' +
                '<br>'.join([
                    '{0} ({1})'.format(d.label, d.fieldtype) for d in missing
                ]))
Example #34
0
File: api.py Project: frappe/iff
def invoice_paid():
    # https://razorpay.com/docs/api/recurring-payments/webhooks/
    data = frappe.request.get_data(as_text=True)
    try:
        verify_signature(data)
    except Exception as e:
        log = frappe.log_error(e, "Webhook Verification Error")
        return {"status": "Failed", "reason": e}

    if isinstance(data, six.string_types):
        data = json.loads(data)
    data = frappe._dict(data)

    payment = frappe._dict(data.payload.get("payment", {}).get("entity", {}))

    if not payment.method == "emandate":
        return

    controller = frappe.get_doc("Razorpay Settings")
    controller.init_client()
    client = controller.client

    today = getdate()

    member = frappe.db.exists("Member", {"customer_id": payment.customer_id})
    token_data = client.token.fetch(payment.customer_id, payment.token_id)

    if not member:
        max_amount = token_data.get("max_amount") / 100
        plan = frappe.db.exists("Membership Type", {"amount": max_amount})
        if plan:
            plan_id = frappe.db.get_value("Membership Type", plan,
                                          "razorpay_plan_id")
            member = create_member(payment.customer_id, plan_id)

    if member:
        member = frappe.get_doc("Member", member)

        membership = frappe.new_doc("Membership")
        membership.update({
            "member":
            member.name,
            "membership_status":
            "New",
            "membership_type":
            member.membership_type,
            "currency":
            "INR",
            "paid":
            1,
            "payment_id":
            payment.id,
            "from_date":
            today,
            "to_date":
            add_months(today, 1),
            "amount":
            frappe.db.get_value("Membership Type", member.membership_type,
                                "amount")
        })
        membership.insert(ignore_permissions=True)

        # Update membership values
        member.subscription_activated = 1
        member.e_mandate = 1
        member.razorpay_token = payment.token_id
        status = token_data.get("recurring_details").get("status")
        if status == "confirmed":
            member.token_status = "Confirmed"
        if status == "rejected":
            member.token_status = "Rejected"

        member.membership_expiry_date = add_months(today, 1)
        member.save(ignore_permissions=True)

        settings = frappe.get_doc("Non Profit Settings")
        if settings.allow_invoicing and settings.automate_membership_invoicing:
            membership.generate_invoice(with_payment_entry=settings.
                                        automate_membership_payment_entries,
                                        save=True)
def initialize_gle_map(gl_entries):
    gle_map = frappe._dict()
    for gle in gl_entries:
        gle_map.setdefault(gle.account,
                           _dict(totals=get_totals_dict(), entries=[]))
    return gle_map
Example #36
0
class Tournament(WebsiteGenerator):
    website = frappe._dict(template="templates/generators/tournament.html")

    def validate(self):
        self.route = "tournament/" + self.name
Example #37
0
def get_items_for_material_requests(doc, ignore_existing_ordered_qty=None):
    if isinstance(doc, string_types):
        doc = frappe._dict(json.loads(doc))

    doc['mr_items'] = []
    po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
    company = doc.get('company')
    warehouse = doc.get('for_warehouse')

    if not ignore_existing_ordered_qty:
        ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty')

    so_item_details = frappe._dict()
    for data in po_items:
        planned_qty = data.get('required_qty') or data.get('planned_qty')
        ignore_existing_ordered_qty = data.get(
            'ignore_existing_ordered_qty') or ignore_existing_ordered_qty

        item_details = {}
        if data.get("bom") or data.get("bom_no"):
            if data.get('required_qty'):
                bom_no = data.get('bom')
                include_non_stock_items = 1
                include_subcontracted_items = 1 if data.get(
                    'include_exploded_items') else 0
            else:
                bom_no = data.get('bom_no')
                include_subcontracted_items = doc.get(
                    'include_subcontracted_items')
                include_non_stock_items = doc.get('include_non_stock_items')

            if not planned_qty:
                frappe.throw(
                    _("For row {0}: Enter Planned Qty").format(
                        data.get('idx')))

            if bom_no:
                if data.get('include_exploded_items'
                            ) and include_subcontracted_items and not doc.get(
                                "include_sub_assembly_with_exploded_item"):
                    # fetch exploded items from BOM
                    item_details = get_exploded_items(
                        item_details,
                        company,
                        bom_no,
                        include_non_stock_items,
                        planned_qty=planned_qty,
                        sales_order=data.get("sales_order"))
                elif data.get('include_exploded_items'
                              ) and include_subcontracted_items and doc.get(
                                  "include_sub_assembly_with_exploded_item"):
                    # fetch exploded items with sub assembly item from BOM
                    item_details = get_exploded_items_with_subassembly(
                        item_details,
                        company,
                        bom_no,
                        include_non_stock_items,
                        planned_qty=planned_qty,
                        sales_order=data.get("sales_order"))
                else:
                    item_details = get_subitems(
                        doc,
                        data,
                        item_details,
                        bom_no,
                        company,
                        include_non_stock_items,
                        include_subcontracted_items,
                        1,
                        planned_qty=planned_qty,
                        sales_order=data.get("sales_order"))
        elif data.get('item_code'):
            item_master = frappe.get_doc('Item', data['item_code']).as_dict()
            purchase_uom = item_master.purchase_uom or item_master.stock_uom
            conversion_factor = 0
            for d in item_master.get("uoms"):
                if d.uom == purchase_uom:
                    conversion_factor = d.conversion_factor

            item_details[item_master.name] = frappe._dict({
                'item_name':
                item_master.item_name,
                'default_bom':
                doc.bom,
                'purchase_uom':
                purchase_uom,
                'default_warehouse':
                item_master.default_warehouse,
                'min_order_qty':
                item_master.min_order_qty,
                'default_material_request_type':
                item_master.default_material_request_type,
                'qty':
                planned_qty or 1,
                'is_sub_contracted':
                item_master.is_subcontracted_item,
                'item_code':
                item_master.name,
                'description':
                item_master.description,
                'stock_uom':
                item_master.stock_uom,
                'conversion_factor':
                conversion_factor,
                'sales_order':
                data.get("sales_order")
            })

        sales_order = doc.get("sales_order")

        for item_code, details in iteritems(item_details):
            so_item_details.setdefault(sales_order, frappe._dict())
            if item_code in so_item_details.get(sales_order, {}):
                so_item_details[sales_order][item_code][
                    'qty'] = so_item_details[sales_order][item_code].get(
                        "qty", 0) + flt(details.qty)
            else:
                so_item_details[sales_order][item_code] = details

    mr_items = []
    for sales_order, item_code in iteritems(so_item_details):
        item_dict = so_item_details[sales_order]
        for details in item_dict.values():
            bin_dict = get_bin_details(details, doc.company, warehouse)
            bin_dict = bin_dict[0] if bin_dict else {}

            if details and details.qty > 0:
                items = get_material_request_items(
                    details, sales_order, company, ignore_existing_ordered_qty,
                    warehouse, bin_dict)
                if items:
                    mr_items.append(items)

    if not mr_items:
        frappe.msgprint(
            _("""As raw materials projected quantity is more than required quantity, there is no need to create material request.
			Still if you want to make material request, kindly enable <b>Ignore Existing Projected Quantity</b> checkbox"""
              ))

    return mr_items
Example #38
0
def get_basic_details(args, item, overwrite_warehouse=True):
    """
	:param args: {
			"item_code": "",
			"warehouse": None,
			"customer": "",
			"conversion_rate": 1.0,
			"selling_price_list": None,
			"price_list_currency": None,
			"price_list_uom_dependant": None,
			"plc_conversion_rate": 1.0,
			"doctype": "",
			"name": "",
			"supplier": None,
			"transaction_date": None,
			"conversion_rate": 1.0,
			"buying_price_list": None,
			"is_subcontracted": "Yes" / "No",
			"ignore_pricing_rule": 0/1
			"project": "",
			barcode: "",
			serial_no: "",
			currency: "",
			update_stock: "",
			price_list: "",
			company: "",
			order_type: "",
			is_pos: "",
			project: "",
			qty: "",
			stock_qty: "",
			conversion_factor: ""
		}
	:param item: `item_code` of Item object
	:return: frappe._dict
	"""

    if not item:
        item = frappe.get_doc("Item", args.get("item_code"))

    if item.variant_of:
        item.update_template_tables()

    item_defaults = get_item_defaults(item.name, args.company)
    item_group_defaults = get_item_group_defaults(item.name, args.company)
    brand_defaults = get_brand_defaults(item.name, args.company)

    defaults = frappe._dict({
        'item_defaults': item_defaults,
        'item_group_defaults': item_group_defaults,
        'brand_defaults': brand_defaults
    })

    warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults)

    if args.get('doctype') == "Material Request" and not args.get(
            'material_request_type'):
        args['material_request_type'] = frappe.db.get_value(
            'Material Request',
            args.get('name'),
            'material_request_type',
            cache=True)

    expense_account = None

    if args.get('doctype') == 'Purchase Invoice' and item.is_fixed_asset:
        from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
        expense_account = get_asset_category_account(
            fieldname="fixed_asset_account",
            item=args.item_code,
            company=args.company)

    #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
    if not args.get('uom'):
        if args.get('doctype') in sales_doctypes:
            args.uom = item.sales_uom if item.sales_uom else item.stock_uom
        elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \
         (args.get('doctype') == 'Material Request' and args.get('material_request_type') == 'Purchase'):
            args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom
        else:
            args.uom = item.stock_uom

    out = frappe._dict({
        "item_code":
        item.name,
        "item_name":
        item.item_name,
        "description":
        cstr(item.description).strip(),
        "image":
        cstr(item.image).strip(),
        "warehouse":
        warehouse,
        "income_account":
        get_default_income_account(args, item_defaults, item_group_defaults,
                                   brand_defaults),
        "expense_account":
        expense_account or get_default_expense_account(
            args, item_defaults, item_group_defaults, brand_defaults),
        "cost_center":
        get_default_cost_center(args, item_defaults, item_group_defaults,
                                brand_defaults),
        'has_serial_no':
        item.has_serial_no,
        'has_batch_no':
        item.has_batch_no,
        "batch_no":
        args.get("batch_no"),
        "uom":
        args.uom,
        "min_order_qty":
        flt(item.min_order_qty) if args.doctype == "Material Request" else "",
        "qty":
        flt(args.qty) or 1.0,
        "stock_qty":
        flt(args.qty) or 1.0,
        "price_list_rate":
        0.0,
        "base_price_list_rate":
        0.0,
        "rate":
        0.0,
        "base_rate":
        0.0,
        "amount":
        0.0,
        "base_amount":
        0.0,
        "net_rate":
        0.0,
        "net_amount":
        0.0,
        "discount_percentage":
        0.0,
        "supplier":
        get_default_supplier(args, item_defaults, item_group_defaults,
                             brand_defaults),
        "update_stock":
        args.get("update_stock")
        if args.get('doctype') in ['Sales Invoice', 'Purchase Invoice'] else 0,
        "delivered_by_supplier":
        item.delivered_by_supplier
        if args.get("doctype") in ["Sales Order", "Sales Invoice"] else 0,
        "is_fixed_asset":
        item.is_fixed_asset,
        "weight_per_unit":
        item.weight_per_unit,
        "weight_uom":
        item.weight_uom,
        "last_purchase_rate":
        item.last_purchase_rate
        if args.get("doctype") in ["Purchase Order"] else 0,
        "transaction_date":
        args.get("transaction_date")
    })

    if item.get("enable_deferred_revenue") or item.get(
            "enable_deferred_expense"):
        out.update(calculate_service_end_date(args, item))

    # calculate conversion factor
    if item.stock_uom == args.uom:
        out.conversion_factor = 1.0
    else:
        out.conversion_factor = args.conversion_factor or \
         get_conversion_factor(item.name, args.uom).get("conversion_factor")

    args.conversion_factor = out.conversion_factor
    out.stock_qty = out.qty * out.conversion_factor

    # calculate last purchase rate
    if args.get('doctype') in purchase_doctypes:
        from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate
        out.last_purchase_rate = item_last_purchase_rate(
            args.name, args.conversion_rate, item.name, out.conversion_factor)

    # if default specified in item is for another company, fetch from company
    for d in [["Account", "income_account", "default_income_account"],
              ["Account", "expense_account", "default_expense_account"],
              ["Cost Center", "cost_center", "cost_center"],
              ["Warehouse", "warehouse", ""]]:
        if not out[d[1]]:
            out[d[1]] = frappe.get_cached_value('Company', args.company,
                                                d[2]) if d[2] else None

    for fieldname in ("item_name", "item_group", "barcodes", "brand",
                      "stock_uom"):
        out[fieldname] = item.get(fieldname)

    if args.get("manufacturer"):
        part_no = get_item_manufacturer_part_no(args.get("item_code"),
                                                args.get("manufacturer"))
        if part_no:
            out["manufacturer_part_no"] = part_no
        else:
            out["manufacturer_part_no"] = None
            out["manufacturer"] = None
    else:
        data = frappe.get_value(
            "Item",
            item.name,
            ["default_item_manufacturer", "default_manufacturer_part_no"],
            as_dict=1)

        if data:
            out.update({
                "manufacturer":
                data.default_item_manufacturer,
                "manufacturer_part_no":
                data.default_manufacturer_part_no
            })

    child_doctype = args.doctype + ' Item'
    meta = frappe.get_meta(child_doctype)
    if meta.get_field("barcode"):
        update_barcode_value(out)

    return out
Example #39
0
def run_onload(doc):
	doc.set("__onload", frappe._dict())
	doc.run_method("onload")
Example #40
0
def _get_party_details(party=None,
                       account=None,
                       party_type="Customer",
                       company=None,
                       posting_date=None,
                       bill_date=None,
                       price_list=None,
                       currency=None,
                       doctype=None,
                       ignore_permissions=False,
                       fetch_payment_terms_template=True,
                       party_address=None,
                       company_address=None,
                       shipping_address=None,
                       pos_profile=None):

    party_details = frappe._dict(
        set_account_and_due_date(party, account, party_type, company,
                                 posting_date, bill_date, doctype))
    party = party_details[party_type.lower()]

    if not ignore_permissions and not frappe.has_permission(
            party_type, "read", party):
        frappe.throw(
            _("Not permitted for {0}").format(party), frappe.PermissionError)

    party = frappe.get_doc(party_type, party)
    currency = party.default_currency if party.get(
        "default_currency") else get_company_currency(company)

    party_address, shipping_address = set_address_details(
        party_details, party, party_type, doctype, company, party_address,
        company_address, shipping_address)
    set_contact_details(party_details, party, party_type)
    set_other_values(party_details, party, party_type)
    set_price_list(party_details, party, party_type, price_list, pos_profile)

    party_details["tax_category"] = get_address_tax_category(
        party.get("tax_category"), party_address,
        shipping_address if party_type != "Supplier" else party_address)

    if not party_details.get("taxes_and_charges"):
        party_details["taxes_and_charges"] = set_taxes(
            party.name,
            party_type,
            posting_date,
            company,
            customer_group=party_details.customer_group,
            supplier_group=party_details.supplier_group,
            tax_category=party_details.tax_category,
            billing_address=party_address,
            shipping_address=shipping_address)

    if fetch_payment_terms_template:
        party_details["payment_terms_template"] = get_pyt_term_template(
            party.name, party_type, company)

    if not party_details.get("currency"):
        party_details["currency"] = currency

    # sales team
    if party_type == "Customer":
        party_details["sales_team"] = [{
            "sales_person":
            d.sales_person,
            "allocated_percentage":
            d.allocated_percentage or None
        } for d in party.get("sales_team")]

    # supplier tax withholding category
    if party_type == "Supplier" and party:
        party_details["supplier_tds"] = frappe.get_value(
            party_type, party.name, "tax_withholding_category")

    return party_details
Example #41
0
    def update_raw_materials_supplied(self, item, raw_material_table):
        bom_items = self.get_items_from_bom(item.item_code, item.bom)
        raw_materials_cost = 0
        items = list(set([d.item_code for d in bom_items]))
        item_wh = frappe._dict(
            frappe.db.sql(
                """select item_code, default_warehouse
			from `tabItem` where name in ({0})""".format(", ".join(["%s"] *
                                                          len(items))), items))

        for bom_item in bom_items:
            if self.doctype == "Purchase Order":
                reserve_warehouse = bom_item.source_warehouse or item_wh.get(
                    bom_item.item_code)
                if frappe.db.get_value("Warehouse", reserve_warehouse,
                                       "company") != self.company:
                    reserve_warehouse = None

            # check if exists
            exists = 0
            for d in self.get(raw_material_table):
                if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \
                 and d.reference_name == item.name:
                    rm, exists = d, 1
                    break

            if not exists:
                rm = self.append(raw_material_table, {})

            required_qty = flt(
                flt(bom_item.qty_consumed_per_unit) * flt(item.qty) *
                flt(item.conversion_factor), rm.precision("required_qty"))
            rm.reference_name = item.name
            rm.bom_detail_no = bom_item.name
            rm.main_item_code = item.item_code
            rm.rm_item_code = bom_item.item_code
            rm.stock_uom = bom_item.stock_uom
            rm.required_qty = required_qty
            if self.doctype == "Purchase Order" and not rm.reserve_warehouse:
                rm.reserve_warehouse = reserve_warehouse

            rm.conversion_factor = item.conversion_factor

            if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
                rm.consumed_qty = required_qty
                rm.description = bom_item.description
                if item.batch_no and not rm.batch_no:
                    rm.batch_no = item.batch_no

            # get raw materials rate
            if self.doctype == "Purchase Receipt":
                from erpnext.stock.utils import get_incoming_rate
                rm.rate = get_incoming_rate({
                    "item_code": bom_item.item_code,
                    "warehouse": self.supplier_warehouse,
                    "posting_date": self.posting_date,
                    "posting_time": self.posting_time,
                    "qty": -1 * required_qty,
                    "serial_no": rm.serial_no
                })
                if not rm.rate:
                    rm.rate = get_valuation_rate(
                        bom_item.item_code,
                        self.supplier_warehouse,
                        self.doctype,
                        self.name,
                        currency=self.company_currency,
                        company=self.company)
            else:
                rm.rate = bom_item.rate

            rm.amount = required_qty * flt(rm.rate)
            raw_materials_cost += flt(rm.amount)

        if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
            item.rm_supp_cost = raw_materials_cost
Example #42
0
    def migrate_doctype(self,
                        doctype,
                        filters=None,
                        update=None,
                        verbose=1,
                        exclude=None,
                        preprocess=None):
        """Migrate records from another doctype"""
        meta = frappe.get_meta(doctype)
        tables = {}
        for df in meta.get_table_fields():
            if verbose: print("getting " + df.options)
            tables[df.fieldname] = self.get_list(df.options,
                                                 limit_page_length=999999)

        # get links
        if verbose: print("getting " + doctype)
        docs = self.get_list(doctype,
                             limit_page_length=999999,
                             filters=filters)

        # build - attach children to parents
        if tables:
            docs = [frappe._dict(doc) for doc in docs]
            docs_map = dict((doc.name, doc) for doc in docs)

            for fieldname in tables:
                for child in tables[fieldname]:
                    child = frappe._dict(child)
                    if child.parent in docs_map:
                        docs_map[child.parent].setdefault(fieldname,
                                                          []).append(child)

        if verbose: print("inserting " + doctype)
        for doc in docs:
            if exclude and doc["name"] in exclude:
                continue

            if preprocess:
                preprocess(doc)

            if not doc.get("owner"):
                doc["owner"] = "Administrator"

            if doctype != "User" and not frappe.db.exists(
                    "User", doc.get("owner")):
                frappe.get_doc({
                    "doctype": "User",
                    "email": doc.get("owner"),
                    "first_name": doc.get("owner").split("@")[0]
                }).insert()

            if update:
                doc.update(update)

            doc["doctype"] = doctype
            new_doc = frappe.get_doc(doc)
            new_doc.insert()

            if not meta.istable:
                if doctype != "Communication":
                    self.migrate_doctype(
                        "Communication", {
                            "reference_doctype": doctype,
                            "reference_name": doc["name"]
                        },
                        update={"reference_name": new_doc.name},
                        verbose=0)

                if doctype != "File":
                    self.migrate_doctype(
                        "File", {
                            "attached_to_doctype": doctype,
                            "attached_to_name": doc["name"]
                        },
                        update={"attached_to_name": new_doc.name},
                        verbose=0)
Example #43
0
def get_rootwise_opening_balances(filters, report_type):
    additional_conditions = ""
    if not filters.show_unclosed_fy_pl_balances:
        additional_conditions = " and posting_date >= %(year_start_date)s" \
         if report_type == "Profit and Loss" else ""

    if not flt(filters.with_period_closing_entry):
        additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"

    if filters.cost_center:
        lft, rgt = frappe.db.get_value('Cost Center', filters.cost_center,
                                       ['lft', 'rgt'])
        additional_conditions += """ and cost_center in (select name from `tabCost Center`
			where lft >= %s and rgt <= %s)""" % (lft, rgt)

    if filters.finance_book:
        fb_conditions = " and finance_book = %(finance_book)s"
        if filters.include_default_book_entries:
            fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s))"

        additional_conditions += fb_conditions

    accounting_dimensions = get_accounting_dimensions()

    query_filters = {
        "company":
        filters.company,
        "from_date":
        filters.from_date,
        "report_type":
        report_type,
        "year_start_date":
        filters.year_start_date,
        "finance_book":
        filters.finance_book,
        "company_fb":
        frappe.db.get_value("Company", filters.company, 'default_finance_book')
    }

    if accounting_dimensions:
        for dimension in accounting_dimensions:
            additional_conditions += """ and {0} in (%({0})s) """.format(
                dimension)

            query_filters.update({dimension: filters.get(dimension)})

    gle = frappe.db.sql("""
		select
			account, sum(debit) as opening_debit, sum(credit) as opening_credit
		from `tabGL Entry`
		where
			company=%(company)s
			{additional_conditions}
			and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
			and account in (select name from `tabAccount` where report_type=%(report_type)s)
		group by account""".format(additional_conditions=additional_conditions),
                        query_filters,
                        as_dict=True)

    opening = frappe._dict()
    for d in gle:
        opening.setdefault(d.account, d)

    return opening
Example #44
0
def make_purchase_receipt(**args):
    if not frappe.db.exists('Location', 'Test Location'):
        frappe.get_doc({
            'doctype': 'Location',
            'location_name': 'Test Location'
        }).insert()

    frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
    pr = frappe.new_doc("Purchase Receipt")
    args = frappe._dict(args)
    pr.posting_date = args.posting_date or today()
    if args.posting_time:
        pr.posting_time = args.posting_time
    if args.posting_date or args.posting_time:
        pr.set_posting_time = 1
    pr.company = args.company or "_Test Company"
    pr.supplier = args.supplier or "_Test Supplier"
    pr.is_subcontracted = args.is_subcontracted or "No"
    pr.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
    pr.currency = args.currency or "INR"
    pr.is_return = args.is_return
    pr.return_against = args.return_against
    qty = args.qty or 5
    received_qty = args.received_qty or qty
    rejected_qty = args.rejected_qty or flt(received_qty) - flt(qty)

    item_code = args.item or args.item_code or "_Test Item"
    uom = args.uom or frappe.db.get_value("Item", item_code,
                                          "stock_uom") or "_Test UOM"
    pr.append(
        "items", {
            "item_code":
            item_code,
            "warehouse":
            args.warehouse or "_Test Warehouse - _TC",
            "qty":
            qty,
            "received_qty":
            received_qty,
            "rejected_qty":
            rejected_qty,
            "rejected_warehouse":
            args.rejected_warehouse or "_Test Rejected Warehouse - _TC"
            if rejected_qty != 0 else "",
            "rate":
            args.rate if args.rate != None else 50,
            "conversion_factor":
            args.conversion_factor or 1.0,
            "serial_no":
            args.serial_no,
            "stock_uom":
            args.stock_uom or "_Test UOM",
            "uom":
            uom,
            "cost_center":
            args.cost_center
            or frappe.get_cached_value('Company', pr.company, 'cost_center'),
            "asset_location":
            args.location or "Test Location"
        })

    if args.get_multiple_items:
        pr.items = []
        for item in get_items(warehouse=args.warehouse,
                              cost_center=args.cost_center
                              or frappe.get_cached_value(
                                  'Company', pr.company, 'cost_center')):
            pr.append("items", item)

    if args.get_taxes_and_charges:
        for tax in get_taxes():
            pr.append("taxes", tax)

    if not args.do_not_save:
        pr.insert()
        if not args.do_not_submit:
            pr.submit()
    return pr
Example #45
0
# 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 erpnext.setup.page.setup_wizard.test_setup_data import args
from erpnext.setup.page.setup_wizard.setup_wizard import setup_account

if __name__ == "__main__":
    frappe.connect()
    frappe.local.form_dict = frappe._dict(args)
    setup_account()
Example #46
0
def get_outstanding_invoices(party_type, party, account, condition=None):
    outstanding_invoices = []
    precision = frappe.get_precision("Sales Invoice", "outstanding_amount")

    if party_type in ("Customer", "Student"):
        dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
        payment_dr_or_cr = "payment_gl_entry.credit_in_account_currency - payment_gl_entry.debit_in_account_currency"
    else:
        dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
        payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency"

    invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice'
    invoice_list = frappe.db.sql("""
		select
			voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount,
			(
				select ifnull(sum({payment_dr_or_cr}), 0)
				from `tabGL Entry` payment_gl_entry
				where payment_gl_entry.against_voucher_type = invoice_gl_entry.voucher_type
					and if(invoice_gl_entry.voucher_type='Journal Entry',
						payment_gl_entry.against_voucher = invoice_gl_entry.voucher_no,
						payment_gl_entry.against_voucher = invoice_gl_entry.against_voucher)
					and payment_gl_entry.party_type = invoice_gl_entry.party_type
					and payment_gl_entry.party = invoice_gl_entry.party
					and payment_gl_entry.account = invoice_gl_entry.account
					and {payment_dr_or_cr} > 0
			) as payment_amount
		from
			`tabGL Entry` invoice_gl_entry
		where
			party_type = %(party_type)s and party = %(party)s
			and account = %(account)s and {dr_or_cr} > 0
			{condition}
			and ((voucher_type = 'Journal Entry'
					and (against_voucher = '' or against_voucher is null))
				or (voucher_type not in ('Journal Entry', 'Payment Entry')))
		group by voucher_type, voucher_no
		having (invoice_amount - payment_amount) > 0.005
		order by posting_date, name""".format(dr_or_cr=dr_or_cr,
                                        invoice=invoice,
                                        payment_dr_or_cr=payment_dr_or_cr,
                                        condition=condition or ""), {
                                            "party_type": party_type,
                                            "party": party,
                                            "account": account,
                                        },
                                 as_dict=True)

    for d in invoice_list:
        due_date = frappe.db.get_value(
            d.voucher_type, d.voucher_no,
            "posting_date" if party_type == "Employee" else "due_date")

        outstanding_invoices.append(
            frappe._dict({
                'voucher_no':
                d.voucher_no,
                'voucher_type':
                d.voucher_type,
                'posting_date':
                d.posting_date,
                'invoice_amount':
                flt(d.invoice_amount),
                'payment_amount':
                flt(d.payment_amount),
                'outstanding_amount':
                flt(d.invoice_amount - d.payment_amount, precision),
                'due_date':
                due_date
            }))

    outstanding_invoices = sorted(
        outstanding_invoices,
        key=lambda k: k['due_date'] or getdate(nowdate()))

    return outstanding_invoices
Example #47
0
def get_ewb_data(dt, dn):
    if dt != 'Sales Invoice':
        frappe.throw(
            _('e-Way Bill JSON can only be generated from Sales Invoice'))

    dn = dn.split(',')

    ewaybills = []
    for doc_name in dn:
        doc = frappe.get_doc(dt, doc_name)

        validate_sales_invoice(doc)

        data = frappe._dict({
            "transporterId": "",
            "TotNonAdvolVal": 0,
        })

        data.userGstin = data.fromGstin = doc.company_gstin
        data.supplyType = 'O'

        if doc.gst_category in ['Registered Regular', 'SEZ']:
            data.subSupplyType = 1
        elif doc.gst_category in ['Overseas', 'Deemed Export']:
            data.subSupplyType = 3
        else:
            frappe.throw(
                _('Unsupported GST Category for e-Way Bill JSON generation'))

        data.docType = 'INV'
        data.docDate = frappe.utils.formatdate(doc.posting_date, 'dd/mm/yyyy')

        company_address = frappe.get_doc('Address', doc.company_address)
        billing_address = frappe.get_doc('Address', doc.customer_address)

        shipping_address = frappe.get_doc('Address', doc.shipping_address_name)

        data = get_address_details(data, doc, company_address, billing_address)

        data.itemList = []
        data.totalValue = doc.total

        data = get_item_list(data, doc)

        disable_rounded = frappe.db.get_single_value('Global Defaults',
                                                     'disable_rounded_total')
        data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total

        data = get_transport_details(data, doc)

        fields = {
            "/. -": {
                'docNo': doc.name,
                'fromTrdName': doc.company,
                'toTrdName': doc.customer_name,
                'transDocNo': doc.lr_no,
            },
            "@#/,&. -": {
                'fromAddr1': company_address.address_line1,
                'fromAddr2': company_address.address_line2,
                'fromPlace': company_address.city,
                'toAddr1': shipping_address.address_line1,
                'toAddr2': shipping_address.address_line2,
                'toPlace': shipping_address.city,
                'transporterName': doc.transporter_name
            }
        }

        for allowed_chars, field_map in fields.items():
            for key, value in field_map.items():
                if not value:
                    data[key] = ''
                else:
                    data[key] = re.sub(r'[^\w' + allowed_chars + ']', '',
                                       value)

        ewaybills.append(data)

    data = {'version': '1.0.1118', 'billLists': ewaybills}

    return data
Example #48
0
def get_period_list(from_fiscal_year,
                    to_fiscal_year,
                    periodicity,
                    accumulated_values=False,
                    company=None,
                    reset_period_on_fy_change=True):
    """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label}
		Periodicity can be (Yearly, Quarterly, Monthly)"""

    fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year)
    validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year)

    # start with first day, so as to avoid year to_dates like 2-April if ever they occur]
    year_start_date = getdate(fiscal_year.year_start_date)
    year_end_date = getdate(fiscal_year.year_end_date)

    months_to_add = {
        "Yearly": 12,
        "Half-Yearly": 6,
        "Quarterly": 3,
        "Monthly": 1
    }[periodicity]

    period_list = []

    start_date = year_start_date
    months = get_months(year_start_date, year_end_date)

    for i in range(months // months_to_add):
        period = frappe._dict({"from_date": start_date})

        to_date = add_months(start_date, months_to_add)
        start_date = to_date

        if to_date == get_first_day(to_date):
            # if to_date is the first day, get the last day of previous month
            to_date = add_days(to_date, -1)

        if to_date <= year_end_date:
            # the normal case
            period.to_date = to_date
        else:
            # if a fiscal year ends before a 12 month period
            period.to_date = year_end_date

        period.to_date_fiscal_year = get_fiscal_year(period.to_date,
                                                     company=company)[0]
        period.from_date_fiscal_year_start_date = get_fiscal_year(
            period.from_date, company=company)[1]

        period_list.append(period)

        if period.to_date == year_end_date:
            break

    # common processing
    for opts in period_list:
        key = opts["to_date"].strftime("%b_%Y").lower()
        if periodicity == "Monthly" and not accumulated_values:
            label = formatdate(opts["to_date"], "MMM YYYY")
        else:
            if not accumulated_values:
                label = get_label(periodicity, opts["from_date"],
                                  opts["to_date"])
            else:
                if reset_period_on_fy_change:
                    label = get_label(periodicity,
                                      opts.from_date_fiscal_year_start_date,
                                      opts["to_date"])
                else:
                    label = get_label(periodicity, period_list[0].from_date,
                                      opts["to_date"])

        opts.update({
            "key": key.replace(" ", "_").replace("-", "_"),
            "label": label,
            "year_start_date": year_start_date,
            "year_end_date": year_end_date
        })

    return period_list
Example #49
0
def get_invoice_summary(items, taxes):
	summary_data = frappe._dict()
	for tax in taxes:
		#Include only VAT charges.
		if tax.charge_type == "Actual":
			continue

		#Charges to appear as items in the e-invoice.
		if tax.charge_type in ["On Previous Row Total", "On Previous Row Amount"]:
			reference_row = next((row for row in taxes if row.idx == int(tax.row_id or 0)), None)
			if reference_row:
				items.append(
					frappe._dict(
						idx=len(items)+1,
						item_code=reference_row.description,
						item_name=reference_row.description,
						description=reference_row.description,
						rate=reference_row.tax_amount,
						qty=1.0,
						amount=reference_row.tax_amount,
						stock_uom=frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos"),
						tax_rate=tax.rate,
						tax_amount=(reference_row.tax_amount * tax.rate) / 100,
						net_amount=reference_row.tax_amount,
						taxable_amount=reference_row.tax_amount,
						item_tax_rate={tax.account_head: tax.rate},
						charges=True
					)
				)

		#Check item tax rates if tax rate is zero.
		if tax.rate == 0:
			for item in items:
				item_tax_rate = item.item_tax_rate
				if isinstance(item.item_tax_rate, string_types):
					item_tax_rate = json.loads(item.item_tax_rate)

				if item_tax_rate and tax.account_head in item_tax_rate:
					key = cstr(item_tax_rate[tax.account_head])
					if key not in summary_data:
						summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0,
							"tax_exemption_reason": "", "tax_exemption_law": ""})

					summary_data[key]["tax_amount"] += item.tax_amount
					summary_data[key]["taxable_amount"] += item.net_amount
					if key == "0.0":
						summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason
						summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law

			if summary_data.get("0.0") and tax.charge_type in ["On Previous Row Total",
				"On Previous Row Amount"]:
				summary_data[key]["taxable_amount"] = tax.total

			if summary_data == {}: #Implies that Zero VAT has not been set on any item.
				summary_data.setdefault("0.0", {"tax_amount": 0.0, "taxable_amount": tax.total,
					"tax_exemption_reason": tax.tax_exemption_reason, "tax_exemption_law": tax.tax_exemption_law})

		else:
			item_wise_tax_detail = json.loads(tax.item_wise_tax_detail)
			for rate_item in [tax_item for tax_item in item_wise_tax_detail.items() if tax_item[1][0] == tax.rate]:
				key = cstr(tax.rate)
				if not summary_data.get(key): summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0})
				summary_data[key]["tax_amount"] += rate_item[1][1]
				summary_data[key]["taxable_amount"] += sum([item.net_amount for item in items if item.item_code == rate_item[0]])

			for item in items:
				key = cstr(tax.rate)
				if item.get("charges"):
					if not summary_data.get(key): summary_data.setdefault(key, {"taxable_amount": 0.0})
					summary_data[key]["taxable_amount"] += item.taxable_amount

	return summary_data
Example #50
0
def sync_events_from_google_calendar(g_calendar, method=None):
	"""
	Syncs Events from Google Calendar in Framework Calendar.
	Google Calendar returns nextSyncToken when all the events in Google Calendar are fetched.
	nextSyncToken is returned at the very last page
	https://developers.google.com/calendar/v3/sync
	"""
	google_calendar, account = get_google_calendar_object(g_calendar)

	if not account.pull_from_google_calendar:
		return

	sync_token = account.get_password(fieldname="next_sync_token", raise_exception=False) or None
	events = frappe._dict()
	results = []
	while True:
		try:
			# API Response listed at EOF
			events = (
				google_calendar.events()
				.list(
					calendarId=account.google_calendar_id,
					maxResults=2000,
					pageToken=events.get("nextPageToken"),
					singleEvents=False,
					showDeleted=True,
					syncToken=sync_token,
				)
				.execute()
			)
		except HttpError as err:
			msg = _("Google Calendar - Could not fetch event from Google Calendar, error code {0}.").format(
				err.resp.status
			)

			if err.resp.status == 410:
				set_encrypted_password("Google Calendar", account.name, "", "next_sync_token")
				frappe.db.commit()
				msg += " " + _("Sync token was invalid and has been resetted, Retry syncing.")
				frappe.msgprint(msg, title="Invalid Sync Token", indicator="blue")
			else:
				frappe.throw(msg)

		for event in events.get("items", []):
			results.append(event)

		if not events.get("nextPageToken"):
			if events.get("nextSyncToken"):
				account.next_sync_token = events.get("nextSyncToken")
				account.save()
			break

	for idx, event in enumerate(results):
		frappe.publish_realtime(
			"import_google_calendar", dict(progress=idx + 1, total=len(results)), user=frappe.session.user
		)

		# If Google Calendar Event if confirmed, then create an Event
		if event.get("status") == "confirmed":
			recurrence = None
			if event.get("recurrence"):
				try:
					recurrence = event.get("recurrence")[0]
				except IndexError:
					pass

			if not frappe.db.exists("Event", {"google_calendar_event_id": event.get("id")}):
				insert_event_to_calendar(account, event, recurrence)
			else:
				update_event_in_calendar(account, event, recurrence)
		elif event.get("status") == "cancelled":
			# If any synced Google Calendar Event is cancelled, then close the Event
			frappe.db.set_value(
				"Event",
				{
					"google_calendar_id": account.google_calendar_id,
					"google_calendar_event_id": event.get("id"),
				},
				"status",
				"Closed",
			)
			frappe.get_doc(
				{
					"doctype": "Comment",
					"comment_type": "Info",
					"reference_doctype": "Event",
					"reference_name": frappe.db.get_value(
						"Event",
						{
							"google_calendar_id": account.google_calendar_id,
							"google_calendar_event_id": event.get("id"),
						},
						"name",
					),
					"content": " - Event deleted from Google Calendar.",
				}
			).insert(ignore_permissions=True)
		else:
			pass

	if not results:
		return _("No Google Calendar Event to sync.")
	elif len(results) == 1:
		return _("1 Google Calendar Event synced.")
	else:
		return _("{0} Google Calendar Events synced.").format(len(results))
Example #51
0
def get_party_and_account_balance(company, date, paid_from=None, paid_to=None, ptype=None, pty=None, cost_center=None):
	return frappe._dict({
		"party_balance": get_balance_on(party_type=ptype, party=pty, cost_center=cost_center),
		"paid_from_account_balance": get_balance_on(paid_from, date, cost_center=cost_center),
		"paid_to_account_balance": get_balance_on(paid_to, date=date, cost_center=cost_center)
	})
    def get_incoming_server(self, in_receive=False, email_sync_rule="UNSEEN"):
        """Returns logged in POP3/IMAP connection object."""
        if frappe.cache().get_value("workers:no-internet") == True:
            return None

        args = frappe._dict({
            "email_account":
            self.name,
            "host":
            self.email_server,
            "use_ssl":
            self.use_ssl,
            "username":
            getattr(self, "login_id", None) or self.email_id,
            "use_imap":
            self.use_imap,
            "email_sync_rule":
            email_sync_rule,
            "uid_validity":
            self.uidvalidity,
            "incoming_port":
            get_port(self),
            "initial_sync_count":
            self.initial_sync_count or 100
        })

        if self.password:
            args.password = self.get_password()

        if not args.get("host"):
            frappe.throw(_("{0} is required").format("Email Server"))

        email_server = EmailServer(frappe._dict(args))
        try:
            email_server.connect()
        except (error_proto, imaplib.IMAP4.error) as e:
            e = cstr(e)
            message = e.lower().replace(" ", "")
            if in_receive and any(
                    map(
                        lambda t: t in message,
                        [
                            'authenticationfailed',
                            'loginviayourwebbrowser',  #abbreviated to work with both failure and failed
                            'loginfailed',
                            'err[auth]',
                            'errtemporaryerror'
                        ])):  #temporary error to deal with godaddy
                # if called via self.receive and it leads to authentication error, disable incoming
                # and send email to system manager
                self.handle_incoming_connect_error(description=_(
                    'Authentication failed while receiving emails from Email Account {0}. Message from server: {1}'
                    .format(self.name, e)))

                return None

            else:
                frappe.throw(e)

        except socket.error:
            if in_receive:
                # timeout while connecting, see receive.py connect method
                description = frappe.message_log.pop(
                ) if frappe.message_log else "Socket Error"
                if test_internet():
                    self.db_set("no_failed", self.no_failed + 1)
                    if self.no_failed > 2:
                        self.handle_incoming_connect_error(
                            description=description)
                else:
                    frappe.cache().set_value("workers:no-internet", True)
                return None

            else:
                raise
        if not in_receive:
            if self.use_imap:
                email_server.imap.logout()
        # reset failed attempts count
        self.set_failed_attempts_count(0)

        return email_server
Example #53
0
def generate_otp(medium="sms", medium_id=None, sms_hash=None, purpose="login"):
    """
  Generate and Send an OTP through the medium specified. we generate new pin on each call, ignoring previous pins
  :param medium: 'email' or 'sms'
  :param medium_id: The actual email/mobile_no
  :param sms_hash: The hash that should be appended to OTP SMS
  :param purpose: Specify an optional purpose (login, pwd_reset) to make a custom context
  """

    if medium not in ("sms", "email"):
        frappe.throw("medium can only be 'sms' or 'email'")

    if not medium_id:
        frappe.throw(f"medium_id is mandatory")

    user = get_linked_user(id_type=medium, id=medium_id)

    # generate a pin
    otp = frappe.safe_decode(str(get_otp()))

    # saving the hashed pin, not the pin as is
    hashed_pin = passlibctx.hash(otp)
    expires_in_sec = (cint(
        frappe.db.get_value("System Settings", None,
                            "verification_otp_validity")) or 15) * 60

    frappe.cache().set_value(get_otp_redis_key(medium, medium_id, purpose),
                             hashed_pin,
                             expires_in_sec=expires_in_sec)

    status = "success"
    if medium == "sms":
        msg = u"Your verification OTP is: " + otp
        if sms_hash:
            msg = msg + u". " + sms_hash
        sms = send_sms([medium_id], msg, success_msg=False)
        status = "fail"
        # Since SMS Settings might remove or add '+' character, we will check against the last 5 digits
        if sms and isinstance(
                sms, list) and len(sms) == 1 and medium_id[-5:] in sms[0]:
            status = "success"
    elif medium == "email":
        email_otp_template = frappe.db.get_value("System Settings", None,
                                                 "email_otp_template")
        if not email_otp_template:
            frappe.throw("Please set Email OTP Template in System Settings")
        email_otp_template = frappe.get_doc("Email Template",
                                            email_otp_template)
        render_params = frappe._dict(
            otp=otp,
            email=medium_id,
            user=frappe.get_doc("User", user) if user else frappe._dict())
        status = "fail"
        try:
            frappe.sendmail(
                recipients=[medium_id],
                subject=frappe.render_template(email_otp_template.subject,
                                               render_params),
                message=frappe.render_template(email_otp_template.response,
                                               render_params))
            status = "success"
        except frappe.OutgoingEmailError:
            status = "fail"

    return frappe._dict({"status": status, medium: medium_id})
Example #54
0
class Item(WebsiteGenerator):
	website = frappe._dict(
		page_title_field = "item_name",
		condition_field = "show_in_website",
		template = "templates/generators/item.html",
		no_cache = 1
	)

	def onload(self):
		super(Item, self).onload()
		self.set_onload('sle_exists', self.check_if_sle_exists())
		if self.is_fixed_asset:
			asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1)
			self.set_onload("asset_exists", True if asset else False)

	def autoname(self):
		if frappe.db.get_default("item_naming_by")=="Naming Series":
			if self.variant_of:
				if not self.item_code:
					template_item_name = frappe.db.get_value("Item", self.variant_of, "item_name")
					self.item_code = make_variant_item_code(self.variant_of, template_item_name, self)
			else:
				from frappe.model.naming import make_autoname
				self.item_code = make_autoname(self.naming_series+'.#####')
		elif not self.item_code:
			msgprint(_("Item Code is mandatory because Item is not automatically numbered"), raise_exception=1)

		self.item_code = strip(self.item_code)
		self.name = self.item_code

	def before_insert(self):
		if not self.description:
			self.description = self.item_name

		self.publish_in_hub = 1

	def after_insert(self):
		'''set opening stock and item price'''
		if self.standard_rate:
			self.add_price()

		if self.opening_stock:
			self.set_opening_stock()

	def validate(self):
		super(Item, self).validate()

		if not self.item_name:
			self.item_name = self.item_code

		if not self.description:
			self.description = self.item_name

		self.validate_uom()
		self.add_default_uom_in_conversion_factor_table()
		self.validate_conversion_factor()
		self.validate_item_type()
		self.check_for_active_boms()
		self.fill_customer_code()
		self.check_item_tax()
		self.validate_barcode()
		self.cant_change()
		self.validate_warehouse_for_reorder()
		self.update_item_desc()
		self.synced_with_hub = 0

		self.validate_has_variants()
		self.validate_attributes()
		self.validate_variant_attributes()
		self.validate_website_image()
		self.make_thumbnail()
		self.validate_fixed_asset()

		if not self.get("__islocal"):
			self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
			self.old_website_item_groups = frappe.db.sql_list("""select item_group
				from `tabWebsite Item Group`
				where parentfield='website_item_groups' and parenttype='Item' and parent=%s""", self.name)

	def on_update(self):
		invalidate_cache_for_item(self)
		self.validate_name_with_item_group()
		self.update_item_price()
		self.update_template_item()

	def add_price(self, price_list=None):
		'''Add a new price'''
		if not price_list:
			price_list = (frappe.db.get_single_value('Selling Settings', 'selling_price_list')
				or frappe.db.get_value('Price List', _('Standard Selling')))
		if price_list:
			item_price = frappe.get_doc({
				"doctype": "Item Price",
				"price_list": price_list,
				"item_code": self.name,
				"currency": erpnext.get_default_currency(),
				"price_list_rate": self.standard_rate
			})
			item_price.insert()

	def set_opening_stock(self):
		'''set opening stock'''
		if not self.is_stock_item or self.has_serial_no or self.has_batch_no:
			return

		if not self.valuation_rate and self.standard_rate:
			self.valuation_rate = self.standard_rate

		if not self.valuation_rate:
			frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered"))

		from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry

		# default warehouse, or Stores
		default_warehouse = (frappe.db.get_single_value('Stock Settings', 'default_warehouse')
			or frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')}))

		if default_warehouse:
			stock_entry = make_stock_entry(item_code=self.name, target=default_warehouse,
				qty=self.opening_stock, rate=self.valuation_rate)

			stock_entry.add_comment("Comment", _("Opening Stock"))

	def make_route(self):
		if not self.route:
			return cstr(frappe.db.get_value('Item Group', self.item_group,
				'route')) + '/' + self.scrub(self.item_name + '-' + random_string(5))

	def get_parents(self, context):
		item_group, route = frappe.db.get_value('Item Group', self.item_group, ['name', 'route'])
		context.parents = [{'name': route, 'label': item_group}]

	def validate_website_image(self):
		"""Validate if the website image is a public file"""
		auto_set_website_image = False
		if not self.website_image and self.image:
			auto_set_website_image = True
			self.website_image = self.image

		if not self.website_image:
			return

		# find if website image url exists as public
		file_doc = frappe.get_all("File", filters={
			"file_url": self.website_image
		}, fields=["name", "is_private"], order_by="is_private asc", limit_page_length=1)


		if file_doc:
			file_doc = file_doc[0]

		if not file_doc:
			if not auto_set_website_image:
				frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found")
					.format(self.website_image, self.name))

			self.website_image = None

		elif file_doc.is_private:
			if not auto_set_website_image:
				frappe.msgprint(_("Website Image should be a public file or website URL"))

			self.website_image = None

	def make_thumbnail(self):
		"""Make a thumbnail of `website_image`"""
		import requests.exceptions

		if not self.is_new() and self.website_image != frappe.db.get_value(self.doctype, self.name, "website_image"):
			self.thumbnail = None

		if self.website_image and not self.thumbnail:
			file_doc = None

			try:
				file_doc = frappe.get_doc("File", {
					"file_url": self.website_image,
					"attached_to_doctype": "Item",
					"attached_to_name": self.name
				})
			except frappe.DoesNotExistError:
				pass
				# cleanup
				frappe.local.message_log.pop()

			except requests.exceptions.HTTPError:
				frappe.msgprint(_("Warning: Invalid attachment {0}").format(self.website_image))
				self.website_image = None

			except requests.exceptions.SSLError:
				frappe.msgprint(_("Warning: Invalid SSL certificate on attachment {0}").format(self.website_image))
				self.website_image = None

			# for CSV import
			if self.website_image and not file_doc:
				try:
					file_doc = frappe.get_doc({
						"doctype": "File",
						"file_url": self.website_image,
						"attached_to_doctype": "Item",
						"attached_to_name": self.name
					}).insert()

				except IOError:
					self.website_image = None

			if file_doc:
				if not file_doc.thumbnail_url:
					file_doc.make_thumbnail()

				self.thumbnail = file_doc.thumbnail_url

	def validate_fixed_asset(self):
		if self.is_fixed_asset:
			if self.is_stock_item:
				frappe.throw(_("Fixed Asset Item must be a non-stock item."))

			if not self.asset_category:
				frappe.throw(_("Asset Category is mandatory for Fixed Asset item"))

	def get_context(self, context):
		context.show_search=True
		context.search_link = '/product_search'

		context.parent_groups = get_parent_item_groups(self.item_group) + \
			[{"name": self.name}]

		self.set_variant_context(context)
		self.set_attribute_context(context)
		self.set_disabled_attributes(context)

		context.parents = self.get_parents(context)

		return context

	def set_variant_context(self, context):
		if self.has_variants:
			context.no_cache = True

			# load variants
			# also used in set_attribute_context
			context.variants = frappe.get_all("Item",
				filters={"variant_of": self.name, "show_variant_in_website": 1},
				order_by="name asc")

			variant = frappe.form_dict.variant
			if not variant and context.variants:
				# the case when the item is opened for the first time from its list
				variant = context.variants[0]

			if variant:
				context.variant = frappe.get_doc("Item", variant)

				for fieldname in ("website_image", "web_long_description", "description",
					"website_specifications"):
					if context.variant.get(fieldname):
						value = context.variant.get(fieldname)
						if isinstance(value, list):
							value = [d.as_dict() for d in value]

						context[fieldname] = value

		if self.slideshow:
			if context.variant and context.variant.slideshow:
				context.update(get_slideshow(context.variant))
			else:
				context.update(get_slideshow(self))

	def set_attribute_context(self, context):
		if self.has_variants:
			attribute_values_available = {}
			context.attribute_values = {}
			context.selected_attributes = {}

			# load attributes
			for v in context.variants:
				v.attributes = frappe.get_all("Item Variant Attribute",
					fields=["attribute", "attribute_value"], filters={"parent": v.name})

				for attr in v.attributes:
					values = attribute_values_available.setdefault(attr.attribute, [])
					if attr.attribute_value not in values:
						values.append(attr.attribute_value)

					if v.name==context.variant.name:
						context.selected_attributes[attr.attribute] = attr.attribute_value

			# filter attributes, order based on attribute table
			for attr in self.attributes:
				values = context.attribute_values.setdefault(attr.attribute, [])

				if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")):
					for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt):
						values.append(val)

				else:
					# get list of values defined (for sequence)
					for attr_value in frappe.db.get_all("Item Attribute Value",
						fields=["attribute_value"], filters={"parent": attr.attribute}, order_by="idx asc"):

						if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []):
							values.append(attr_value.attribute_value)

			context.variant_info = json.dumps(context.variants)

	def set_disabled_attributes(self, context):
		"""Disable selection options of attribute combinations that do not result in a variant"""
		if not self.attributes or not self.has_variants:
			return

		context.disabled_attributes = {}
		attributes = [attr.attribute for attr in self.attributes]

		def find_variant(combination):
			for variant in context.variants:
				if len(variant.attributes) < len(attributes):
					continue

				if "combination" not in variant:
					ref_combination = []

					for attr in variant.attributes:
						idx = attributes.index(attr.attribute)
						ref_combination.insert(idx, attr.attribute_value)

					variant["combination"] = ref_combination

				if not (set(combination) - set(variant["combination"])):
					# check if the combination is a subset of a variant combination
					# eg. [Blue, 0.5] is a possible combination if exists [Blue, Large, 0.5]
					return True

		for i, attr in enumerate(self.attributes):
			if i==0:
				continue

			combination_source = []

			# loop through previous attributes
			for prev_attr in self.attributes[:i]:
				combination_source.append([context.selected_attributes.get(prev_attr.attribute)])

			combination_source.append(context.attribute_values[attr.attribute])

			for combination in itertools.product(*combination_source):
				if not find_variant(combination):
					context.disabled_attributes.setdefault(attr.attribute, []).append(combination[-1])

	def add_default_uom_in_conversion_factor_table(self):
		uom_conv_list = [d.uom for d in self.get("uoms")]
		if self.stock_uom not in uom_conv_list:
			ch = self.append('uoms', {})
			ch.uom = self.stock_uom
			ch.conversion_factor = 1

		to_remove = []
		for d in self.get("uoms"):
			if d.conversion_factor == 1 and d.uom != self.stock_uom:
				to_remove.append(d)

		[self.remove(d) for d in to_remove]

	def update_template_tables(self):
		template = frappe.get_doc("Item", self.variant_of)

		# add item taxes from template
		for d in template.get("taxes"):
			self.append("taxes", {"tax_type": d.tax_type, "tax_rate": d.tax_rate})

		# copy re-order table if empty
		if not self.get("reorder_levels"):
			for d in template.get("reorder_levels"):
				n = {}
				for k in ("warehouse", "warehouse_reorder_level",
					"warehouse_reorder_qty", "material_request_type"):
					n[k] = d.get(k)
				self.append("reorder_levels", n)

	def validate_conversion_factor(self):
		check_list = []
		for d in self.get('uoms'):
			if cstr(d.uom) in check_list:
				frappe.throw(_("Unit of Measure {0} has been entered more than once in Conversion Factor Table").format(d.uom))
			else:
				check_list.append(cstr(d.uom))

			if d.uom and cstr(d.uom) == cstr(self.stock_uom) and flt(d.conversion_factor) != 1:
				frappe.throw(_("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx))

	def validate_item_type(self):
		if self.has_serial_no == 1 and self.is_stock_item == 0:
			msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1)

		if self.has_serial_no == 0 and self.serial_no_series:
			self.serial_no_series = None


	def check_for_active_boms(self):
		if self.default_bom:
			bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
			if bom_item not in (self.name, self.variant_of):
				frappe.throw(_("Default BOM ({0}) must be active for this item or its template").format(bom_item))

	def fill_customer_code(self):
		""" Append all the customer codes and insert into "customer_code" field of item table """
		cust_code=[]
		for d in self.get('customer_items'):
			cust_code.append(d.ref_code)
		self.customer_code=','.join(cust_code)

	def check_item_tax(self):
		"""Check whether Tax Rate is not entered twice for same Tax Type"""
		check_list=[]
		for d in self.get('taxes'):
			if d.tax_type:
				account_type = frappe.db.get_value("Account", d.tax_type, "account_type")

				if account_type not in ['Tax', 'Chargeable', 'Income Account', 'Expense Account']:
					frappe.throw(_("Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable").format(d.idx))
				else:
					if d.tax_type in check_list:
						frappe.throw(_("{0} entered twice in Item Tax").format(d.tax_type))
					else:
						check_list.append(d.tax_type)

	def validate_barcode(self):
		if self.barcode:
			duplicate = frappe.db.sql("""select name from tabItem where barcode = %s
				and name != %s""", (self.barcode, self.name))
			if duplicate:
				frappe.throw(_("Barcode {0} already used in Item {1}").format(self.barcode, duplicate[0][0]))

	def cant_change(self):
		if not self.get("__islocal"):
			to_check = ("has_serial_no", "is_stock_item",
				"valuation_method", "has_batch_no", "is_fixed_asset")

			vals = frappe.db.get_value("Item", self.name, to_check, as_dict=True)
			if not vals.get('valuation_method') and self.get('valuation_method'):
				vals['valuation_method'] = frappe.db.get_single_value("Stock Settings", "valuation_method") or "FIFO"

			if vals:
				for key in to_check:
					if cstr(self.get(key)) != cstr(vals.get(key)):
						if not self.check_if_linked_document_exists(key):
							break # no linked document, allowed
						else:
							frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(key))))

			if vals and not self.is_fixed_asset and self.is_fixed_asset != vals.is_fixed_asset:
				asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1)
				if asset:
					frappe.throw(_('"Is Fixed Asset" cannot be unchecked, as Asset record exists against the item'))

	def check_if_linked_document_exists(self, key):
		linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "Purchase Receipt Item",
			"Purchase Invoice Item", "Stock Entry Detail", "Stock Reconciliation Item"]

		# For "Is Stock Item", following doctypes is important
		# because reserved_qty, ordered_qty and requested_qty updated from these doctypes
		if key == "is_stock_item":
			linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item"]

		for doctype in linked_doctypes:
			if frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}) or \
				frappe.db.get_value("Production Order",
					filters={"production_item": self.name, "docstatus": 1}):
				return True

		for d in self.get("reorder_levels"):
			if d.warehouse_reorder_level and not d.warehouse_reorder_qty:
				frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx))

	def validate_warehouse_for_reorder(self):
		warehouse = []
		for i in self.get("reorder_levels"):
			if i.get("warehouse") and i.get("warehouse") not in warehouse:
				warehouse += [i.get("warehouse")]
			else:
				frappe.throw(_("Row {0}: An Reorder entry already exists for this warehouse {1}")
					.format(i.idx, i.warehouse), DuplicateReorderRows)

	def check_if_sle_exists(self):
		sle = frappe.db.sql("""select name from `tabStock Ledger Entry`
			where item_code = %s""", self.name)
		return sle and 'exists' or 'not exists'

	def validate_name_with_item_group(self):
		# causes problem with tree build
		if frappe.db.exists("Item Group", self.name):
			frappe.throw(_("An Item Group exists with same name, please change the item name or rename the item group"))

	def update_item_price(self):
		frappe.db.sql("""update `tabItem Price` set item_name=%s,
			item_description=%s, modified=NOW() where item_code=%s""",
			(self.item_name, self.description, self.name))

	def on_trash(self):
		super(Item, self).on_trash()
		frappe.db.sql("""delete from tabBin where item_code=%s""", self.item_code)
		frappe.db.sql("delete from `tabItem Price` where item_code=%s", self.name)
		for variant_of in frappe.get_all("Item", filters={"variant_of": self.name}):
			frappe.delete_doc("Item", variant_of.name)

	def before_rename(self, old_name, new_name, merge=False):
		if self.item_name==old_name:
			self.item_name=new_name

		if merge:
			# Validate properties before merging
			if not frappe.db.exists("Item", new_name):
				frappe.throw(_("Item {0} does not exist").format(new_name))

			field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"]
			new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)]
			if new_properties != [cstr(self.get(fld)) for fld in field_list]:
				frappe.throw(_("To merge, following properties must be same for both items")
					+ ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))

	def after_rename(self, old_name, new_name, merge):
		if self.route:
			invalidate_cache_for_item(self)
			clear_cache(self.route)

		frappe.db.set_value("Item", new_name, "item_code", new_name)

		if merge:
			self.set_last_purchase_rate(new_name)
			self.recalculate_bin_qty(new_name)

		for dt in ("Sales Taxes and Charges", "Purchase Taxes and Charges"):
			for d in frappe.db.sql("""select name, item_wise_tax_detail from `tab{0}`
					where ifnull(item_wise_tax_detail, '') != ''""".format(dt), as_dict=1):

				item_wise_tax_detail = json.loads(d.item_wise_tax_detail)
				if old_name in item_wise_tax_detail:
					item_wise_tax_detail[new_name] = item_wise_tax_detail[old_name]
					item_wise_tax_detail.pop(old_name)

					frappe.db.set_value(dt, d.name, "item_wise_tax_detail",
						json.dumps(item_wise_tax_detail), update_modified=False)

	def set_last_purchase_rate(self, new_name):
		last_purchase_rate = get_last_purchase_details(new_name).get("base_rate", 0)
		frappe.db.set_value("Item", new_name, "last_purchase_rate", last_purchase_rate)

	def recalculate_bin_qty(self, new_name):
		from erpnext.stock.stock_balance import repost_stock
		frappe.db.auto_commit_on_many_writes = 1
		existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)

		repost_stock_for_warehouses = frappe.db.sql_list("""select distinct warehouse
			from tabBin where item_code=%s""", new_name)

		# Delete all existing bins to avoid duplicate bins for the same item and warehouse
		frappe.db.sql("delete from `tabBin` where item_code=%s", new_name)

		for warehouse in repost_stock_for_warehouses:
			repost_stock(new_name, warehouse)

		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
		frappe.db.auto_commit_on_many_writes = 0

	def copy_specification_from_item_group(self):
		self.set("website_specifications", [])
		if self.item_group:
			for label, desc in frappe.db.get_values("Item Website Specification",
				{"parent": self.item_group}, ["label", "description"]):
					row = self.append("website_specifications")
					row.label = label
					row.description = desc

	def update_item_desc(self):
		if frappe.db.get_value('BOM',self.name, 'description') != self.description:
			frappe.db.sql("""update `tabBOM` set description = %s where item = %s and docstatus < 2""",(self.description, self.name))
			frappe.db.sql("""update `tabBOM Item` set description = %s where
				item_code = %s and docstatus < 2""",(self.description, self.name))
			frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where
				item_code = %s and docstatus < 2""",(self.description, self.name))

	def update_template_item(self):
		"""Set Show in Website for Template Item if True for its Variant"""
		if self.variant_of and self.show_in_website:
			self.show_variant_in_website = 1
			self.show_in_website = 0

		if self.show_variant_in_website:
			# show template
			template_item = frappe.get_doc("Item", self.variant_of)

			if not template_item.show_in_website:
				template_item.show_in_website = 1
				template_item.flags.ignore_permissions = True
				template_item.save()

	def validate_has_variants(self):
		if not self.has_variants and frappe.db.get_value("Item", self.name, "has_variants"):
			if frappe.db.exists("Item", {"variant_of": self.name}):
				frappe.throw(_("Item has variants."))

	def validate_uom(self):
		if not self.get("__islocal"):
			check_stock_uom_with_bin(self.name, self.stock_uom)
		if self.has_variants:
			for d in frappe.db.get_all("Item", filters= {"variant_of": self.name}):
				check_stock_uom_with_bin(d.name, self.stock_uom)
		if self.variant_of:
			template_uom = frappe.db.get_value("Item", self.variant_of, "stock_uom")
			if template_uom != self.stock_uom:
				frappe.throw(_("Default Unit of Measure for Variant '{0}' must be same as in Template '{1}'")
					.format(self.stock_uom, template_uom))

	def validate_attributes(self):
		if (self.has_variants or self.variant_of) and self.variant_based_on=='Item Attribute':
			attributes = []
			if not self.attributes:
				frappe.throw(_("Attribute table is mandatory"))
			for d in self.attributes:
				if d.attribute in attributes:
					frappe.throw(_("Attribute {0} selected multiple times in Attributes Table".format(d.attribute)))
				else:
					attributes.append(d.attribute)

	def validate_variant_attributes(self):
		if self.variant_of and self.variant_based_on=='Item Attribute':
			args = {}
			for d in self.attributes:
				if not d.attribute_value:
					frappe.throw(_("Please specify Attribute Value for attribute {0}").format(d.attribute))
				args[d.attribute] = d.attribute_value

			variant = get_variant(self.variant_of, args, self.name)
			if variant:
				frappe.throw(_("Item variant {0} exists with same attributes")
					.format(variant), ItemVariantExistsError)

			validate_item_variant_attributes(self, args)
Example #55
0
def get_bootinfo():
    """build and return boot info"""
    frappe.set_user_lang(frappe.session.user)
    bootinfo = frappe._dict()
    hooks = frappe.get_hooks()
    doclist = []

    # user
    get_user(bootinfo)

    # system info
    bootinfo['sysdefaults'] = frappe.defaults.get_defaults()
    bootinfo['server_date'] = frappe.utils.nowdate()

    if frappe.session['user'] != 'Guest':
        bootinfo['user_info'] = get_fullnames()
        bootinfo['sid'] = frappe.session['sid']

    # home page
    bootinfo.modules = {}
    for app in frappe.get_installed_apps():
        try:
            bootinfo.modules.update(
                frappe.get_attr(app + ".config.desktop.get_data")() or {})
        except ImportError:
            pass
        except AttributeError:
            pass

    bootinfo.module_app = frappe.local.module_app
    bootinfo.hidden_modules = frappe.db.get_global("hidden_modules")
    bootinfo.doctype_icons = dict(
        frappe.db.sql("""select name, icon from
		tabDocType where ifnull(icon,'')!=''"""))
    bootinfo.single_types = frappe.db.sql_list(
        """select name from tabDocType where ifnull(issingle,0)=1""")
    add_home_page(bootinfo, doclist)
    bootinfo.page_info = get_allowed_pages()
    load_translations(bootinfo)
    add_timezone_info(bootinfo)
    load_conf_settings(bootinfo)
    load_print(bootinfo, doclist)
    doclist.extend(get_meta_bundle("Page"))

    # ipinfo
    if frappe.session['data'].get('ipinfo'):
        bootinfo['ipinfo'] = frappe.session['data']['ipinfo']

    # add docs
    bootinfo['docs'] = doclist

    for method in hooks.boot_session or []:
        frappe.get_attr(method)(bootinfo)

    if bootinfo.lang:
        bootinfo.lang = unicode(bootinfo.lang)
    bootinfo['versions'] = {k: v['version'] for k, v in get_versions().items()}

    bootinfo.error_report_email = frappe.get_hooks("error_report_email")
    bootinfo.default_background_image = "/assets/frappe/images/ui/into-the-dawn.jpg"
    bootinfo.calendars = sorted(frappe.get_hooks("calendars"))

    return bootinfo
Example #56
0
 def http_response(out):
     r = frappe._dict(status=out, medium=medium_id)
     return r
Example #57
0
    def update_stock_ledger(self):
        self.update_reserved_qty()

        sl_entries = []
        for d in self.get_item_list():
            if frappe.db.get_value("Item", d.item_code,
                                   "is_stock_item") == 1 and flt(d.qty):
                return_rate = 0
                if cint(self.is_return
                        ) and self.return_against and self.docstatus == 1:
                    return_rate = self.get_incoming_rate_for_sales_return(
                        d.item_code, d.warehouse, self.return_against)

                # On cancellation or if return entry submission, make stock ledger entry for
                # target warehouse first, to update serial no values properly

                if d.warehouse and (
                    (not cint(self.is_return) and self.docstatus == 1) or
                    (cint(self.is_return) and self.docstatus == 2)):
                    sl_entries.append(
                        self.get_sl_entries(
                            d, {
                                "actual_qty": -1 * flt(d.qty),
                                "incoming_rate": return_rate
                            }))

                if d.target_warehouse:
                    target_warehouse_sle = self.get_sl_entries(
                        d, {
                            "actual_qty": flt(d.qty),
                            "warehouse": d.target_warehouse
                        })

                    if self.docstatus == 1:
                        if not cint(self.is_return):
                            args = frappe._dict({
                                "item_code": d.item_code,
                                "warehouse": d.warehouse,
                                "posting_date": self.posting_date,
                                "posting_time": self.posting_time,
                                "qty": -1 * flt(d.qty),
                                "serial_no": d.serial_no
                            })
                            target_warehouse_sle.update(
                                {"incoming_rate": get_incoming_rate(args)})
                        else:
                            target_warehouse_sle.update(
                                {"outgoing_rate": return_rate})
                    sl_entries.append(target_warehouse_sle)

                if d.warehouse and (
                    (not cint(self.is_return) and self.docstatus == 2) or
                    (cint(self.is_return) and self.docstatus == 1)):
                    sl_entries.append(
                        self.get_sl_entries(
                            d, {
                                "actual_qty": -1 * flt(d.qty),
                                "incoming_rate": return_rate
                            }))

        self.make_sl_entries(sl_entries)
 def _get_debit_credit_dict(label):
     return _dict(account="'{0}'".format(label),
                  debit=0.0,
                  credit=0.0,
                  debit_in_account_currency=0.0,
                  credit_in_account_currency=0.0)
Example #59
0
def get_dashboard_info(party_type, party, loyalty_program=None):
    current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)

    doctype = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"

    companies = frappe.get_all(doctype,
                               filters={
                                   'docstatus': 1,
                                   party_type.lower(): party
                               },
                               distinct=1,
                               fields=['company'])

    company_wise_info = []

    company_wise_grand_total = frappe.get_all(
        doctype,
        filters={
            'docstatus':
            1,
            party_type.lower():
            party,
            'posting_date': ('between', [
                current_fiscal_year.year_start_date,
                current_fiscal_year.year_end_date
            ])
        },
        group_by="company",
        fields=[
            "company", "sum(grand_total) as grand_total",
            "sum(base_grand_total) as base_grand_total"
        ])

    loyalty_point_details = []

    if party_type == "Customer":
        loyalty_point_details = frappe._dict(
            frappe.get_all(
                "Loyalty Point Entry",
                filters={
                    'customer': party,
                    'expiry_date': ('>=', getdate()),
                },
                group_by="company",
                fields=["company", "sum(loyalty_points) as loyalty_points"],
                as_list=1))

    company_wise_billing_this_year = frappe._dict()

    for d in company_wise_grand_total:
        company_wise_billing_this_year.setdefault(
            d.company, {
                "grand_total": d.grand_total,
                "base_grand_total": d.base_grand_total
            })

    company_wise_total_unpaid = frappe._dict(
        frappe.db.sql(
            """
		select company, sum(debit_in_account_currency) - sum(credit_in_account_currency)
		from `tabGL Entry`
		where party_type = %s and party=%s
		group by company""", (party_type, party)))

    for d in companies:
        company_default_currency = frappe.db.get_value("Company", d.company,
                                                       'default_currency')
        party_account_currency = get_party_account_currency(
            party_type, party, d.company)

        if party_account_currency == company_default_currency:
            billing_this_year = flt(
                company_wise_billing_this_year.get(d.company,
                                                   {}).get("base_grand_total"))
        else:
            billing_this_year = flt(
                company_wise_billing_this_year.get(d.company,
                                                   {}).get("grand_total"))

        total_unpaid = flt(company_wise_total_unpaid.get(d.company))

        if loyalty_point_details:
            loyalty_points = loyalty_point_details.get(d.company)

        info = {}
        info["billing_this_year"] = flt(
            billing_this_year) if billing_this_year else 0
        info["currency"] = party_account_currency
        info["total_unpaid"] = flt(total_unpaid) if total_unpaid else 0
        info["company"] = d.company

        if party_type == "Customer" and loyalty_point_details:
            info["loyalty_points"] = loyalty_points

        if party_type == "Supplier":
            info["total_unpaid"] = -1 * info["total_unpaid"]

        company_wise_info.append(info)

    return company_wise_info
Example #60
0
    def update_against_document_in_jv(self):
        """
			Links invoice and advance voucher:
				1. cancel advance voucher
				2. split into multiple rows if partially adjusted, assign against voucher
				3. submit advance voucher
		"""

        if self.doctype == "Sales Invoice":
            party_type = "Customer"
            party = self.customer
            party_account = self.debit_to
            dr_or_cr = "credit_in_account_currency"
        else:
            party_type = "Supplier"
            party = self.supplier
            party_account = self.credit_to
            dr_or_cr = "debit_in_account_currency"

        lst = []
        for d in self.get('advances'):
            if flt(d.allocated_amount) > 0:
                args = frappe._dict({
                    'voucher_type':
                    d.reference_type,
                    'voucher_no':
                    d.reference_name,
                    'voucher_detail_no':
                    d.reference_row,
                    'against_voucher_type':
                    self.doctype,
                    'against_voucher':
                    self.name,
                    'account':
                    party_account,
                    'party_type':
                    party_type,
                    'party':
                    party,
                    'is_advance':
                    'Yes',
                    'dr_or_cr':
                    dr_or_cr,
                    'unadjusted_amount':
                    flt(d.advance_amount),
                    'allocated_amount':
                    flt(d.allocated_amount),
                    'exchange_rate':
                    (self.conversion_rate
                     if self.party_account_currency != self.company_currency
                     else 1),
                    'grand_total':
                    (self.base_grand_total if self.party_account_currency
                     == self.company_currency else self.grand_total),
                    'outstanding_amount':
                    self.outstanding_amount
                })
                lst.append(args)

        if lst:
            from erpnext.accounts.utils import reconcile_against_document
            reconcile_against_document(lst)