Fixed merge conflict
This commit is contained in:
commit
e21e59614f
@ -2,23 +2,30 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, json
|
|
||||||
from frappe import _
|
import json
|
||||||
from frappe.utils import nowdate
|
|
||||||
from erpnext.setup.utils import get_exchange_rate
|
import frappe
|
||||||
from frappe.core.doctype.communication.email import make
|
|
||||||
from erpnext.stock.get_item_details import get_pos_profile
|
|
||||||
from erpnext.accounts.party import get_party_account_currency
|
from erpnext.accounts.party import get_party_account_currency
|
||||||
from erpnext.controllers.accounts_controller import get_taxes_and_charges
|
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()
|
@frappe.whitelist()
|
||||||
def get_pos_data():
|
def get_pos_data():
|
||||||
doc = frappe.new_doc('Sales Invoice')
|
doc = frappe.new_doc('Sales Invoice')
|
||||||
doc.is_pos = 1;
|
doc.is_pos = 1
|
||||||
pos_profile = get_pos_profile(doc.company) or {}
|
pos_profile = get_pos_profile(doc.company) or {}
|
||||||
if not pos_profile:
|
if not pos_profile:
|
||||||
frappe.throw(_("POS Profile is required to use Point-of-Sale"))
|
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')
|
doc.update_stock = pos_profile.get('update_stock')
|
||||||
|
|
||||||
if pos_profile.get('name'):
|
if pos_profile.get('name'):
|
||||||
@ -30,18 +37,20 @@ def get_pos_data():
|
|||||||
update_multi_mode_option(doc, pos_profile)
|
update_multi_mode_option(doc, pos_profile)
|
||||||
default_print_format = pos_profile.get('print_format') or "Point of Sale"
|
default_print_format = pos_profile.get('print_format') or "Point of Sale"
|
||||||
print_template = frappe.db.get_value('Print Format', default_print_format, 'html')
|
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)
|
customers = get_customers_list(pos_profile)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'doc': doc,
|
'doc': doc,
|
||||||
'default_customer': pos_profile.get('customer'),
|
'default_customer': pos_profile.get('customer'),
|
||||||
'items': get_items_list(pos_profile),
|
'items': items_list,
|
||||||
'item_groups': get_item_groups(pos_profile),
|
'item_groups': get_item_groups(pos_profile),
|
||||||
'customers': customers,
|
'customers': customers,
|
||||||
'address': get_customers_address(customers),
|
'address': get_customers_address(customers),
|
||||||
'contacts': get_contacts(customers),
|
'contacts': get_contacts(customers),
|
||||||
'serial_no_data': get_serial_no_data(pos_profile, doc.company),
|
'serial_no_data': get_serial_no_data(pos_profile, doc.company),
|
||||||
'batch_no_data': get_batch_no_data(),
|
'batch_no_data': get_batch_no_data(),
|
||||||
|
'barcode_data': get_barcode_data(items_list),
|
||||||
'tax_data': get_item_tax_data(),
|
'tax_data': get_item_tax_data(),
|
||||||
'price_list_data': get_price_list_data(doc.selling_price_list),
|
'price_list_data': get_price_list_data(doc.selling_price_list),
|
||||||
'bin_data': get_bin_data(pos_profile),
|
'bin_data': get_bin_data(pos_profile),
|
||||||
@ -51,6 +60,7 @@ def get_pos_data():
|
|||||||
'meta': get_meta()
|
'meta': get_meta()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_meta():
|
def get_meta():
|
||||||
doctype_meta = {
|
doctype_meta = {
|
||||||
'customer': frappe.get_meta('Customer'),
|
'customer': frappe.get_meta('Customer'),
|
||||||
@ -63,9 +73,11 @@ def get_meta():
|
|||||||
|
|
||||||
return doctype_meta
|
return doctype_meta
|
||||||
|
|
||||||
|
|
||||||
def get_company_data(company):
|
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):
|
def update_pos_profile_data(doc, pos_profile, company_data):
|
||||||
doc.campaign = pos_profile.get('campaign')
|
doc.campaign = pos_profile.get('campaign')
|
||||||
if pos_profile and not pos_profile.get('country'):
|
if pos_profile and not pos_profile.get('country'):
|
||||||
@ -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.terms = frappe.db.get_value('Terms and Conditions', pos_profile.get('tc_name'), 'terms') or doc.terms or ''
|
||||||
doc.offline_pos_name = ''
|
doc.offline_pos_name = ''
|
||||||
|
|
||||||
|
|
||||||
def get_root(table):
|
def get_root(table):
|
||||||
root = frappe.db.sql(""" select name from `tab%(table)s` having
|
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
|
return root[0].name
|
||||||
|
|
||||||
|
|
||||||
def update_multi_mode_option(doc, pos_profile):
|
def update_multi_mode_option(doc, pos_profile):
|
||||||
from frappe.model import default_fields
|
from frappe.model import default_fields
|
||||||
|
|
||||||
@ -123,15 +137,18 @@ def update_multi_mode_option(doc, pos_profile):
|
|||||||
|
|
||||||
doc.append('payments', payment_mode)
|
doc.append('payments', payment_mode)
|
||||||
|
|
||||||
|
|
||||||
def get_mode_of_payment(doc):
|
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,
|
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)
|
`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):
|
def update_tax_table(doc):
|
||||||
taxes = get_taxes_and_charges('Sales Taxes and Charges Template', doc.taxes_and_charges)
|
taxes = get_taxes_and_charges('Sales Taxes and Charges Template', doc.taxes_and_charges)
|
||||||
for tax in taxes:
|
for tax in taxes:
|
||||||
doc.append('taxes', tax)
|
doc.append('taxes', tax)
|
||||||
|
|
||||||
|
|
||||||
def get_items_list(pos_profile):
|
def get_items_list(pos_profile):
|
||||||
cond = "1=1"
|
cond = "1=1"
|
||||||
item_groups = []
|
item_groups = []
|
||||||
@ -145,13 +162,14 @@ def get_items_list(pos_profile):
|
|||||||
select
|
select
|
||||||
name, item_code, item_name, description, item_group, expense_account, has_batch_no,
|
name, item_code, item_name, description, item_group, expense_account, has_batch_no,
|
||||||
has_serial_no, expense_account, selling_cost_center, stock_uom, image,
|
has_serial_no, expense_account, selling_cost_center, stock_uom, image,
|
||||||
default_warehouse, is_stock_item, barcode, brand
|
default_warehouse, is_stock_item, brand
|
||||||
from
|
from
|
||||||
tabItem
|
tabItem
|
||||||
where
|
where
|
||||||
disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond}
|
disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond}
|
||||||
""".format(cond=cond), tuple(item_groups), as_dict=1)
|
""".format(cond=cond), tuple(item_groups), as_dict=1)
|
||||||
|
|
||||||
|
|
||||||
def get_item_groups(pos_profile):
|
def get_item_groups(pos_profile):
|
||||||
item_group_dict = {}
|
item_group_dict = {}
|
||||||
item_groups = frappe.db.sql("""Select name,
|
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]
|
item_group_dict[data.name] = [data.lft, data.rgt]
|
||||||
return item_group_dict
|
return item_group_dict
|
||||||
|
|
||||||
|
|
||||||
def get_customers_list(pos_profile={}):
|
def get_customers_list(pos_profile={}):
|
||||||
cond = "1=1"
|
cond = "1=1"
|
||||||
customer_groups = []
|
customer_groups = []
|
||||||
@ -174,6 +193,7 @@ def get_customers_list(pos_profile={}):
|
|||||||
territory, customer_pos_id from tabCustomer where disabled = 0
|
territory, customer_pos_id from tabCustomer where disabled = 0
|
||||||
and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
|
and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
|
||||||
|
|
||||||
|
|
||||||
def get_customers_address(customers):
|
def get_customers_address(customers):
|
||||||
customer_address = {}
|
customer_address = {}
|
||||||
if isinstance(customers, basestring):
|
if isinstance(customers, basestring):
|
||||||
@ -185,13 +205,15 @@ def get_customers_address(customers):
|
|||||||
(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
|
(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
|
||||||
and parenttype = 'Address')""", data.name, as_dict=1)
|
and parenttype = 'Address')""", data.name, as_dict=1)
|
||||||
address_data = {}
|
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})
|
address_data.update({'full_name': data.customer_name, 'customer_pos_id': data.customer_pos_id})
|
||||||
customer_address[data.name] = address_data
|
customer_address[data.name] = address_data
|
||||||
|
|
||||||
return customer_address
|
return customer_address
|
||||||
|
|
||||||
|
|
||||||
def get_contacts(customers):
|
def get_contacts(customers):
|
||||||
customer_contact = {}
|
customer_contact = {}
|
||||||
if isinstance(customers, basestring):
|
if isinstance(customers, basestring):
|
||||||
@ -207,11 +229,13 @@ def get_contacts(customers):
|
|||||||
|
|
||||||
return customer_contact
|
return customer_contact
|
||||||
|
|
||||||
|
|
||||||
def get_child_nodes(group_type, root):
|
def get_child_nodes(group_type, root):
|
||||||
lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
|
lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
|
||||||
return frappe.db.sql(""" Select name, lft, rgt from `tab{tab}` where
|
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)
|
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):
|
def get_serial_no_data(pos_profile, company):
|
||||||
# get itemwise serial no data
|
# get itemwise serial no data
|
||||||
# example {'Nokia Lumia 1020': {'SN0001': 'Pune'}}
|
# example {'Nokia Lumia 1020': {'SN0001': 'Pune'}}
|
||||||
@ -232,6 +256,7 @@ def get_serial_no_data(pos_profile, company):
|
|||||||
|
|
||||||
return itemwise_serial_no
|
return itemwise_serial_no
|
||||||
|
|
||||||
|
|
||||||
def get_batch_no_data():
|
def get_batch_no_data():
|
||||||
# get itemwise batch no data
|
# get itemwise batch no data
|
||||||
# exmaple: {'LED-GRE': [Batch001, Batch002]}
|
# exmaple: {'LED-GRE': [Batch001, Batch002]}
|
||||||
@ -248,6 +273,26 @@ def get_batch_no_data():
|
|||||||
|
|
||||||
return itemwise_batch
|
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():
|
def get_item_tax_data():
|
||||||
# get default tax of an item
|
# get default tax of an item
|
||||||
# example: {'Consulting Services': {'Excise 12 - TS': '12.000'}}
|
# example: {'Consulting Services': {'Excise 12 - TS': '12.000'}}
|
||||||
@ -262,6 +307,7 @@ def get_item_tax_data():
|
|||||||
|
|
||||||
return itemwise_tax
|
return itemwise_tax
|
||||||
|
|
||||||
|
|
||||||
def get_price_list_data(selling_price_list):
|
def get_price_list_data(selling_price_list):
|
||||||
itemwise_price_list = {}
|
itemwise_price_list = {}
|
||||||
price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate,
|
price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate,
|
||||||
@ -273,6 +319,7 @@ def get_price_list_data(selling_price_list):
|
|||||||
|
|
||||||
return itemwise_price_list
|
return itemwise_price_list
|
||||||
|
|
||||||
|
|
||||||
def get_bin_data(pos_profile):
|
def get_bin_data(pos_profile):
|
||||||
itemwise_bin_data = {}
|
itemwise_bin_data = {}
|
||||||
cond = "1=1"
|
cond = "1=1"
|
||||||
@ -289,6 +336,7 @@ def get_bin_data(pos_profile):
|
|||||||
|
|
||||||
return itemwise_bin_data
|
return itemwise_bin_data
|
||||||
|
|
||||||
|
|
||||||
def get_pricing_rule_data(doc):
|
def get_pricing_rule_data(doc):
|
||||||
pricing_rules = ""
|
pricing_rules = ""
|
||||||
if doc.ignore_pricing_rule == 0:
|
if doc.ignore_pricing_rule == 0:
|
||||||
@ -300,6 +348,7 @@ def get_pricing_rule_data(doc):
|
|||||||
{'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
|
return pricing_rules
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
||||||
if isinstance(doc_list, basestring):
|
if isinstance(doc_list, basestring):
|
||||||
@ -338,14 +387,15 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
|||||||
'synced_contacts': get_contacts(customers)
|
'synced_contacts': get_contacts(customers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def validate_records(doc):
|
def validate_records(doc):
|
||||||
validate_item(doc)
|
validate_item(doc)
|
||||||
|
|
||||||
|
|
||||||
def get_customer_id(doc, customer=None):
|
def get_customer_id(doc, customer=None):
|
||||||
cust_id = None
|
cust_id = None
|
||||||
if doc.get('customer_pos_id'):
|
if doc.get('customer_pos_id'):
|
||||||
cust_id = frappe.db.get_value('Customer',
|
cust_id = frappe.db.get_value('Customer',{'customer_pos_id': doc.get('customer_pos_id')}, 'name')
|
||||||
{'customer_pos_id': doc.get('customer_pos_id')}, 'name')
|
|
||||||
|
|
||||||
if not cust_id:
|
if not cust_id:
|
||||||
customer = customer or doc.get('customer')
|
customer = customer or doc.get('customer')
|
||||||
@ -356,6 +406,7 @@ def get_customer_id(doc, customer=None):
|
|||||||
|
|
||||||
return cust_id
|
return cust_id
|
||||||
|
|
||||||
|
|
||||||
def make_customer_and_address(customers):
|
def make_customer_and_address(customers):
|
||||||
customers_list = []
|
customers_list = []
|
||||||
for customer, data in customers.items():
|
for customer, data in customers.items():
|
||||||
@ -372,6 +423,7 @@ def make_customer_and_address(customers):
|
|||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
return customers_list
|
return customers_list
|
||||||
|
|
||||||
|
|
||||||
def add_customer(data):
|
def add_customer(data):
|
||||||
customer_doc = frappe.new_doc('Customer')
|
customer_doc = frappe.new_doc('Customer')
|
||||||
customer_doc.customer_name = data.get('full_name') or data.get('customer')
|
customer_doc.customer_name = data.get('full_name') or data.get('customer')
|
||||||
@ -384,19 +436,20 @@ def add_customer(data):
|
|||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
return customer_doc.name
|
return customer_doc.name
|
||||||
|
|
||||||
|
|
||||||
def get_territory(data):
|
def get_territory(data):
|
||||||
if data.get('territory'):
|
if data.get('territory'):
|
||||||
return data.get('territory')
|
return data.get('territory')
|
||||||
|
|
||||||
return frappe.db.get_single_value('Selling Settings',
|
return frappe.db.get_single_value('Selling Settings','territory') or _('All Territories')
|
||||||
'territory') or _('All Territories')
|
|
||||||
|
|
||||||
def get_customer_group(data):
|
def get_customer_group(data):
|
||||||
if data.get('customer_group'):
|
if data.get('customer_group'):
|
||||||
return data.get('customer_group')
|
return data.get('customer_group')
|
||||||
|
|
||||||
return frappe.db.get_single_value('Selling Settings',
|
return frappe.db.get_single_value('Selling Settings', 'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name')
|
||||||
'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'):
|
if args.get('email_id') or args.get('phone'):
|
||||||
@ -423,8 +476,10 @@ def make_contact(args,customer):
|
|||||||
doc.flags.ignore_mandatory = True
|
doc.flags.ignore_mandatory = True
|
||||||
doc.save(ignore_permissions=True)
|
doc.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
def make_address(args, customer):
|
def make_address(args, customer):
|
||||||
if not args.get('address_line1'): return
|
if not args.get('address_line1'):
|
||||||
|
return
|
||||||
|
|
||||||
name = args.get('name')
|
name = args.get('name')
|
||||||
|
|
||||||
@ -448,6 +503,7 @@ def make_address(args, customer):
|
|||||||
address.flags.ignore_mandatory = True
|
address.flags.ignore_mandatory = True
|
||||||
address.save(ignore_permissions=True)
|
address.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
def make_email_queue(email_queue):
|
def make_email_queue(email_queue):
|
||||||
name_list = []
|
name_list = []
|
||||||
for key, data in email_queue.items():
|
for key, data in email_queue.items():
|
||||||
@ -464,6 +520,7 @@ def make_email_queue(email_queue):
|
|||||||
|
|
||||||
return name_list
|
return name_list
|
||||||
|
|
||||||
|
|
||||||
def validate_item(doc):
|
def validate_item(doc):
|
||||||
for item in doc.get('items'):
|
for item in doc.get('items'):
|
||||||
if not frappe.db.exists('Item', item.get('item_code')):
|
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()
|
frappe.db.commit()
|
||||||
name_list.append(name)
|
name_list.append(name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if frappe.message_log: frappe.message_log.pop()
|
if frappe.message_log:
|
||||||
|
frappe.message_log.pop()
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
frappe.log_error(frappe.get_traceback())
|
frappe.log_error(frappe.get_traceback())
|
||||||
name_list = save_invoice(doc, name, name_list)
|
name_list = save_invoice(doc, name, name_list)
|
||||||
|
|
||||||
return name_list
|
return name_list
|
||||||
|
|
||||||
|
|
||||||
def save_invoice(doc, name, name_list):
|
def save_invoice(doc, name, name_list):
|
||||||
try:
|
try:
|
||||||
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
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.customers = r.message.customers;
|
||||||
this.serial_no_data = r.message.serial_no_data;
|
this.serial_no_data = r.message.serial_no_data;
|
||||||
this.batch_no_data = r.message.batch_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.tax_data = r.message.tax_data;
|
||||||
this.contacts = r.message.contacts;
|
this.contacts = r.message.contacts;
|
||||||
this.address = r.message.address || {};
|
this.address = r.message.address || {};
|
||||||
@ -1110,9 +1111,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
search_status = false;
|
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()]]
|
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
|
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;
|
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())) ||
|
} 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())) {
|
reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase())) {
|
||||||
return true
|
return true
|
||||||
|
@ -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.accounts.party import get_party_account_currency, validate_party_frozen_disabled
|
||||||
from erpnext.exceptions import InvalidCurrency
|
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):
|
class AccountsController(TransactionBase):
|
||||||
def __init__(self, *args, **kwargs):
|
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
|
and (tabItem.`{key}` LIKE %(txt)s
|
||||||
or tabItem.item_group LIKE %(txt)s
|
or tabItem.item_group LIKE %(txt)s
|
||||||
or tabItem.item_name LIKE %(txt)s
|
or tabItem.item_name LIKE %(txt)s
|
||||||
or tabItem.barcode LIKE %(txt)s
|
|
||||||
or tabItem.description 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}
|
{fcond} {mcond}
|
||||||
order by
|
order by
|
||||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
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.set_default_payment_terms_based_on_company
|
||||||
erpnext.patches.v10_0.update_sales_order_link_to_purchase_order
|
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.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
|
batch_no, item_code = batch_no_data
|
||||||
|
|
||||||
if not serial_no and not batch_no:
|
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:
|
if barcode_data:
|
||||||
item_code, barcode = barcode_data
|
item_code, barcode = barcode_data
|
||||||
|
|
||||||
|
@ -172,35 +172,6 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 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_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -701,6 +672,67 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 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_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -3484,7 +3516,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 1,
|
"max_attachments": 1,
|
||||||
"modified": "2018-01-24 20:42:23.303090",
|
"modified": "2018-02-12 15:42:23.303090",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item",
|
"name": "Item",
|
||||||
|
@ -2,23 +2,31 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
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
|
import itertools
|
||||||
class StockExistsForTemplate(frappe.ValidationError): pass
|
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):
|
class Item(WebsiteGenerator):
|
||||||
website = frappe._dict(
|
website = frappe._dict(
|
||||||
@ -176,7 +184,6 @@ class Item(WebsiteGenerator):
|
|||||||
"file_url": self.website_image
|
"file_url": self.website_image
|
||||||
}, fields=["name", "is_private"], order_by="is_private asc", limit_page_length=1)
|
}, fields=["name", "is_private"], order_by="is_private asc", limit_page_length=1)
|
||||||
|
|
||||||
|
|
||||||
if file_doc:
|
if file_doc:
|
||||||
file_doc = file_doc[0]
|
file_doc = file_doc[0]
|
||||||
|
|
||||||
@ -219,7 +226,8 @@ class Item(WebsiteGenerator):
|
|||||||
self.website_image = None
|
self.website_image = None
|
||||||
|
|
||||||
except requests.exceptions.SSLError:
|
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
|
self.website_image = None
|
||||||
|
|
||||||
# for CSV import
|
# for CSV import
|
||||||
@ -259,9 +267,10 @@ class Item(WebsiteGenerator):
|
|||||||
|
|
||||||
def validate_retain_sample(self):
|
def validate_retain_sample(self):
|
||||||
if self.retain_sample and not frappe.db.get_single_value('Stock Settings', 'sample_retention_warehouse'):
|
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:
|
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):
|
def get_context(self, context):
|
||||||
context.show_search = True
|
context.show_search = True
|
||||||
@ -422,12 +431,14 @@ class Item(WebsiteGenerator):
|
|||||||
check_list = []
|
check_list = []
|
||||||
for d in self.get('uoms'):
|
for d in self.get('uoms'):
|
||||||
if cstr(d.uom) in check_list:
|
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:
|
else:
|
||||||
check_list.append(cstr(d.uom))
|
check_list.append(cstr(d.uom))
|
||||||
|
|
||||||
if d.uom and cstr(d.uom) == cstr(self.stock_uom) and flt(d.conversion_factor) != 1:
|
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):
|
def validate_item_type(self):
|
||||||
if self.has_serial_no == 1 and self.is_stock_item == 0:
|
if self.has_serial_no == 1 and self.is_stock_item == 0:
|
||||||
@ -436,12 +447,12 @@ class Item(WebsiteGenerator):
|
|||||||
if self.has_serial_no == 0 and self.serial_no_series:
|
if self.has_serial_no == 0 and self.serial_no_series:
|
||||||
self.serial_no_series = None
|
self.serial_no_series = None
|
||||||
|
|
||||||
|
|
||||||
def check_for_active_boms(self):
|
def check_for_active_boms(self):
|
||||||
if self.default_bom:
|
if self.default_bom:
|
||||||
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
||||||
if bom_item not in (self.name, self.variant_of):
|
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):
|
def fill_customer_code(self):
|
||||||
""" Append all the customer codes and insert into "customer_code" field of item table """
|
""" Append all the customer codes and insert into "customer_code" field of item table """
|
||||||
@ -458,7 +469,8 @@ class Item(WebsiteGenerator):
|
|||||||
account_type = frappe.db.get_value("Account", d.tax_type, "account_type")
|
account_type = frappe.db.get_value("Account", d.tax_type, "account_type")
|
||||||
|
|
||||||
if account_type not in ['Tax', 'Chargeable', 'Income Account', 'Expense Account']:
|
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:
|
else:
|
||||||
if d.tax_type in check_list:
|
if d.tax_type in check_list:
|
||||||
frappe.throw(_("{0} entered twice in Item Tax").format(d.tax_type))
|
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)
|
check_list.append(d.tax_type)
|
||||||
|
|
||||||
def validate_barcode(self):
|
def validate_barcode(self):
|
||||||
if self.barcode:
|
from stdnum import ean
|
||||||
duplicate = frappe.db.sql("""select name from tabItem where barcode = %s
|
if len(self.barcodes) > 0:
|
||||||
and name != %s""", (self.barcode, self.name))
|
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:
|
if duplicate:
|
||||||
frappe.throw(_("Barcode {0} already used in Item {1}").format(self.barcode, duplicate[0][0]))
|
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):
|
def validate_warehouse_for_reorder(self):
|
||||||
'''Validate Reorder level table for duplicate and conditional mandatory'''
|
'''Validate Reorder level table for duplicate and conditional mandatory'''
|
||||||
@ -497,7 +517,8 @@ class Item(WebsiteGenerator):
|
|||||||
def validate_name_with_item_group(self):
|
def validate_name_with_item_group(self):
|
||||||
# causes problem with tree build
|
# causes problem with tree build
|
||||||
if frappe.db.exists("Item Group", self.name):
|
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):
|
def update_item_price(self):
|
||||||
frappe.db.sql("""update `tabItem Price` set item_name=%s,
|
frappe.db.sql("""update `tabItem Price` set item_name=%s,
|
||||||
@ -581,7 +602,8 @@ class Item(WebsiteGenerator):
|
|||||||
row.description = desc
|
row.description = desc
|
||||||
|
|
||||||
def update_bom_item_desc(self):
|
def update_bom_item_desc(self):
|
||||||
if self.is_new(): return
|
if self.is_new():
|
||||||
|
return
|
||||||
|
|
||||||
if self.db_get('description') != self.description:
|
if self.db_get('description') != self.description:
|
||||||
frappe.db.sql("""
|
frappe.db.sql("""
|
||||||
@ -647,7 +669,8 @@ class Item(WebsiteGenerator):
|
|||||||
|
|
||||||
if self.has_variants or self.variant_of:
|
if self.has_variants or self.variant_of:
|
||||||
if not self.is_child_table_same('attributes'):
|
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):
|
def validate_uom(self):
|
||||||
if not self.get("__islocal"):
|
if not self.get("__islocal"):
|
||||||
@ -668,7 +691,8 @@ class Item(WebsiteGenerator):
|
|||||||
frappe.throw(_("Attribute table is mandatory"))
|
frappe.throw(_("Attribute table is mandatory"))
|
||||||
for d in self.attributes:
|
for d in self.attributes:
|
||||||
if d.attribute in 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:
|
else:
|
||||||
attributes.append(d.attribute)
|
attributes.append(d.attribute)
|
||||||
|
|
||||||
@ -687,6 +711,7 @@ class Item(WebsiteGenerator):
|
|||||||
|
|
||||||
validate_item_variant_attributes(self, args)
|
validate_item_variant_attributes(self, args)
|
||||||
|
|
||||||
|
|
||||||
def get_timeline_data(doctype, name):
|
def get_timeline_data(doctype, name):
|
||||||
'''returns timeline data based on stock ledger entry'''
|
'''returns timeline data based on stock ledger entry'''
|
||||||
out = {}
|
out = {}
|
||||||
@ -701,6 +726,7 @@ def get_timeline_data(doctype, name):
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1):
|
def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1):
|
||||||
if (not end_of_life) or (disabled is None):
|
if (not end_of_life) or (disabled is None):
|
||||||
end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"])
|
end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"])
|
||||||
@ -712,6 +738,7 @@ def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1):
|
|||||||
if disabled:
|
if disabled:
|
||||||
_msgprint(_("Item {0} is disabled").format(item_code), verbose)
|
_msgprint(_("Item {0} is disabled").format(item_code), verbose)
|
||||||
|
|
||||||
|
|
||||||
def validate_is_stock_item(item_code, is_stock_item=None, verbose=1):
|
def validate_is_stock_item(item_code, is_stock_item=None, verbose=1):
|
||||||
if not is_stock_item:
|
if not is_stock_item:
|
||||||
is_stock_item = frappe.db.get_value("Item", item_code, "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)
|
_msgprint(msg, verbose)
|
||||||
|
|
||||||
|
|
||||||
def validate_cancelled_item(item_code, docstatus=None, verbose=1):
|
def validate_cancelled_item(item_code, docstatus=None, verbose=1):
|
||||||
if docstatus is None:
|
if docstatus is None:
|
||||||
docstatus = frappe.db.get_value("Item", item_code, "docstatus")
|
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)
|
msg = _("Item {0} is cancelled").format(item_code)
|
||||||
_msgprint(msg, verbose)
|
_msgprint(msg, verbose)
|
||||||
|
|
||||||
|
|
||||||
def _msgprint(msg, verbose):
|
def _msgprint(msg, verbose):
|
||||||
if verbose:
|
if verbose:
|
||||||
msgprint(msg, raise_exception=True)
|
msgprint(msg, raise_exception=True)
|
||||||
@ -760,9 +789,9 @@ 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
|
order by pr.posting_date desc, pr.posting_time desc, pr.name desc
|
||||||
limit 1""", (item_code, cstr(doc_name)), as_dict=1)
|
limit 1""", (item_code, cstr(doc_name)), as_dict=1)
|
||||||
|
|
||||||
purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date \
|
purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
|
||||||
or "1900-01-01")
|
or "1900-01-01")
|
||||||
purchase_receipt_date = getdate(last_purchase_receipt and \
|
purchase_receipt_date = getdate(last_purchase_receipt and
|
||||||
last_purchase_receipt[0].posting_date or "1900-01-01")
|
last_purchase_receipt[0].posting_date or "1900-01-01")
|
||||||
|
|
||||||
if (purchase_order_date > purchase_receipt_date) or \
|
if (purchase_order_date > purchase_receipt_date) or \
|
||||||
@ -797,6 +826,7 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def invalidate_cache_for_item(doc):
|
def invalidate_cache_for_item(doc):
|
||||||
invalidate_cache_for(doc, doc.item_group)
|
invalidate_cache_for(doc, doc.item_group)
|
||||||
|
|
||||||
@ -809,6 +839,7 @@ def invalidate_cache_for_item(doc):
|
|||||||
if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group:
|
if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group:
|
||||||
invalidate_cache_for(doc, doc.old_item_group)
|
invalidate_cache_for(doc, doc.old_item_group)
|
||||||
|
|
||||||
|
|
||||||
def check_stock_uom_with_bin(item, stock_uom):
|
def check_stock_uom_with_bin(item, stock_uom):
|
||||||
if stock_uom == frappe.db.get_value("Item", item, "stock_uom"):
|
if stock_uom == frappe.db.get_value("Item", item, "stock_uom"):
|
||||||
return
|
return
|
||||||
@ -823,7 +854,7 @@ def check_stock_uom_with_bin(item, stock_uom):
|
|||||||
else:
|
else:
|
||||||
bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1)
|
bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1)
|
||||||
for bin in bin_list:
|
for bin in bin_list:
|
||||||
if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 \
|
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):
|
or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom):
|
||||||
matched = False
|
matched = False
|
||||||
break
|
break
|
||||||
@ -832,4 +863,5 @@ def check_stock_uom_with_bin(item, stock_uom):
|
|||||||
frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", (stock_uom, item))
|
frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", (stock_uom, item))
|
||||||
|
|
||||||
if not matched:
|
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)
|
frappe.msgprint (_("`Freeze Stocks Older Than` should be smaller than %d days.") %stock_frozen_limit)
|
||||||
|
|
||||||
# show/hide barcode field
|
# 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})
|
'value': 0 if self.show_barcode_field else 1})
|
||||||
|
|
||||||
self.cant_change_valuation_method()
|
self.cant_change_valuation_method()
|
||||||
|
@ -120,7 +120,7 @@ def process_args(args):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_item_code(barcode=None, serial_no=None):
|
def get_item_code(barcode=None, serial_no=None):
|
||||||
if barcode:
|
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:
|
if not item_code:
|
||||||
frappe.throw(_("No Item with Barcode {0}").format(barcode))
|
frappe.throw(_("No Item with Barcode {0}").format(barcode))
|
||||||
elif serial_no:
|
elif serial_no:
|
||||||
@ -273,7 +273,7 @@ def get_basic_details(args, item):
|
|||||||
if not out[d[1]] or (company and args.company != company):
|
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
|
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)
|
out[fieldname] = item.get(fieldname)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
@ -2,3 +2,4 @@ frappe
|
|||||||
unidecode
|
unidecode
|
||||||
pygithub
|
pygithub
|
||||||
googlemaps
|
googlemaps
|
||||||
|
python-stdnum
|
||||||
|
Loading…
x
Reference in New Issue
Block a user