Fixed merge conflict
This commit is contained in:
		
						commit
						e21e59614f
					
				| @ -2,23 +2,30 @@ | ||||
| # License: GNU General Public License v3. See license.txt | ||||
| 
 | ||||
| from __future__ import unicode_literals | ||||
| import frappe, json | ||||
| from frappe import _ | ||||
| from frappe.utils import nowdate | ||||
| from erpnext.setup.utils import get_exchange_rate | ||||
| from frappe.core.doctype.communication.email import make | ||||
| from erpnext.stock.get_item_details import get_pos_profile | ||||
| 
 | ||||
| import json | ||||
| 
 | ||||
| import frappe | ||||
| from erpnext.accounts.party import get_party_account_currency | ||||
| from erpnext.controllers.accounts_controller import get_taxes_and_charges | ||||
| from erpnext.setup.utils import get_exchange_rate | ||||
| from erpnext.stock.get_item_details import get_pos_profile | ||||
| from frappe import _ | ||||
| from frappe.core.doctype.communication.email import make | ||||
| from frappe.utils import nowdate | ||||
| 
 | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def get_pos_data(): | ||||
| 	doc = frappe.new_doc('Sales Invoice') | ||||
| 	doc.is_pos = 1; | ||||
| 	doc.is_pos = 1 | ||||
| 	pos_profile = get_pos_profile(doc.company) or {} | ||||
| 	if not pos_profile: | ||||
| 		frappe.throw(_("POS Profile is required to use Point-of-Sale")) | ||||
| 	if not doc.company: doc.company = pos_profile.get('company') | ||||
| 
 | ||||
| 	if not doc.company: | ||||
| 		doc.company = pos_profile.get('company') | ||||
| 
 | ||||
| 	doc.update_stock = pos_profile.get('update_stock') | ||||
| 
 | ||||
| 	if pos_profile.get('name'): | ||||
| @ -30,18 +37,20 @@ def get_pos_data(): | ||||
| 	update_multi_mode_option(doc, pos_profile) | ||||
| 	default_print_format = pos_profile.get('print_format') or "Point of Sale" | ||||
| 	print_template = frappe.db.get_value('Print Format', default_print_format, 'html') | ||||
| 	items_list = get_items_list(pos_profile) | ||||
| 	customers = get_customers_list(pos_profile) | ||||
| 
 | ||||
| 	return { | ||||
| 		'doc': doc, | ||||
| 		'default_customer': pos_profile.get('customer'), | ||||
| 		'items': get_items_list(pos_profile), | ||||
| 		'items': items_list, | ||||
| 		'item_groups': get_item_groups(pos_profile), | ||||
| 		'customers': customers, | ||||
| 		'address': get_customers_address(customers), | ||||
| 		'contacts': get_contacts(customers), | ||||
| 		'serial_no_data': get_serial_no_data(pos_profile, doc.company), | ||||
| 		'batch_no_data': get_batch_no_data(), | ||||
| 		'barcode_data': get_barcode_data(items_list), | ||||
| 		'tax_data': get_item_tax_data(), | ||||
| 		'price_list_data': get_price_list_data(doc.selling_price_list), | ||||
| 		'bin_data': get_bin_data(pos_profile), | ||||
| @ -51,20 +60,23 @@ def get_pos_data(): | ||||
| 		'meta': get_meta() | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| def get_meta(): | ||||
| 	doctype_meta = { | ||||
| 		'customer': frappe.get_meta('Customer'), | ||||
| 		'invoice': frappe.get_meta('Sales Invoice') | ||||
| 	} | ||||
| 
 | ||||
| 	for row in frappe.get_all('DocField', fields = ['fieldname', 'options'], | ||||
| 		filters = {'parent': 'Sales Invoice', 'fieldtype': 'Table'}): | ||||
| 	for row in frappe.get_all('DocField', fields=['fieldname', 'options'], | ||||
|             filters={'parent': 'Sales Invoice', 'fieldtype': 'Table'}): | ||||
| 		doctype_meta[row.fieldname] = frappe.get_meta(row.options) | ||||
| 
 | ||||
| 	return doctype_meta | ||||
| 
 | ||||
| 
 | ||||
| def get_company_data(company): | ||||
| 	return frappe.get_all('Company', fields = ["*"], filters= {'name': company})[0] | ||||
| 	return frappe.get_all('Company', fields=["*"], filters={'name': company})[0] | ||||
| 
 | ||||
| 
 | ||||
| def update_pos_profile_data(doc, pos_profile, company_data): | ||||
| 	doc.campaign = pos_profile.get('campaign') | ||||
| @ -96,12 +108,14 @@ def update_pos_profile_data(doc, pos_profile, company_data): | ||||
| 	doc.terms = frappe.db.get_value('Terms and Conditions', pos_profile.get('tc_name'), 'terms') or doc.terms or '' | ||||
| 	doc.offline_pos_name = '' | ||||
| 
 | ||||
| 
 | ||||
| def get_root(table): | ||||
| 	root = frappe.db.sql(""" select name from `tab%(table)s` having | ||||
| 		min(lft)"""%{'table': table}, as_dict=1) | ||||
| 		min(lft)""" % {'table': table}, as_dict=1) | ||||
| 
 | ||||
| 	return root[0].name | ||||
| 
 | ||||
| 
 | ||||
| def update_multi_mode_option(doc, pos_profile): | ||||
| 	from frappe.model import default_fields | ||||
| 
 | ||||
| @ -123,15 +137,18 @@ def update_multi_mode_option(doc, pos_profile): | ||||
| 
 | ||||
| 		doc.append('payments', payment_mode) | ||||
| 
 | ||||
| 
 | ||||
| def get_mode_of_payment(doc): | ||||
| 	return frappe.db.sql(""" select mpa.default_account, mpa.parent, mp.type as type from `tabMode of Payment Account` mpa, | ||||
| 		 `tabMode of Payment` mp where mpa.parent = mp.name and mpa.company = %(company)s""", {'company': doc.company}, as_dict=1) | ||||
| 	return frappe.db.sql(""" select mpa.default_account, mpa.parent, mp.type as type from `tabMode of Payment Account` mpa, \ | ||||
| 			`tabMode of Payment` mp where mpa.parent = mp.name and mpa.company = %(company)s""", {'company': doc.company}, as_dict=1) | ||||
| 
 | ||||
| 
 | ||||
| def update_tax_table(doc): | ||||
| 	taxes = get_taxes_and_charges('Sales Taxes and Charges Template', doc.taxes_and_charges) | ||||
| 	for tax in taxes: | ||||
| 		doc.append('taxes', tax) | ||||
| 
 | ||||
| 
 | ||||
| def get_items_list(pos_profile): | ||||
| 	cond = "1=1" | ||||
| 	item_groups = [] | ||||
| @ -139,19 +156,20 @@ def get_items_list(pos_profile): | ||||
| 		# Get items based on the item groups defined in the POS profile | ||||
| 		for d in pos_profile.get('item_groups'): | ||||
| 			item_groups.extend([d.name for d in get_child_nodes('Item Group', d.item_group)]) | ||||
| 		cond = "item_group in (%s)"%(', '.join(['%s']*len(item_groups))) | ||||
| 		cond = "item_group in (%s)" % (', '.join(['%s'] * len(item_groups))) | ||||
| 
 | ||||
| 	return frappe.db.sql("""  | ||||
| 	return frappe.db.sql(""" | ||||
| 		select | ||||
| 			name, item_code, item_name, description, item_group, expense_account, has_batch_no, | ||||
| 			has_serial_no, expense_account, selling_cost_center, stock_uom, image,  | ||||
| 			default_warehouse, is_stock_item, barcode, brand | ||||
| 			has_serial_no, expense_account, selling_cost_center, stock_uom, image, | ||||
| 			default_warehouse, is_stock_item, brand | ||||
| 		from | ||||
| 			tabItem | ||||
| 		where | ||||
| 			disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond} | ||||
| 		""".format(cond=cond), tuple(item_groups), as_dict=1) | ||||
| 
 | ||||
| 
 | ||||
| def get_item_groups(pos_profile): | ||||
| 	item_group_dict = {} | ||||
| 	item_groups = frappe.db.sql("""Select name, | ||||
| @ -161,6 +179,7 @@ def get_item_groups(pos_profile): | ||||
| 		item_group_dict[data.name] = [data.lft, data.rgt] | ||||
| 	return item_group_dict | ||||
| 
 | ||||
| 
 | ||||
| def get_customers_list(pos_profile={}): | ||||
| 	cond = "1=1" | ||||
| 	customer_groups = [] | ||||
| @ -168,12 +187,13 @@ def get_customers_list(pos_profile={}): | ||||
| 		# Get customers based on the customer groups defined in the POS profile | ||||
| 		for d in pos_profile.get('customer_groups'): | ||||
| 			customer_groups.extend([d.name for d in get_child_nodes('Customer Group', d.customer_group)]) | ||||
| 		cond = "customer_group in (%s)"%(', '.join(['%s']*len(customer_groups))) | ||||
| 		cond = "customer_group in (%s)" % (', '.join(['%s'] * len(customer_groups))) | ||||
| 
 | ||||
| 	return frappe.db.sql(""" select name, customer_name, customer_group, | ||||
| 		territory, customer_pos_id from tabCustomer where disabled = 0 | ||||
| 		and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {} | ||||
| 
 | ||||
| 
 | ||||
| def get_customers_address(customers): | ||||
| 	customer_address = {} | ||||
| 	if isinstance(customers, basestring): | ||||
| @ -185,33 +205,37 @@ def get_customers_address(customers): | ||||
| 			(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s | ||||
| 			and parenttype = 'Address')""", data.name, as_dict=1) | ||||
| 		address_data = {} | ||||
| 		if address: address_data = address[0] | ||||
| 		if address: | ||||
| 			address_data = address[0] | ||||
| 
 | ||||
| 		address_data.update({'full_name': data.customer_name, 'customer_pos_id': data.customer_pos_id}) | ||||
| 		customer_address[data.name] = address_data | ||||
| 
 | ||||
| 	return customer_address | ||||
| 
 | ||||
| 
 | ||||
| def get_contacts(customers): | ||||
| 	customer_contact = {} | ||||
| 	if isinstance(customers, basestring): | ||||
| 		customers = [frappe._dict({'name': customers})] | ||||
| 
 | ||||
| 	for data in customers: | ||||
| 		contact = frappe.db.sql(""" select email_id, phone, mobile_no from `tabContact`  | ||||
| 		contact = frappe.db.sql(""" select email_id, phone, mobile_no from `tabContact` | ||||
| 			where is_primary_contact =1 and name in | ||||
| 			(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s | ||||
| 			and parenttype = 'Contact')""", data.name, as_dict=1) | ||||
| 		if contact:  | ||||
| 		if contact: | ||||
| 			customer_contact[data.name] = contact[0] | ||||
| 
 | ||||
| 	return customer_contact | ||||
| 
 | ||||
| 
 | ||||
| def get_child_nodes(group_type, root): | ||||
| 	lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"]) | ||||
| 	return frappe.db.sql(""" Select name, lft, rgt from `tab{tab}` where | ||||
| 			lft >= {lft} and rgt <= {rgt} order by lft""".format(tab=group_type, lft=lft, rgt=rgt), as_dict=1) | ||||
| 
 | ||||
| 
 | ||||
| def get_serial_no_data(pos_profile, company): | ||||
| 	# get itemwise serial no data | ||||
| 	# example {'Nokia Lumia 1020': {'SN0001': 'Pune'}} | ||||
| @ -232,6 +256,7 @@ def get_serial_no_data(pos_profile, company): | ||||
| 
 | ||||
| 	return itemwise_serial_no | ||||
| 
 | ||||
| 
 | ||||
| def get_batch_no_data(): | ||||
| 	# get itemwise batch no data | ||||
| 	# exmaple: {'LED-GRE': [Batch001, Batch002]} | ||||
| @ -248,6 +273,26 @@ def get_batch_no_data(): | ||||
| 
 | ||||
| 	return itemwise_batch | ||||
| 
 | ||||
| 
 | ||||
| def get_barcode_data(items_list): | ||||
| 	# get itemwise batch no data | ||||
| 	# exmaple: {'LED-GRE': [Batch001, Batch002]} | ||||
| 	# where LED-GRE is item code, SN0001 is serial no and Pune is warehouse | ||||
| 
 | ||||
| 	itemwise_barcode = {} | ||||
| 	for item in items_list: | ||||
| 		barcodes = frappe.db.sql(""" | ||||
| 		select barcode from `tabItem Barcode` where parent = '{0}' | ||||
| 		""".format(item.item_code), as_dict=1) | ||||
| 
 | ||||
| 		for barcode in barcodes: | ||||
| 			if item.item_code not in itemwise_barcode: | ||||
| 				itemwise_barcode.setdefault(item.item_code, []) | ||||
| 			itemwise_barcode[item.item_code].append(barcode) | ||||
| 
 | ||||
| 	return itemwise_barcode | ||||
| 
 | ||||
| 
 | ||||
| def get_item_tax_data(): | ||||
| 	# get default tax of an item | ||||
| 	# example: {'Consulting Services': {'Excise 12 - TS': '12.000'}} | ||||
| @ -262,17 +307,19 @@ def get_item_tax_data(): | ||||
| 
 | ||||
| 	return itemwise_tax | ||||
| 
 | ||||
| 
 | ||||
| def get_price_list_data(selling_price_list): | ||||
| 	itemwise_price_list = {} | ||||
| 	price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate, | ||||
| 		item_code from `tabItem Price` ip where price_list = %(price_list)s""", | ||||
| 		{'price_list': selling_price_list}, as_dict=1) | ||||
|         {'price_list': selling_price_list}, as_dict=1) | ||||
| 
 | ||||
| 	for item in price_lists: | ||||
| 		itemwise_price_list[item.item_code] = item.price_list_rate | ||||
| 
 | ||||
| 	return itemwise_price_list | ||||
| 
 | ||||
| 
 | ||||
| def get_bin_data(pos_profile): | ||||
| 	itemwise_bin_data = {} | ||||
| 	cond = "1=1" | ||||
| @ -289,6 +336,7 @@ def get_bin_data(pos_profile): | ||||
| 
 | ||||
| 	return itemwise_bin_data | ||||
| 
 | ||||
| 
 | ||||
| def get_pricing_rule_data(doc): | ||||
| 	pricing_rules = "" | ||||
| 	if doc.ignore_pricing_rule == 0: | ||||
| @ -297,9 +345,10 @@ def get_pricing_rule_data(doc): | ||||
| 						and ifnull(company, '') in (%(company)s, '') and disable = 0 and %(date)s | ||||
| 						between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') | ||||
| 						order by priority desc, name desc""", | ||||
| 						{'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1) | ||||
|                         {'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1) | ||||
| 	return pricing_rules | ||||
| 
 | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def make_invoice(doc_list={}, email_queue_list={}, customers_list={}): | ||||
| 	if isinstance(doc_list, basestring): | ||||
| @ -338,14 +387,15 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}): | ||||
| 		'synced_contacts': get_contacts(customers) | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| def validate_records(doc): | ||||
| 	validate_item(doc) | ||||
| 
 | ||||
| 
 | ||||
| def get_customer_id(doc, customer=None): | ||||
| 	cust_id = None | ||||
| 	if doc.get('customer_pos_id'): | ||||
| 		cust_id = frappe.db.get_value('Customer', | ||||
| 			{'customer_pos_id': doc.get('customer_pos_id')}, 'name') | ||||
| 		cust_id = frappe.db.get_value('Customer',{'customer_pos_id': doc.get('customer_pos_id')}, 'name') | ||||
| 
 | ||||
| 	if not cust_id: | ||||
| 		customer = customer or doc.get('customer') | ||||
| @ -356,6 +406,7 @@ def get_customer_id(doc, customer=None): | ||||
| 
 | ||||
| 	return cust_id | ||||
| 
 | ||||
| 
 | ||||
| def make_customer_and_address(customers): | ||||
| 	customers_list = [] | ||||
| 	for customer, data in customers.items(): | ||||
| @ -372,6 +423,7 @@ def make_customer_and_address(customers): | ||||
| 	frappe.db.commit() | ||||
| 	return customers_list | ||||
| 
 | ||||
| 
 | ||||
| def add_customer(data): | ||||
| 	customer_doc = frappe.new_doc('Customer') | ||||
| 	customer_doc.customer_name = data.get('full_name') or data.get('customer') | ||||
| @ -380,28 +432,29 @@ def add_customer(data): | ||||
| 	customer_doc.customer_group = get_customer_group(data) | ||||
| 	customer_doc.territory = get_territory(data) | ||||
| 	customer_doc.flags.ignore_mandatory = True | ||||
| 	customer_doc.save(ignore_permissions = True) | ||||
| 	customer_doc.save(ignore_permissions=True) | ||||
| 	frappe.db.commit() | ||||
| 	return customer_doc.name | ||||
| 
 | ||||
| 
 | ||||
| def get_territory(data): | ||||
| 	if data.get('territory'): | ||||
| 		return data.get('territory') | ||||
| 
 | ||||
| 	return frappe.db.get_single_value('Selling Settings', | ||||
| 		'territory') or _('All Territories') | ||||
| 	return frappe.db.get_single_value('Selling Settings','territory') or _('All Territories') | ||||
| 
 | ||||
| 
 | ||||
| def get_customer_group(data): | ||||
| 	if data.get('customer_group'): | ||||
| 		return data.get('customer_group') | ||||
| 
 | ||||
| 	return frappe.db.get_single_value('Selling Settings', | ||||
| 		'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name') | ||||
| 	return frappe.db.get_single_value('Selling Settings', 'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name') | ||||
| 
 | ||||
| def make_contact(args,customer): | ||||
| 
 | ||||
| def make_contact(args, customer): | ||||
| 	if args.get('email_id') or args.get('phone'): | ||||
| 		name = frappe.db.get_value('Dynamic Link', | ||||
| 			{'link_doctype': 'Customer', 'link_name': customer, 'parenttype': 'Contact'}, 'parent') | ||||
|             	{'link_doctype': 'Customer', 'link_name': customer, 'parenttype': 'Contact'}, 'parent') | ||||
| 
 | ||||
| 		args = { | ||||
| 			'first_name': args.get('full_name'), | ||||
| @ -416,16 +469,18 @@ def make_contact(args,customer): | ||||
| 		doc.update(args) | ||||
| 		doc.is_primary_contact = 1 | ||||
| 		if not name: | ||||
| 			doc.append('links',{ | ||||
| 			doc.append('links', { | ||||
| 				'link_doctype': 'Customer', | ||||
| 				'link_name': customer | ||||
| 			}) | ||||
| 		doc.flags.ignore_mandatory = True | ||||
| 		doc.save(ignore_permissions=True) | ||||
| 
 | ||||
| 
 | ||||
| def make_address(args, customer): | ||||
| 	if not args.get('address_line1'): return | ||||
| 	 | ||||
| 	if not args.get('address_line1'): | ||||
| 		return | ||||
| 
 | ||||
| 	name = args.get('name') | ||||
| 
 | ||||
| 	if not name: | ||||
| @ -437,7 +492,7 @@ def make_address(args, customer): | ||||
| 	else: | ||||
| 		address = frappe.new_doc('Address') | ||||
| 		address.country = frappe.db.get_value('Company', args.get('company'), 'country') | ||||
| 		address.append('links',{ | ||||
| 		address.append('links', { | ||||
| 			'link_doctype': 'Customer', | ||||
| 			'link_name': customer | ||||
| 		}) | ||||
| @ -446,7 +501,8 @@ def make_address(args, customer): | ||||
| 	address.is_shipping_address = 1 | ||||
| 	address.update(args) | ||||
| 	address.flags.ignore_mandatory = True | ||||
| 	address.save(ignore_permissions = True) | ||||
| 	address.save(ignore_permissions=True) | ||||
| 
 | ||||
| 
 | ||||
| def make_email_queue(email_queue): | ||||
| 	name_list = [] | ||||
| @ -455,15 +511,16 @@ def make_email_queue(email_queue): | ||||
| 		data = json.loads(data) | ||||
| 		sender = frappe.session.user | ||||
| 		print_format = "POS Invoice" | ||||
| 		attachments = [frappe.attach_print('Sales Invoice', name, print_format= print_format)] | ||||
| 		attachments = [frappe.attach_print('Sales Invoice', name, print_format=print_format)] | ||||
| 
 | ||||
| 		make(subject = data.get('subject'), content = data.get('content'), recipients = data.get('recipients'), | ||||
| 			sender=sender,attachments = attachments, send_email=True, | ||||
| 			doctype='Sales Invoice', name=name) | ||||
| 		make(subject=data.get('subject'), content=data.get('content'), recipients=data.get('recipients'), | ||||
|                     sender=sender, attachments=attachments, send_email=True, | ||||
|                     doctype='Sales Invoice', name=name) | ||||
| 		name_list.append(key) | ||||
| 
 | ||||
| 	return name_list | ||||
| 
 | ||||
| 
 | ||||
| def validate_item(doc): | ||||
| 	for item in doc.get('items'): | ||||
| 		if not frappe.db.exists('Item', item.get('item_code')): | ||||
| @ -486,13 +543,15 @@ def submit_invoice(si_doc, name, doc, name_list): | ||||
| 		frappe.db.commit() | ||||
| 		name_list.append(name) | ||||
| 	except Exception as e: | ||||
| 		if frappe.message_log: frappe.message_log.pop() | ||||
| 		if frappe.message_log: | ||||
| 			frappe.message_log.pop() | ||||
| 		frappe.db.rollback() | ||||
| 		frappe.log_error(frappe.get_traceback()) | ||||
| 		name_list = save_invoice(doc, name, name_list) | ||||
| 
 | ||||
| 	return name_list | ||||
| 
 | ||||
| 
 | ||||
| def save_invoice(doc, name, name_list): | ||||
| 	try: | ||||
| 		if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}): | ||||
|  | ||||
| @ -301,6 +301,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ | ||||
| 		this.customers = r.message.customers; | ||||
| 		this.serial_no_data = r.message.serial_no_data; | ||||
| 		this.batch_no_data = r.message.batch_no_data; | ||||
| 		this.barcode_data = r.message.barcode_data; | ||||
| 		this.tax_data = r.message.tax_data; | ||||
| 		this.contacts = r.message.contacts; | ||||
| 		this.address = r.message.address || {}; | ||||
| @ -415,7 +416,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ | ||||
| 		}); | ||||
| 
 | ||||
| 		this.serach_item.make_input(); | ||||
| 		 | ||||
| 
 | ||||
| 		this.serach_item.$input.on("keypress", function (event) { | ||||
| 
 | ||||
| 			clearTimeout(me.last_search_timeout); | ||||
| @ -423,7 +424,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ | ||||
| 				if((me.serach_item.$input.val() != "") || (event.which == 13)) { | ||||
| 					me.items = me.get_items(); | ||||
| 					me.make_item_list(); | ||||
| 				}				 | ||||
| 				} | ||||
| 			}, 400); | ||||
| 		}); | ||||
| 
 | ||||
| @ -1110,9 +1111,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ | ||||
| 						search_status = false; | ||||
| 						me.item_serial_no[item.item_code] = [me.serach_item.$input.val(), me.serial_no_data[item.item_code][me.serach_item.$input.val()]] | ||||
| 						return true | ||||
| 					} else if (item.barcode == me.serach_item.$input.val()) { | ||||
| 					} else if (in_list(me.barcode_data[item.item_code], me.serach_item.$input.val())) { | ||||
| 						search_status = false; | ||||
| 						return item.barcode == me.serach_item.$input.val(); | ||||
| 						return true; | ||||
| 					} else if (reg.test(item.item_code.toLowerCase()) || (item.description && reg.test(item.description.toLowerCase())) || | ||||
| 						reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase())) { | ||||
| 						return true | ||||
| @ -1526,8 +1527,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ | ||||
| 				me.print_document(html) | ||||
| 			}) | ||||
| 		} | ||||
| 		 | ||||
| 		if (this.frm.doc.docstatus == 1) {	 | ||||
| 
 | ||||
| 		if (this.frm.doc.docstatus == 1) { | ||||
| 			this.page.add_menu_item(__("Email"), function () { | ||||
| 				me.email_prompt() | ||||
| 			}) | ||||
|  | ||||
| @ -12,7 +12,7 @@ from erpnext.controllers.sales_and_purchase_return import validate_return | ||||
| from erpnext.accounts.party import get_party_account_currency, validate_party_frozen_disabled | ||||
| from erpnext.exceptions import InvalidCurrency | ||||
| 
 | ||||
| force_item_fields = ("item_group", "barcode", "brand", "stock_uom") | ||||
| force_item_fields = ("item_group", "brand", "stock_uom") | ||||
| 
 | ||||
| class AccountsController(TransactionBase): | ||||
| 	def __init__(self, *args, **kwargs): | ||||
|  | ||||
| @ -165,8 +165,8 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals | ||||
| 			and (tabItem.`{key}` LIKE %(txt)s | ||||
| 				or tabItem.item_group LIKE %(txt)s | ||||
| 				or tabItem.item_name LIKE %(txt)s | ||||
| 				or tabItem.barcode LIKE %(txt)s | ||||
| 				or tabItem.description LIKE %(txt)s) | ||||
|                 or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s) | ||||
| 			{fcond} {mcond} | ||||
| 		order by | ||||
| 			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), | ||||
|  | ||||
| @ -493,3 +493,4 @@ erpnext.patches.v10_0.workflow_leave_application #2018-01-24 | ||||
| erpnext.patches.v10_0.set_default_payment_terms_based_on_company | ||||
| erpnext.patches.v10_0.update_sales_order_link_to_purchase_order | ||||
| erpnext.patches.v10_0.added_extra_gst_custom_field_in_gstr2 | ||||
| erpnext.patches.v10_0.item_barcode_childtable_migrate | ||||
|  | ||||
							
								
								
									
										22
									
								
								erpnext/patches/v10_0/item_barcode_childtable_migrate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								erpnext/patches/v10_0/item_barcode_childtable_migrate.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| # Copyright (c) 2017, Frappe and Contributors | ||||
| # License: GNU General Public License v3. See license.txt | ||||
| 
 | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import frappe | ||||
| 
 | ||||
| 
 | ||||
| def execute(): | ||||
| 	items_barcode = frappe.db.sql("""SELECT name, barcode FROM tabItem | ||||
| 		WHERE barcode IS NOT NULL and barcode != ''""", as_dict=1) | ||||
| 
 | ||||
| 	frappe.reload_doc("stock", "doctype", "item") | ||||
| 	frappe.reload_doc("stock", "doctype", "item_barcode") | ||||
| 
 | ||||
| 	for item in items_barcode: | ||||
| 		doc = frappe.get_doc("Item", item.get("name")) | ||||
| 		if item.get("barcode"): | ||||
| 			doc.append("barcodes", {"barcode": item.get("barcode")}) | ||||
| 			doc.flags.ignore_validate = True | ||||
| 			doc.flags.ignore_mandatory = True | ||||
| 			doc.save() | ||||
| @ -29,7 +29,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p | ||||
| 				batch_no, item_code = batch_no_data | ||||
| 
 | ||||
| 		if not serial_no and not batch_no: | ||||
| 			barcode_data = frappe.db.get_value('Item', {'barcode': search_value}, ['name', 'barcode']) | ||||
| 			barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['parent', 'barcode']) | ||||
| 			if barcode_data: | ||||
| 				item_code, barcode = barcode_data | ||||
| 
 | ||||
|  | ||||
| @ -172,35 +172,6 @@ | ||||
|    "set_only_once": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fieldname": "barcode", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 0, | ||||
|    "ignore_user_permissions": 0, | ||||
|    "ignore_xss_filter": 0, | ||||
|    "in_filter": 0, | ||||
|    "in_global_search": 0, | ||||
|    "in_list_view": 0, | ||||
|    "in_standard_filter": 0, | ||||
|    "label": "Barcode", | ||||
|    "length": 0, | ||||
|    "no_copy": 1, | ||||
|    "permlevel": 0, | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_on_submit": 0, | ||||
| @ -701,6 +672,67 @@ | ||||
|    "set_only_once": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "sb_barcodes",  | ||||
|    "fieldtype": "Section Break",  | ||||
|    "hidden": 0,  | ||||
|    "ignore_user_permissions": 0,  | ||||
|    "ignore_xss_filter": 0,  | ||||
|    "in_filter": 0,  | ||||
|    "in_global_search": 0,  | ||||
|    "in_list_view": 0,  | ||||
|    "in_standard_filter": 0,  | ||||
|    "label": "Barcodes",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "barcodes",  | ||||
|    "fieldtype": "Table",  | ||||
|    "hidden": 0,  | ||||
|    "ignore_user_permissions": 0,  | ||||
|    "ignore_xss_filter": 0,  | ||||
|    "in_filter": 0,  | ||||
|    "in_global_search": 0,  | ||||
|    "in_list_view": 0,  | ||||
|    "in_standard_filter": 0,  | ||||
|    "label": "Barcodes",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "options": "Item Barcode",  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_on_submit": 0, | ||||
| @ -3484,7 +3516,7 @@ | ||||
|  "issingle": 0, | ||||
|  "istable": 0, | ||||
|  "max_attachments": 1, | ||||
|  "modified": "2018-01-24 20:42:23.303090", | ||||
|  "modified": "2018-02-12 15:42:23.303090", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Stock", | ||||
|  "name": "Item", | ||||
| @ -3661,4 +3693,4 @@ | ||||
|  "title_field": "item_name", | ||||
|  "track_changes": 1, | ||||
|  "track_seen": 0 | ||||
| } | ||||
| } | ||||
| @ -2,30 +2,38 @@ | ||||
| # License: GNU General Public License v3. See license.txt | ||||
| 
 | ||||
| from __future__ import unicode_literals | ||||
| import frappe | ||||
| import erpnext | ||||
| import json | ||||
| import itertools | ||||
| from frappe import msgprint, _ | ||||
| from frappe.utils import (cstr, flt, cint, getdate, now_datetime, formatdate, | ||||
| 	strip, get_timestamp, random_string) | ||||
| from frappe.utils.html_utils import clean_html | ||||
| from frappe.website.website_generator import WebsiteGenerator | ||||
| from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for, get_parent_item_groups | ||||
| from frappe.website.render import clear_cache | ||||
| from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow | ||||
| from erpnext.controllers.item_variant import (get_variant, copy_attributes_to_variant, | ||||
| 	make_variant_item_code, validate_item_variant_attributes, ItemVariantExistsError) | ||||
| 
 | ||||
| class DuplicateReorderRows(frappe.ValidationError): pass | ||||
| class StockExistsForTemplate(frappe.ValidationError): pass | ||||
| import itertools | ||||
| import json | ||||
| import erpnext | ||||
| import frappe | ||||
| from erpnext.controllers.item_variant import (ItemVariantExistsError, | ||||
|         copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes) | ||||
| from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for) | ||||
| from frappe import _, msgprint | ||||
| from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate, | ||||
|                           now_datetime, random_string, strip) | ||||
| from frappe.utils.html_utils import clean_html | ||||
| from frappe.website.doctype.website_slideshow.website_slideshow import \ | ||||
| 	get_slideshow | ||||
| from frappe.website.render import clear_cache | ||||
| from frappe.website.website_generator import WebsiteGenerator | ||||
| 
 | ||||
| 
 | ||||
| class DuplicateReorderRows(frappe.ValidationError): | ||||
| 	pass | ||||
| 
 | ||||
| 
 | ||||
| class StockExistsForTemplate(frappe.ValidationError): | ||||
| 	pass | ||||
| 
 | ||||
| 
 | ||||
| class Item(WebsiteGenerator): | ||||
| 	website = frappe._dict( | ||||
| 		page_title_field = "item_name", | ||||
| 		condition_field = "show_in_website", | ||||
| 		template = "templates/generators/item.html", | ||||
| 		no_cache = 1 | ||||
| 		page_title_field="item_name", | ||||
| 		condition_field="show_in_website", | ||||
| 		template="templates/generators/item.html", | ||||
| 		no_cache=1 | ||||
| 	) | ||||
| 
 | ||||
| 	def onload(self): | ||||
| @ -37,14 +45,14 @@ class Item(WebsiteGenerator): | ||||
| 			self.set_onload("asset_exists", True if asset else False) | ||||
| 
 | ||||
| 	def autoname(self): | ||||
| 		if frappe.db.get_default("item_naming_by")=="Naming Series": | ||||
| 		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+'.#####') | ||||
| 				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) | ||||
| 
 | ||||
| @ -102,8 +110,8 @@ class Item(WebsiteGenerator): | ||||
| 		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) | ||||
| 					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) | ||||
| @ -121,7 +129,7 @@ class Item(WebsiteGenerator): | ||||
| 		'''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'))) | ||||
|                     	or frappe.db.get_value('Price List', _('Standard Selling'))) | ||||
| 		if price_list: | ||||
| 			item_price = frappe.get_doc({ | ||||
| 				"doctype": "Item Price", | ||||
| @ -147,19 +155,19 @@ class Item(WebsiteGenerator): | ||||
| 
 | ||||
| 		# default warehouse, or Stores | ||||
| 		default_warehouse = (self.default_warehouse | ||||
| 			or frappe.db.get_single_value('Stock Settings', 'default_warehouse') | ||||
| 			or frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})) | ||||
|         		or 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) | ||||
|                                   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 if self.item_name else self.item_code) + '-' + random_string(5)) | ||||
|                     'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5)) | ||||
| 
 | ||||
| 	def validate_website_image(self): | ||||
| 		"""Validate if the website image is a public file""" | ||||
| @ -176,14 +184,13 @@ class Item(WebsiteGenerator): | ||||
| 			"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)) | ||||
|                                     .format(self.website_image, self.name)) | ||||
| 
 | ||||
| 			self.website_image = None | ||||
| 
 | ||||
| @ -219,7 +226,8 @@ class Item(WebsiteGenerator): | ||||
| 				self.website_image = None | ||||
| 
 | ||||
| 			except requests.exceptions.SSLError: | ||||
| 				frappe.msgprint(_("Warning: Invalid SSL certificate on attachment {0}").format(self.website_image)) | ||||
| 				frappe.msgprint( | ||||
| 					_("Warning: Invalid SSL certificate on attachment {0}").format(self.website_image)) | ||||
| 				self.website_image = None | ||||
| 
 | ||||
| 			# for CSV import | ||||
| @ -259,12 +267,13 @@ class Item(WebsiteGenerator): | ||||
| 
 | ||||
| 	def validate_retain_sample(self): | ||||
| 		if self.retain_sample and not frappe.db.get_single_value('Stock Settings', 'sample_retention_warehouse'): | ||||
| 			frappe.throw(_("Please select Sample Retention Warehouse in Stock Settings first")); | ||||
| 			frappe.throw(_("Please select Sample Retention Warehouse in Stock Settings first")) | ||||
| 		if self.retain_sample and not self.has_batch_no: | ||||
| 			frappe.throw(_(" {0} Retain Sample is based on batch, please check Has Batch No to retain sample of item").format(self.item_code)) | ||||
| 			frappe.throw(_(" {0} Retain Sample is based on batch, please check Has Batch No to retain sample of item").format( | ||||
| 				self.item_code)) | ||||
| 
 | ||||
| 	def get_context(self, context): | ||||
| 		context.show_search=True | ||||
| 		context.show_search = True | ||||
| 		context.search_link = '/product_search' | ||||
| 
 | ||||
| 		context.parents = get_parent_item_groups(self.item_group) | ||||
| @ -282,8 +291,8 @@ class Item(WebsiteGenerator): | ||||
| 			# 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") | ||||
|                                      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: | ||||
| @ -294,7 +303,7 @@ class Item(WebsiteGenerator): | ||||
| 				context.variant = frappe.get_doc("Item", variant) | ||||
| 
 | ||||
| 				for fieldname in ("website_image", "web_long_description", "description", | ||||
| 					"website_specifications"): | ||||
|                                         "website_specifications"): | ||||
| 					if context.variant.get(fieldname): | ||||
| 						value = context.variant.get(fieldname) | ||||
| 						if isinstance(value, list): | ||||
| @ -317,14 +326,14 @@ class Item(WebsiteGenerator): | ||||
| 			# load attributes | ||||
| 			for v in context.variants: | ||||
| 				v.attributes = frappe.get_all("Item Variant Attribute", | ||||
| 					fields=["attribute", "attribute_value"], filters={"parent": v.name}) | ||||
|                                   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: | ||||
| 					if v.name == context.variant.name: | ||||
| 						context.selected_attributes[attr.attribute] = attr.attribute_value | ||||
| 
 | ||||
| 			# filter attributes, order based on attribute table | ||||
| @ -338,7 +347,7 @@ class Item(WebsiteGenerator): | ||||
| 				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"): | ||||
|                                          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) | ||||
| @ -373,7 +382,7 @@ class Item(WebsiteGenerator): | ||||
| 					return True | ||||
| 
 | ||||
| 		for i, attr in enumerate(self.attributes): | ||||
| 			if i==0: | ||||
| 			if i == 0: | ||||
| 				continue | ||||
| 
 | ||||
| 			combination_source = [] | ||||
| @ -414,7 +423,7 @@ class Item(WebsiteGenerator): | ||||
| 			for d in template.get("reorder_levels"): | ||||
| 				n = {} | ||||
| 				for k in ("warehouse", "warehouse_reorder_level", | ||||
| 					"warehouse_reorder_qty", "material_request_type"): | ||||
|                                         "warehouse_reorder_qty", "material_request_type"): | ||||
| 					n[k] = d.get(k) | ||||
| 				self.append("reorder_levels", n) | ||||
| 
 | ||||
| @ -422,12 +431,14 @@ class Item(WebsiteGenerator): | ||||
| 		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)) | ||||
| 				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)) | ||||
| 				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: | ||||
| @ -436,29 +447,30 @@ class Item(WebsiteGenerator): | ||||
| 		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)) | ||||
| 				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=[] | ||||
| 		cust_code = [] | ||||
| 		for d in self.get('customer_items'): | ||||
| 			cust_code.append(d.ref_code) | ||||
| 		self.customer_code=','.join(cust_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=[] | ||||
| 		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)) | ||||
| 					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)) | ||||
| @ -466,12 +478,20 @@ class Item(WebsiteGenerator): | ||||
| 						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])) | ||||
| 		from stdnum import ean | ||||
| 		if len(self.barcodes) > 0: | ||||
| 			for item_barcode in self.barcodes: | ||||
| 				if item_barcode.barcode: | ||||
| 					duplicate = frappe.db.sql( | ||||
| 						"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name)) | ||||
| 					if duplicate: | ||||
| 						frappe.throw(_("Barcode {0} already used in Item {1}").format( | ||||
| 							item_barcode.barcode, duplicate[0][0])) | ||||
| 
 | ||||
| 					if item_barcode.barcode_type: | ||||
| 						if not ean.is_valid(item_barcode.barcode): | ||||
| 							frappe.throw(_("Barcode {0} is not a valid {1} code").format( | ||||
| 								item_barcode.barcode, item_barcode.barcode_type)) | ||||
| 
 | ||||
| 	def validate_warehouse_for_reorder(self): | ||||
| 		'''Validate Reorder level table for duplicate and conditional mandatory''' | ||||
| @ -483,7 +503,7 @@ class Item(WebsiteGenerator): | ||||
| 				warehouse += [d.get("warehouse")] | ||||
| 			else: | ||||
| 				frappe.throw(_("Row {0}: An Reorder entry already exists for this warehouse {1}") | ||||
| 					.format(d.idx, d.warehouse), DuplicateReorderRows) | ||||
|                                     .format(d.idx, d.warehouse), DuplicateReorderRows) | ||||
| 
 | ||||
| 			if d.warehouse_reorder_level and not d.warehouse_reorder_qty: | ||||
| 				frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx)) | ||||
| @ -497,12 +517,13 @@ class Item(WebsiteGenerator): | ||||
| 	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")) | ||||
| 			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)) | ||||
|                     (self.item_name, self.description, self.name)) | ||||
| 
 | ||||
| 	def on_trash(self): | ||||
| 		super(Item, self).on_trash() | ||||
| @ -512,7 +533,7 @@ class Item(WebsiteGenerator): | ||||
| 			frappe.delete_doc("Item", variant_of.name) | ||||
| 
 | ||||
| 	def before_rename(self, old_name, new_name, merge=False): | ||||
| 		if self.item_name==old_name: | ||||
| 		if self.item_name == old_name: | ||||
| 			frappe.db.set_value("Item", old_name, "item_name", new_name) | ||||
| 
 | ||||
| 		if merge: | ||||
| @ -524,7 +545,7 @@ class Item(WebsiteGenerator): | ||||
| 			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])) | ||||
|                                     + ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list])) | ||||
| 
 | ||||
| 	def after_rename(self, old_name, new_name, merge): | ||||
| 		if self.route: | ||||
| @ -547,7 +568,7 @@ class Item(WebsiteGenerator): | ||||
| 					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) | ||||
|                                             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) | ||||
| @ -575,13 +596,14 @@ class Item(WebsiteGenerator): | ||||
| 		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 | ||||
|                                            {"parent": self.item_group}, ["label", "description"]): | ||||
| 				row = self.append("website_specifications") | ||||
| 				row.label = label | ||||
| 				row.description = desc | ||||
| 
 | ||||
| 	def update_bom_item_desc(self): | ||||
| 		if self.is_new(): return | ||||
| 		if self.is_new(): | ||||
| 			return | ||||
| 
 | ||||
| 		if self.db_get('description') != self.description: | ||||
| 			frappe.db.sql(""" | ||||
| @ -620,11 +642,11 @@ class Item(WebsiteGenerator): | ||||
| 
 | ||||
| 	def update_variants(self): | ||||
| 		if self.flags.dont_update_variants or \ | ||||
| 			frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'): | ||||
|                         frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'): | ||||
| 			return | ||||
| 		if self.has_variants: | ||||
| 			updated = [] | ||||
| 			variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name }) | ||||
| 			variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name}) | ||||
| 			for d in variants: | ||||
| 				variant = frappe.get_doc("Item", d) | ||||
| 				copy_attributes_to_variant(self, variant) | ||||
| @ -641,39 +663,41 @@ class Item(WebsiteGenerator): | ||||
| 	def validate_stock_exists_for_template_item(self): | ||||
| 		if self.stock_ledger_created() and self._doc_before_save: | ||||
| 			if (self._doc_before_save.has_variants != self.has_variants | ||||
| 				or self._doc_before_save.variant_of != self.variant_of): | ||||
|                                 or self._doc_before_save.variant_of != self.variant_of): | ||||
| 				frappe.throw(_("Cannot change Variant properties after stock transction. You will have to make a new Item to do this.").format(self.name), | ||||
| 					StockExistsForTemplate) | ||||
|                                     StockExistsForTemplate) | ||||
| 
 | ||||
| 			if self.has_variants or self.variant_of: | ||||
| 				if not self.is_child_table_same('attributes'): | ||||
| 					frappe.throw(_('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item')) | ||||
| 					frappe.throw( | ||||
| 						_('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item')) | ||||
| 
 | ||||
| 	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}): | ||||
| 			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)) | ||||
|                                     .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': | ||||
| 		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))) | ||||
| 					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': | ||||
| 		if self.variant_of and self.variant_based_on == 'Item Attribute': | ||||
| 			args = {} | ||||
| 			for d in self.attributes: | ||||
| 				if not d.attribute_value: | ||||
| @ -683,10 +707,11 @@ class Item(WebsiteGenerator): | ||||
| 			variant = get_variant(self.variant_of, args, self.name) | ||||
| 			if variant: | ||||
| 				frappe.throw(_("Item variant {0} exists with same attributes") | ||||
| 					.format(variant), ItemVariantExistsError) | ||||
|                                     .format(variant), ItemVariantExistsError) | ||||
| 
 | ||||
| 			validate_item_variant_attributes(self, args) | ||||
| 
 | ||||
| 
 | ||||
| def get_timeline_data(doctype, name): | ||||
| 	'''returns timeline data based on stock ledger entry''' | ||||
| 	out = {} | ||||
| @ -697,21 +722,23 @@ def get_timeline_data(doctype, name): | ||||
| 
 | ||||
| 	for date, count in items.iteritems(): | ||||
| 		timestamp = get_timestamp(date) | ||||
| 		out.update({ timestamp: count }) | ||||
| 		out.update({timestamp: count}) | ||||
| 
 | ||||
| 	return out | ||||
| 
 | ||||
| 
 | ||||
| def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1): | ||||
| 	if (not end_of_life) or (disabled is None): | ||||
| 		end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"]) | ||||
| 
 | ||||
| 	if end_of_life and end_of_life!="0000-00-00" and getdate(end_of_life) <= now_datetime().date(): | ||||
| 	if end_of_life and end_of_life != "0000-00-00" and getdate(end_of_life) <= now_datetime().date(): | ||||
| 		msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life)) | ||||
| 		_msgprint(msg, verbose) | ||||
| 
 | ||||
| 	if disabled: | ||||
| 		_msgprint(_("Item {0} is disabled").format(item_code), verbose) | ||||
| 
 | ||||
| 
 | ||||
| def validate_is_stock_item(item_code, is_stock_item=None, verbose=1): | ||||
| 	if not is_stock_item: | ||||
| 		is_stock_item = frappe.db.get_value("Item", item_code, "is_stock_item") | ||||
| @ -721,6 +748,7 @@ def validate_is_stock_item(item_code, is_stock_item=None, verbose=1): | ||||
| 
 | ||||
| 		_msgprint(msg, verbose) | ||||
| 
 | ||||
| 
 | ||||
| def validate_cancelled_item(item_code, docstatus=None, verbose=1): | ||||
| 	if docstatus is None: | ||||
| 		docstatus = frappe.db.get_value("Item", item_code, "docstatus") | ||||
| @ -729,6 +757,7 @@ def validate_cancelled_item(item_code, docstatus=None, verbose=1): | ||||
| 		msg = _("Item {0} is cancelled").format(item_code) | ||||
| 		_msgprint(msg, verbose) | ||||
| 
 | ||||
| 
 | ||||
| def _msgprint(msg, verbose): | ||||
| 	if verbose: | ||||
| 		msgprint(msg, raise_exception=True) | ||||
| @ -760,19 +789,19 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): | ||||
| 		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") | ||||
| 	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): | ||||
|                 (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): | ||||
|                 (last_purchase_receipt and not last_purchase_order): | ||||
| 		# use purchase receipt | ||||
| 		last_purchase = last_purchase_receipt[0] | ||||
| 		purchase_date = purchase_receipt_date | ||||
| @ -797,11 +826,12 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): | ||||
| 
 | ||||
| 	return out | ||||
| 
 | ||||
| 
 | ||||
| def invalidate_cache_for_item(doc): | ||||
| 	invalidate_cache_for(doc, doc.item_group) | ||||
| 
 | ||||
| 	website_item_groups = list(set((doc.get("old_website_item_groups") or []) | ||||
| 		+ [d.item_group for d in doc.get({"doctype":"Website Item Group"}) if d.item_group])) | ||||
|                                 + [d.item_group for d in doc.get({"doctype": "Website Item Group"}) if d.item_group])) | ||||
| 
 | ||||
| 	for item_group in website_item_groups: | ||||
| 		invalidate_cache_for(doc, item_group) | ||||
| @ -809,13 +839,14 @@ def invalidate_cache_for_item(doc): | ||||
| 	if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group: | ||||
| 		invalidate_cache_for(doc, doc.old_item_group) | ||||
| 
 | ||||
| 
 | ||||
| def check_stock_uom_with_bin(item, stock_uom): | ||||
| 	if stock_uom == frappe.db.get_value("Item", item, "stock_uom"): | ||||
| 		return | ||||
| 
 | ||||
| 	matched=True | ||||
| 	matched = True | ||||
| 	ref_uom = frappe.db.get_value("Stock Ledger Entry", | ||||
| 		{"item_code": item}, "stock_uom") | ||||
|                                {"item_code": item}, "stock_uom") | ||||
| 
 | ||||
| 	if ref_uom: | ||||
| 		if cstr(ref_uom) != cstr(stock_uom): | ||||
| @ -823,13 +854,14 @@ def check_stock_uom_with_bin(item, stock_uom): | ||||
| 	else: | ||||
| 		bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1) | ||||
| 		for bin in bin_list: | ||||
| 			if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 \ | ||||
| 				or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom): | ||||
| 					matched = False | ||||
| 					break | ||||
| 			if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 | ||||
|                                 or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom): | ||||
| 				matched = False | ||||
| 				break | ||||
| 
 | ||||
| 		if matched and bin_list: | ||||
| 			frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", (stock_uom, item)) | ||||
| 
 | ||||
| 	if not matched: | ||||
| 		frappe.throw(_("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.").format(item)) | ||||
| 		frappe.throw( | ||||
| 			_("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.").format(item)) | ||||
|  | ||||
							
								
								
									
										0
									
								
								erpnext/stock/doctype/item_barcode/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								erpnext/stock/doctype/item_barcode/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										103
									
								
								erpnext/stock/doctype/item_barcode/item_barcode.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								erpnext/stock/doctype/item_barcode/item_barcode.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 0,  | ||||
|  "allow_rename": 0,  | ||||
|  "autoname": "field:barcode",  | ||||
|  "beta": 0,  | ||||
|  "creation": "2017-12-09 18:54:50.562438",  | ||||
|  "custom": 0,  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "DocType",  | ||||
|  "document_type": "",  | ||||
|  "editable_grid": 1,  | ||||
|  "engine": "InnoDB",  | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "barcode",  | ||||
|    "fieldtype": "Data",  | ||||
|    "hidden": 0,  | ||||
|    "ignore_user_permissions": 0,  | ||||
|    "ignore_xss_filter": 0,  | ||||
|    "in_filter": 0,  | ||||
|    "in_global_search": 1,  | ||||
|    "in_list_view": 1,  | ||||
|    "in_standard_filter": 0,  | ||||
|    "label": "Barcode",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 1,  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 1,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "unique": 1 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "barcode_type",  | ||||
|    "fieldtype": "Select",  | ||||
|    "hidden": 0,  | ||||
|    "ignore_user_permissions": 0,  | ||||
|    "ignore_xss_filter": 0,  | ||||
|    "in_filter": 0,  | ||||
|    "in_global_search": 0,  | ||||
|    "in_list_view": 1,  | ||||
|    "in_standard_filter": 0,  | ||||
|    "label": "Barcode Type",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "options": "\nEAN\nUPC-A",  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "unique": 0 | ||||
|   } | ||||
|  ],  | ||||
|  "has_web_view": 0,  | ||||
|  "hide_heading": 0,  | ||||
|  "hide_toolbar": 0,  | ||||
|  "idx": 0,  | ||||
|  "image_view": 0,  | ||||
|  "in_create": 0,  | ||||
|  "is_submittable": 0,  | ||||
|  "issingle": 0,  | ||||
|  "istable": 1,  | ||||
|  "max_attachments": 0,  | ||||
|  "modified": "2017-12-10 20:55:23.814039",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Stock",  | ||||
|  "name": "Item Barcode",  | ||||
|  "name_case": "",  | ||||
|  "owner": "Administrator",  | ||||
|  "permissions": [],  | ||||
|  "quick_entry": 1,  | ||||
|  "read_only": 0,  | ||||
|  "read_only_onload": 0,  | ||||
|  "show_name_in_global_search": 0,  | ||||
|  "sort_field": "modified",  | ||||
|  "sort_order": "DESC",  | ||||
|  "track_changes": 1,  | ||||
|  "track_seen": 0 | ||||
| } | ||||
							
								
								
									
										11
									
								
								erpnext/stock/doctype/item_barcode/item_barcode.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								erpnext/stock/doctype/item_barcode/item_barcode.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors | ||||
| # For license information, please see license.txt | ||||
| 
 | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from frappe.model.document import Document | ||||
| 
 | ||||
| 
 | ||||
| class ItemBarcode(Document): | ||||
|     pass | ||||
| @ -25,7 +25,7 @@ class StockSettings(Document): | ||||
| 			frappe.msgprint (_("`Freeze Stocks Older Than` should be smaller than %d days.") %stock_frozen_limit) | ||||
| 
 | ||||
| 		# show/hide barcode field | ||||
| 		frappe.make_property_setter({'fieldname': 'barcode', 'property': 'hidden', | ||||
| 		frappe.make_property_setter({'fieldname': 'barcodes', 'property': 'hidden', | ||||
| 			'value': 0 if self.show_barcode_field else 1}) | ||||
| 
 | ||||
| 		self.cant_change_valuation_method() | ||||
|  | ||||
| @ -120,7 +120,7 @@ def process_args(args): | ||||
| @frappe.whitelist() | ||||
| def get_item_code(barcode=None, serial_no=None): | ||||
| 	if barcode: | ||||
| 		item_code = frappe.db.get_value("Item", {"barcode": barcode}) | ||||
| 		item_code = frappe.db.get_value("Item Barcode", {"barcode": barcode}, fieldname=["parent"]) | ||||
| 		if not item_code: | ||||
| 			frappe.throw(_("No Item with Barcode {0}").format(barcode)) | ||||
| 	elif serial_no: | ||||
| @ -273,7 +273,7 @@ def get_basic_details(args, item): | ||||
| 			if not out[d[1]] or (company and args.company != company): | ||||
| 				out[d[1]] = frappe.db.get_value("Company", args.company, d[2]) if d[2] else None | ||||
| 
 | ||||
| 	for fieldname in ("item_name", "item_group", "barcode", "brand", "stock_uom"): | ||||
| 	for fieldname in ("item_name", "item_group", "barcodes", "brand", "stock_uom"): | ||||
| 		out[fieldname] = item.get(fieldname) | ||||
| 
 | ||||
| 	return out | ||||
|  | ||||
| @ -2,3 +2,4 @@ frappe | ||||
| unidecode | ||||
| pygithub | ||||
| googlemaps | ||||
| python-stdnum | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user