more message fixes
This commit is contained in:
parent
a6e2ca9d3b
commit
ff93802d58
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt, fmt_money, cstr, cint
|
from frappe.utils import flt, cstr, cint
|
||||||
from frappe import msgprint, throw, _
|
from frappe import msgprint, throw, _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
@ -16,8 +16,8 @@ class Account(Document):
|
|||||||
|
|
||||||
def get_address(self):
|
def get_address(self):
|
||||||
return {'address': frappe.db.get_value(self.master_type, self.master_name, "address")}
|
return {'address': frappe.db.get_value(self.master_type, self.master_name, "address")}
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_master_name()
|
self.validate_master_name()
|
||||||
self.validate_parent()
|
self.validate_parent()
|
||||||
self.validate_duplicate_account()
|
self.validate_duplicate_account()
|
||||||
@ -25,18 +25,18 @@ class Account(Document):
|
|||||||
self.validate_mandatory()
|
self.validate_mandatory()
|
||||||
self.validate_warehouse_account()
|
self.validate_warehouse_account()
|
||||||
self.validate_frozen_accounts_modifier()
|
self.validate_frozen_accounts_modifier()
|
||||||
|
|
||||||
def validate_master_name(self):
|
def validate_master_name(self):
|
||||||
if self.master_type in ('Customer', 'Supplier') or self.account_type == "Warehouse":
|
if self.master_type in ('Customer', 'Supplier') or self.account_type == "Warehouse":
|
||||||
if not self.master_name:
|
if not self.master_name:
|
||||||
msgprint(_("Please enter Master Name once the account is created."))
|
msgprint(_("Please enter Master Name once the account is created."))
|
||||||
elif not frappe.db.exists(self.master_type or self.account_type, self.master_name):
|
elif not frappe.db.exists(self.master_type or self.account_type, self.master_name):
|
||||||
throw(_("Invalid Master Name"))
|
throw(_("Invalid Master Name"))
|
||||||
|
|
||||||
def validate_parent(self):
|
def validate_parent(self):
|
||||||
"""Fetch Parent Details and validation for account not to be created under ledger"""
|
"""Fetch Parent Details and validation for account not to be created under ledger"""
|
||||||
if self.parent_account:
|
if self.parent_account:
|
||||||
par = frappe.db.get_value("Account", self.parent_account,
|
par = frappe.db.get_value("Account", self.parent_account,
|
||||||
["name", "group_or_ledger", "report_type"], as_dict=1)
|
["name", "group_or_ledger", "report_type"], as_dict=1)
|
||||||
if not par:
|
if not par:
|
||||||
throw(_("Parent account does not exists"))
|
throw(_("Parent account does not exists"))
|
||||||
@ -44,46 +44,36 @@ class Account(Document):
|
|||||||
throw(_("You can not assign itself as parent account"))
|
throw(_("You can not assign itself as parent account"))
|
||||||
elif par["group_or_ledger"] != 'Group':
|
elif par["group_or_ledger"] != 'Group':
|
||||||
throw(_("Parent account can not be a ledger"))
|
throw(_("Parent account can not be a ledger"))
|
||||||
|
|
||||||
if par["report_type"]:
|
if par["report_type"]:
|
||||||
self.report_type = par["report_type"]
|
self.report_type = par["report_type"]
|
||||||
|
|
||||||
def validate_duplicate_account(self):
|
def validate_duplicate_account(self):
|
||||||
if self.get('__islocal') or not self.name:
|
if self.get('__islocal') or not self.name:
|
||||||
company_abbr = frappe.db.get_value("Company", self.company, "abbr")
|
company_abbr = frappe.db.get_value("Company", self.company, "abbr")
|
||||||
if frappe.db.exists("Account", (self.account_name + " - " + company_abbr)):
|
if frappe.db.exists("Account", (self.account_name + " - " + company_abbr)):
|
||||||
throw("{name}: {acc_name} {exist}, {rename}".format(**{
|
throw(_("Account {0} already exists").format(self.account_name))
|
||||||
"name": _("Account Name"),
|
|
||||||
"acc_name": self.account_name,
|
|
||||||
"exist": _("already exists"),
|
|
||||||
"rename": _("please rename")
|
|
||||||
}))
|
|
||||||
|
|
||||||
def validate_root_details(self):
|
def validate_root_details(self):
|
||||||
#does not exists parent
|
#does not exists parent
|
||||||
if frappe.db.exists("Account", self.name):
|
if frappe.db.exists("Account", self.name):
|
||||||
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
||||||
throw(_("Root cannot be edited."))
|
throw(_("Root cannot be edited."))
|
||||||
|
|
||||||
def validate_frozen_accounts_modifier(self):
|
def validate_frozen_accounts_modifier(self):
|
||||||
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
|
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
|
||||||
if old_value and old_value != self.freeze_account:
|
if old_value and old_value != self.freeze_account:
|
||||||
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,
|
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,
|
||||||
'frozen_accounts_modifier')
|
'frozen_accounts_modifier')
|
||||||
if not frozen_accounts_modifier or \
|
if not frozen_accounts_modifier or \
|
||||||
frozen_accounts_modifier not in frappe.user.get_roles():
|
frozen_accounts_modifier not in frappe.user.get_roles():
|
||||||
throw(_("You are not authorized to set Frozen value"))
|
throw(_("You are not authorized to set Frozen value"))
|
||||||
|
|
||||||
def convert_group_to_ledger(self):
|
def convert_group_to_ledger(self):
|
||||||
if self.check_if_child_exists():
|
if self.check_if_child_exists():
|
||||||
throw("{acc}: {account_name} {child}. {msg}".format(**{
|
throw(_("Account with child nodes cannot be converted to ledger"))
|
||||||
"acc": _("Account"),
|
|
||||||
"account_name": self.name,
|
|
||||||
"child": _("has existing child"),
|
|
||||||
"msg": _("You can not convert this account to ledger")
|
|
||||||
}))
|
|
||||||
elif self.check_gle_exists():
|
elif self.check_gle_exists():
|
||||||
throw(_("Account with existing transaction can not be converted to ledger."))
|
throw(_("Account with existing transaction cannot be converted to ledger"))
|
||||||
else:
|
else:
|
||||||
self.group_or_ledger = 'Ledger'
|
self.group_or_ledger = 'Ledger'
|
||||||
self.save()
|
self.save()
|
||||||
@ -104,17 +94,17 @@ class Account(Document):
|
|||||||
return frappe.db.get_value("GL Entry", {"account": self.name})
|
return frappe.db.get_value("GL Entry", {"account": self.name})
|
||||||
|
|
||||||
def check_if_child_exists(self):
|
def check_if_child_exists(self):
|
||||||
return frappe.db.sql("""select name from `tabAccount` where parent_account = %s
|
return frappe.db.sql("""select name from `tabAccount` where parent_account = %s
|
||||||
and docstatus != 2""", self.name)
|
and docstatus != 2""", self.name)
|
||||||
|
|
||||||
def validate_mandatory(self):
|
def validate_mandatory(self):
|
||||||
if not self.report_type:
|
if not self.report_type:
|
||||||
throw(_("Report Type is mandatory"))
|
throw(_("Report Type is mandatory"))
|
||||||
|
|
||||||
def validate_warehouse_account(self):
|
def validate_warehouse_account(self):
|
||||||
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.account_type == "Warehouse":
|
if self.account_type == "Warehouse":
|
||||||
old_warehouse = cstr(frappe.db.get_value("Account", self.name, "master_name"))
|
old_warehouse = cstr(frappe.db.get_value("Account", self.name, "master_name"))
|
||||||
if old_warehouse != cstr(self.master_name):
|
if old_warehouse != cstr(self.master_name):
|
||||||
@ -124,10 +114,10 @@ class Account(Document):
|
|||||||
self.validate_warehouse(self.master_name)
|
self.validate_warehouse(self.master_name)
|
||||||
else:
|
else:
|
||||||
throw(_("Master Name is mandatory if account type is Warehouse"))
|
throw(_("Master Name is mandatory if account type is Warehouse"))
|
||||||
|
|
||||||
def validate_warehouse(self, warehouse):
|
def validate_warehouse(self, warehouse):
|
||||||
if frappe.db.get_value("Stock Ledger Entry", {"warehouse": warehouse}):
|
if frappe.db.get_value("Stock Ledger Entry", {"warehouse": warehouse}):
|
||||||
throw(_("Stock transactions exist against warehouse ") + warehouse +
|
throw(_("Stock transactions exist against warehouse ") + warehouse +
|
||||||
_(" .You can not assign / modify / remove Master Name"))
|
_(" .You can not assign / modify / remove Master Name"))
|
||||||
|
|
||||||
def update_nsm_model(self):
|
def update_nsm_model(self):
|
||||||
@ -135,73 +125,67 @@ class Account(Document):
|
|||||||
import frappe
|
import frappe
|
||||||
import frappe.utils.nestedset
|
import frappe.utils.nestedset
|
||||||
frappe.utils.nestedset.update_nsm(self)
|
frappe.utils.nestedset.update_nsm(self)
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
self.update_nsm_model()
|
self.update_nsm_model()
|
||||||
|
|
||||||
def get_authorized_user(self):
|
def get_authorized_user(self):
|
||||||
# Check logged-in user is authorized
|
# Check logged-in user is authorized
|
||||||
if frappe.db.get_value('Accounts Settings', None, 'credit_controller') \
|
if frappe.db.get_value('Accounts Settings', None, 'credit_controller') \
|
||||||
in frappe.user.get_roles():
|
in frappe.user.get_roles():
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def check_credit_limit(self, total_outstanding):
|
def check_credit_limit(self, total_outstanding):
|
||||||
# Get credit limit
|
# Get credit limit
|
||||||
credit_limit_from = 'Customer'
|
credit_limit_from = 'Customer'
|
||||||
|
|
||||||
cr_limit = frappe.db.sql("""select t1.credit_limit from tabCustomer t1, `tabAccount` t2
|
cr_limit = frappe.db.sql("""select t1.credit_limit from tabCustomer t1, `tabAccount` t2
|
||||||
where t2.name=%s and t1.name = t2.master_name""", self.name)
|
where t2.name=%s and t1.name = t2.master_name""", self.name)
|
||||||
credit_limit = cr_limit and flt(cr_limit[0][0]) or 0
|
credit_limit = cr_limit and flt(cr_limit[0][0]) or 0
|
||||||
if not credit_limit:
|
if not credit_limit:
|
||||||
credit_limit = frappe.db.get_value('Company', self.company, 'credit_limit')
|
credit_limit = frappe.db.get_value('Company', self.company, 'credit_limit')
|
||||||
credit_limit_from = 'Company'
|
credit_limit_from = 'Company'
|
||||||
|
|
||||||
# If outstanding greater than credit limit and not authorized person raise exception
|
# If outstanding greater than credit limit and not authorized person raise exception
|
||||||
if credit_limit > 0 and flt(total_outstanding) > credit_limit \
|
if credit_limit > 0 and flt(total_outstanding) > credit_limit \
|
||||||
and not self.get_authorized_user():
|
and not self.get_authorized_user():
|
||||||
throw("""Total Outstanding amount (%s) for <b>%s</b> can not be \
|
throw(_("{0} Credit limit {0} crossed").format(_(credit_limit_from), credit_limit))
|
||||||
greater than credit limit (%s). To change your credit limit settings, \
|
|
||||||
please update in the <b>%s</b> master""" % (fmt_money(total_outstanding),
|
|
||||||
self.name, fmt_money(credit_limit), credit_limit_from))
|
|
||||||
|
|
||||||
def validate_trash(self):
|
def validate_trash(self):
|
||||||
"""checks gl entries and if child exists"""
|
"""checks gl entries and if child exists"""
|
||||||
if not self.parent_account:
|
if not self.parent_account:
|
||||||
throw(_("Root account can not be deleted"))
|
throw(_("Root account can not be deleted"))
|
||||||
|
|
||||||
if self.check_gle_exists():
|
if self.check_gle_exists():
|
||||||
throw("""Account with existing transaction (Sales Invoice / Purchase Invoice / \
|
throw(_("Account with existing transaction can not be deleted"))
|
||||||
Journal Voucher) can not be deleted""")
|
|
||||||
if self.check_if_child_exists():
|
if self.check_if_child_exists():
|
||||||
throw(_("Child account exists for this account. You can not delete this account."))
|
throw(_("Child account exists for this account. You can not delete this account."))
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
self.validate_trash()
|
self.validate_trash()
|
||||||
self.update_nsm_model()
|
self.update_nsm_model()
|
||||||
|
|
||||||
def before_rename(self, old, new, merge=False):
|
def before_rename(self, old, new, merge=False):
|
||||||
# Add company abbr if not provided
|
# Add company abbr if not provided
|
||||||
from erpnext.setup.doctype.company.company import get_name_with_abbr
|
from erpnext.setup.doctype.company.company import get_name_with_abbr
|
||||||
new_account = get_name_with_abbr(new, self.company)
|
new_account = get_name_with_abbr(new, self.company)
|
||||||
|
|
||||||
# Validate properties before merging
|
# Validate properties before merging
|
||||||
if merge:
|
if merge:
|
||||||
if not frappe.db.exists("Account", new):
|
if not frappe.db.exists("Account", new):
|
||||||
throw(_("Account ") + new +_(" does not exists"))
|
throw(_("Account ") + new +_(" does not exists"))
|
||||||
|
|
||||||
val = list(frappe.db.get_value("Account", new_account,
|
val = list(frappe.db.get_value("Account", new_account,
|
||||||
["group_or_ledger", "report_type", "company"]))
|
["group_or_ledger", "report_type", "company"]))
|
||||||
|
|
||||||
if val != [self.group_or_ledger, self.report_type, self.company]:
|
if val != [self.group_or_ledger, self.report_type, self.company]:
|
||||||
throw(_("""Merging is only possible if following \
|
throw(_("""Merging is only possible if following properties are same in both records. Group or Ledger, Report Type, Company"""))
|
||||||
properties are same in both records.
|
|
||||||
Group or Ledger, Report Type, Company"""))
|
|
||||||
|
|
||||||
return new_account
|
return new_account
|
||||||
|
|
||||||
def after_rename(self, old, new, merge=False):
|
def after_rename(self, old, new, merge=False):
|
||||||
if not merge:
|
if not merge:
|
||||||
frappe.db.set_value("Account", new, "account_name",
|
frappe.db.set_value("Account", new, "account_name",
|
||||||
" - ".join(new.split(" - ")[:-1]))
|
" - ".join(new.split(" - ")[:-1]))
|
||||||
else:
|
else:
|
||||||
from frappe.utils.nestedset import rebuild_tree
|
from frappe.utils.nestedset import rebuild_tree
|
||||||
@ -209,15 +193,15 @@ class Account(Document):
|
|||||||
|
|
||||||
def get_master_name(doctype, txt, searchfield, start, page_len, filters):
|
def get_master_name(doctype, txt, searchfield, start, page_len, filters):
|
||||||
conditions = (" and company='%s'"% filters["company"].replace("'", "\'")) if doctype == "Warehouse" else ""
|
conditions = (" and company='%s'"% filters["company"].replace("'", "\'")) if doctype == "Warehouse" else ""
|
||||||
|
|
||||||
return frappe.db.sql("""select name from `tab%s` where %s like %s %s
|
return frappe.db.sql("""select name from `tab%s` where %s like %s %s
|
||||||
order by name limit %s, %s""" %
|
order by name limit %s, %s""" %
|
||||||
(filters["master_type"], searchfield, "%s", conditions, "%s", "%s"),
|
(filters["master_type"], searchfield, "%s", conditions, "%s", "%s"),
|
||||||
("%%%s%%" % txt, start, page_len), as_list=1)
|
("%%%s%%" % txt, start, page_len), as_list=1)
|
||||||
|
|
||||||
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
|
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
|
||||||
return frappe.db.sql("""select name from tabAccount
|
return frappe.db.sql("""select name from tabAccount
|
||||||
where group_or_ledger = 'Group' and docstatus != 2 and company = %s
|
where group_or_ledger = 'Group' and docstatus != 2 and company = %s
|
||||||
and %s like %s order by name limit %s, %s""" %
|
and %s like %s order by name limit %s, %s""" %
|
||||||
("%s", searchfield, "%s", "%s", "%s"),
|
("%s", searchfield, "%s", "%s", "%s"),
|
||||||
(filters["company"], "%%%s%%" % txt, start, page_len), as_list=1)
|
(filters["company"], "%%%s%%" % txt, start, page_len), as_list=1)
|
||||||
|
@ -9,46 +9,42 @@ from frappe.model.document import Document
|
|||||||
|
|
||||||
class CForm(Document):
|
class CForm(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
"""Validate invoice that c-form is applicable
|
"""Validate invoice that c-form is applicable
|
||||||
and no other c-form is received for that"""
|
and no other c-form is received for that"""
|
||||||
|
|
||||||
for d in self.get('invoice_details'):
|
for d in self.get('invoice_details'):
|
||||||
if d.invoice_no:
|
if d.invoice_no:
|
||||||
inv = frappe.db.sql("""select c_form_applicable, c_form_no from
|
inv = frappe.db.sql("""select c_form_applicable, c_form_no from
|
||||||
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
|
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
|
||||||
|
|
||||||
if not inv:
|
if inv[0][0] != 'Yes':
|
||||||
frappe.throw("""Invoice: %s is not exists in the system or
|
|
||||||
is not submitted, please check.""" % d.invoice_no)
|
|
||||||
|
|
||||||
elif inv[0][0] != 'Yes':
|
|
||||||
frappe.throw("C-form is not applicable for Invoice: %s" % d.invoice_no)
|
frappe.throw("C-form is not applicable for Invoice: %s" % d.invoice_no)
|
||||||
|
|
||||||
elif inv[0][1] and inv[0][1] != self.name:
|
elif inv[0][1] and inv[0][1] != self.name:
|
||||||
frappe.throw("""Invoice %s is tagged in another C-form: %s.
|
frappe.throw("""Invoice %s is tagged in another C-form: %s.
|
||||||
If you want to change C-form no for this invoice,
|
If you want to change C-form no for this invoice,
|
||||||
please remove invoice no from the previous c-form and then try again""" %
|
please remove invoice no from the previous c-form and then try again""" %
|
||||||
(d.invoice_no, inv[0][1]))
|
(d.invoice_no, inv[0][1]))
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
""" Update C-Form No on invoices"""
|
""" Update C-Form No on invoices"""
|
||||||
self.set_total_invoiced_amount()
|
self.set_total_invoiced_amount()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.set_cform_in_sales_invoices()
|
self.set_cform_in_sales_invoices()
|
||||||
|
|
||||||
def before_cancel(self):
|
def before_cancel(self):
|
||||||
# remove cform reference
|
# remove cform reference
|
||||||
frappe.db.sql("""update `tabSales Invoice` set c_form_no=null where c_form_no=%s""", self.name)
|
frappe.db.sql("""update `tabSales Invoice` set c_form_no=null where c_form_no=%s""", self.name)
|
||||||
|
|
||||||
def set_cform_in_sales_invoices(self):
|
def set_cform_in_sales_invoices(self):
|
||||||
inv = [d.invoice_no for d in self.get('invoice_details')]
|
inv = [d.invoice_no for d in self.get('invoice_details')]
|
||||||
if inv:
|
if inv:
|
||||||
frappe.db.sql("""update `tabSales Invoice` set c_form_no=%s, modified=%s where name in (%s)""" %
|
frappe.db.sql("""update `tabSales Invoice` set c_form_no=%s, modified=%s where name in (%s)""" %
|
||||||
('%s', '%s', ', '.join(['%s'] * len(inv))), tuple([self.name, self.modified] + inv))
|
('%s', '%s', ', '.join(['%s'] * len(inv))), tuple([self.name, self.modified] + inv))
|
||||||
|
|
||||||
frappe.db.sql("""update `tabSales Invoice` set c_form_no = null, modified = %s
|
frappe.db.sql("""update `tabSales Invoice` set c_form_no = null, modified = %s
|
||||||
where name not in (%s) and ifnull(c_form_no, '') = %s""" %
|
where name not in (%s) and ifnull(c_form_no, '') = %s""" %
|
||||||
('%s', ', '.join(['%s']*len(inv)), '%s'), tuple([self.modified] + inv + [self.name]))
|
('%s', ', '.join(['%s']*len(inv)), '%s'), tuple([self.modified] + inv + [self.name]))
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
||||||
@ -60,7 +56,7 @@ class CForm(Document):
|
|||||||
def get_invoice_details(self, invoice_no):
|
def get_invoice_details(self, invoice_no):
|
||||||
""" Pull details from invoices for referrence """
|
""" Pull details from invoices for referrence """
|
||||||
|
|
||||||
inv = frappe.db.get_value("Sales Invoice", invoice_no,
|
inv = frappe.db.get_value("Sales Invoice", invoice_no,
|
||||||
["posting_date", "territory", "net_total", "grand_total"], as_dict=True)
|
["posting_date", "territory", "net_total", "grand_total"], as_dict=True)
|
||||||
return {
|
return {
|
||||||
'invoice_date' : inv.posting_date,
|
'invoice_date' : inv.posting_date,
|
||||||
@ -72,9 +68,9 @@ class CForm(Document):
|
|||||||
def get_invoice_nos(doctype, txt, searchfield, start, page_len, filters):
|
def get_invoice_nos(doctype, txt, searchfield, start, page_len, filters):
|
||||||
from erpnext.utilities import build_filter_conditions
|
from erpnext.utilities import build_filter_conditions
|
||||||
conditions, filter_values = build_filter_conditions(filters)
|
conditions, filter_values = build_filter_conditions(filters)
|
||||||
|
|
||||||
return frappe.db.sql("""select name from `tabSales Invoice` where docstatus = 1
|
return frappe.db.sql("""select name from `tabSales Invoice` where docstatus = 1
|
||||||
and c_form_applicable = 'Yes' and ifnull(c_form_no, '') = '' %s
|
and c_form_applicable = 'Yes' and ifnull(c_form_no, '') = '' %s
|
||||||
and %s like %s order by name limit %s, %s""" %
|
and %s like %s order by name limit %s, %s""" %
|
||||||
(conditions, searchfield, "%s", "%s", "%s"),
|
(conditions, searchfield, "%s", "%s", "%s"),
|
||||||
tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
|
tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
|
||||||
|
@ -8,13 +8,13 @@ from erpnext.accounts.report.accounts_receivable.accounts_receivable import get_
|
|||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
|
|
||||||
columns = get_columns()
|
columns = get_columns()
|
||||||
entries = get_entries(filters)
|
entries = get_entries(filters)
|
||||||
invoice_posting_date_map = get_invoice_posting_date_map(filters)
|
invoice_posting_date_map = get_invoice_posting_date_map(filters)
|
||||||
against_date = ""
|
against_date = ""
|
||||||
outstanding_amount = 0.0
|
outstanding_amount = 0.0
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for d in entries:
|
for d in entries:
|
||||||
if d.against_voucher:
|
if d.against_voucher:
|
||||||
@ -23,67 +23,66 @@ def execute(filters=None):
|
|||||||
else:
|
else:
|
||||||
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
|
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
|
||||||
outstanding_amount = d.credit or -1*d.debit
|
outstanding_amount = d.credit or -1*d.debit
|
||||||
|
|
||||||
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice,
|
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice,
|
||||||
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
|
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
|
||||||
|
|
||||||
if d.against_voucher or d.against_invoice:
|
if d.against_voucher or d.against_invoice:
|
||||||
row += get_ageing_data(d.posting_date, against_date, outstanding_amount)
|
row += get_ageing_data(d.posting_date, against_date, outstanding_amount)
|
||||||
else:
|
else:
|
||||||
row += ["", "", "", "", ""]
|
row += ["", "", "", "", ""]
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
def get_columns():
|
def get_columns():
|
||||||
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
|
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
|
||||||
"Posting Date:Date:100", "Against Invoice:Link/Purchase Invoice:130",
|
"Posting Date:Date:100", "Against Invoice:Link/Purchase Invoice:130",
|
||||||
"Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120",
|
"Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120",
|
||||||
"Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40",
|
"Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40",
|
||||||
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
|
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_conditions(filters):
|
def get_conditions(filters):
|
||||||
conditions = ""
|
conditions = ""
|
||||||
party_accounts = []
|
party_accounts = []
|
||||||
|
|
||||||
if filters.get("account"):
|
if filters.get("account"):
|
||||||
party_accounts = [filters["account"]]
|
party_accounts = [filters["account"]]
|
||||||
else:
|
else:
|
||||||
cond = filters.get("company") and (" and company = '%s'" %
|
cond = filters.get("company") and (" and company = '%s'" %
|
||||||
filters["company"].replace("'", "\'")) or ""
|
filters["company"].replace("'", "\'")) or ""
|
||||||
|
|
||||||
if filters.get("payment_type") == "Incoming":
|
if filters.get("payment_type") == "Incoming":
|
||||||
cond += " and master_type = 'Customer'"
|
cond += " and master_type = 'Customer'"
|
||||||
else:
|
else:
|
||||||
cond += " and master_type = 'Supplier'"
|
cond += " and master_type = 'Supplier'"
|
||||||
|
|
||||||
party_accounts = frappe.db.sql_list("""select name from `tabAccount`
|
party_accounts = frappe.db.sql_list("""select name from `tabAccount`
|
||||||
where ifnull(master_name, '')!='' and docstatus < 2 %s""" % cond)
|
where ifnull(master_name, '')!='' and docstatus < 2 %s""" % cond)
|
||||||
|
|
||||||
if party_accounts:
|
if party_accounts:
|
||||||
conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(party_accounts)))
|
conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(party_accounts)))
|
||||||
else:
|
else:
|
||||||
msgprint(_("No Customer or Supplier Accounts found. Accounts are identified based on \
|
msgprint(_("No Customer or Supplier Accounts found"), raise_exception=1)
|
||||||
'Master Type' value in account record."), raise_exception=1)
|
|
||||||
|
|
||||||
if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
|
if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
|
||||||
if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
|
if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
|
||||||
|
|
||||||
return conditions, party_accounts
|
return conditions, party_accounts
|
||||||
|
|
||||||
def get_entries(filters):
|
def get_entries(filters):
|
||||||
conditions, party_accounts = get_conditions(filters)
|
conditions, party_accounts = get_conditions(filters)
|
||||||
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date,
|
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date,
|
||||||
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
|
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
|
||||||
jv.cheque_no, jv.cheque_date, jv.remark
|
jv.cheque_no, jv.cheque_date, jv.remark
|
||||||
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
|
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
|
||||||
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
|
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
|
||||||
(conditions), tuple(party_accounts), as_dict=1)
|
(conditions), tuple(party_accounts), as_dict=1)
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
|
|
||||||
def get_invoice_posting_date_map(filters):
|
def get_invoice_posting_date_map(filters):
|
||||||
invoice_posting_date_map = {}
|
invoice_posting_date_map = {}
|
||||||
if filters.get("payment_type") == "Incoming":
|
if filters.get("payment_type") == "Incoming":
|
||||||
@ -93,4 +92,4 @@ def get_invoice_posting_date_map(filters):
|
|||||||
for t in frappe.db.sql("""select name, posting_date from `tabPurchase Invoice`"""):
|
for t in frappe.db.sql("""select name, posting_date from `tabPurchase Invoice`"""):
|
||||||
invoice_posting_date_map[t[0]] = t[1]
|
invoice_posting_date_map[t[0]] = t[1]
|
||||||
|
|
||||||
return invoice_posting_date_map
|
return invoice_posting_date_map
|
||||||
|
@ -147,7 +147,7 @@ class PurchaseCommon(BuyingController):
|
|||||||
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
||||||
status = 'Stopped'""" % (doctype, '%s'), docname)
|
status = 'Stopped'""" % (doctype, '%s'), docname)
|
||||||
if stopped:
|
if stopped:
|
||||||
frappe.throw("{0} {1} status is 'Stopped'".format(doctype, docname), frappe.InvalidStatusError)
|
frappe.throw(_("{0} {1} status is 'Stopped'").format(doctype, docname), frappe.InvalidStatusError)
|
||||||
|
|
||||||
def check_docstatus(self, check, doctype, docname, detail_doctype = ''):
|
def check_docstatus(self, check, doctype, docname, detail_doctype = ''):
|
||||||
if check == 'Next':
|
if check == 'Next':
|
||||||
|
@ -9,23 +9,23 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
|
|||||||
this.frm.fields_dict.reports_to.get_query = function(doc, cdt, cdn) {
|
this.frm.fields_dict.reports_to.get_query = function(doc, cdt, cdn) {
|
||||||
return { query: "erpnext.controllers.queries.employee_query"} }
|
return { query: "erpnext.controllers.queries.employee_query"} }
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function() {
|
onload: function() {
|
||||||
this.setup_leave_approver_select();
|
this.setup_leave_approver_select();
|
||||||
this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"],
|
this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"],
|
||||||
frappe.boot.sysdefaults.country==="India");
|
frappe.boot.sysdefaults.country==="India");
|
||||||
if(this.frm.doc.__islocal) this.frm.set_value("employee_name", "");
|
if(this.frm.doc.__islocal) this.frm.set_value("employee_name", "");
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
erpnext.hide_naming_series();
|
erpnext.hide_naming_series();
|
||||||
if(!this.frm.doc.__islocal) {
|
if(!this.frm.doc.__islocal) {
|
||||||
cur_frm.add_custom_button(__('Make Salary Structure'), function() {
|
cur_frm.add_custom_button(__('Make Salary Structure'), function() {
|
||||||
me.make_salary_structure(this); });
|
me.make_salary_structure(this); });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setup_leave_approver_select: function() {
|
setup_leave_approver_select: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
@ -33,21 +33,21 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
var df = frappe.meta.get_docfield("Employee Leave Approver", "leave_approver",
|
var df = frappe.meta.get_docfield("Employee Leave Approver", "leave_approver",
|
||||||
me.frm.doc.name);
|
me.frm.doc.name);
|
||||||
df.options = $.map(r.message, function(user) {
|
df.options = $.map(r.message, function(user) {
|
||||||
return {value: user, label: frappe.user_info(user).fullname};
|
return {value: user, label: frappe.user_info(user).fullname};
|
||||||
});
|
});
|
||||||
me.frm.fields_dict.employee_leave_approvers.refresh();
|
me.frm.fields_dict.employee_leave_approvers.refresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
date_of_birth: function() {
|
date_of_birth: function() {
|
||||||
return cur_frm.call({
|
return cur_frm.call({
|
||||||
method: "get_retirement_date",
|
method: "get_retirement_date",
|
||||||
args: {date_of_birth: this.frm.doc.date_of_birth}
|
args: {date_of_birth: this.frm.doc.date_of_birth}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
salutation: function() {
|
salutation: function() {
|
||||||
if(this.frm.doc.salutation) {
|
if(this.frm.doc.salutation) {
|
||||||
this.frm.set_value("gender", {
|
this.frm.set_value("gender", {
|
||||||
@ -56,16 +56,12 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
|
|||||||
}[this.frm.doc.salutation]);
|
}[this.frm.doc.salutation]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
make_salary_structure: function(btn) {
|
make_salary_structure: function(btn) {
|
||||||
var me = this;
|
var me = this;
|
||||||
this.validate_salary_structure(btn, function(r) {
|
this.validate_salary_structure(btn, function(r) {
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
msgprint(__("Employee {0}:\
|
msgprint(__("Active Salary Sructure already exists for Employee {0}", [me.frm.doc.name]));
|
||||||
An active Salary Structure already exists. \
|
|
||||||
If you want to create new one, please ensure that no active \
|
|
||||||
Salary Structure exists for this Employee. \
|
|
||||||
Go to the active Salary Structure and set \"Is Active\" = \"No\"", [me.frm.doc.name]));
|
|
||||||
} else if(!r.exc) {
|
} else if(!r.exc) {
|
||||||
frappe.model.map({
|
frappe.model.map({
|
||||||
source: me.frm.doc,
|
source: me.frm.doc,
|
||||||
@ -74,7 +70,7 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_salary_structure: function(btn, callback) {
|
validate_salary_structure: function(btn, callback) {
|
||||||
var me = this;
|
var me = this;
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
|
@ -63,7 +63,7 @@ class LeaveAllocation(Document):
|
|||||||
cf = cf and cint(cf[0][0]) or 0
|
cf = cf and cint(cf[0][0]) or 0
|
||||||
if not cf:
|
if not cf:
|
||||||
frappe.db.set(self,'carry_forward',0)
|
frappe.db.set(self,'carry_forward',0)
|
||||||
frappe.throw("Cannot carry forward {0}".format(self.leave_type))
|
frappe.throw(_("Cannot carry forward {0}").format(self.leave_type))
|
||||||
|
|
||||||
def get_carry_forwarded_leaves(self):
|
def get_carry_forwarded_leaves(self):
|
||||||
if self.carry_forward:
|
if self.carry_forward:
|
||||||
|
@ -144,8 +144,7 @@ class LeaveApplication(DocListController):
|
|||||||
def validate_max_days(self):
|
def validate_max_days(self):
|
||||||
max_days = frappe.db.get_value("Leave Type", self.leave_type, "max_days_allowed")
|
max_days = frappe.db.get_value("Leave Type", self.leave_type, "max_days_allowed")
|
||||||
if max_days and self.total_leave_days > max_days:
|
if max_days and self.total_leave_days > max_days:
|
||||||
frappe.throw("Sorry ! You cannot apply for %s for more than %s days" %
|
frappe.throw(_("Leave of type {0} cannot be longer than {1}").format(self.leave_type, max_days))
|
||||||
(self.leave_type, max_days))
|
|
||||||
|
|
||||||
def validate_leave_approver(self):
|
def validate_leave_approver(self):
|
||||||
employee = frappe.get_doc("Employee", self.employee)
|
employee = frappe.get_doc("Employee", self.employee)
|
||||||
|
@ -130,7 +130,7 @@ class SalarySlip(TransactionBase):
|
|||||||
(self.month, self.fiscal_year, self.employee, self.name))
|
(self.month, self.fiscal_year, self.employee, self.name))
|
||||||
if ret_exist:
|
if ret_exist:
|
||||||
self.employee = ''
|
self.employee = ''
|
||||||
frappe.throw("Salary Slip of employee {0} already created for this month".format(self.employee))
|
frappe.throw(_("Salary Slip of employee {0} already created for this month").format(self.employee))
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
from frappe.utils import money_in_words
|
from frappe.utils import money_in_words
|
||||||
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from frappe.utils import cstr, flt, nowdate
|
from frappe.utils import cstr, flt, nowdate
|
||||||
from frappe import msgprint, _
|
from frappe import _
|
||||||
|
|
||||||
class OverProductionError(frappe.ValidationError): pass
|
class OverProductionError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@ -34,9 +34,7 @@ class ProductionOrder(Document):
|
|||||||
and is_active=1 and item=%s"""
|
and is_active=1 and item=%s"""
|
||||||
, (self.bom_no, self.production_item), as_dict =1)
|
, (self.bom_no, self.production_item), as_dict =1)
|
||||||
if not bom:
|
if not bom:
|
||||||
frappe.throw("""Incorrect BOM: %s entered.
|
frappe.throw(_("BOM {0} is not active or not submitted").format(self.bom_no))
|
||||||
May be BOM not exists or inactive or not submitted
|
|
||||||
or for some other item.""" % cstr(self.bom_no))
|
|
||||||
|
|
||||||
def validate_sales_order(self):
|
def validate_sales_order(self):
|
||||||
if self.sales_order:
|
if self.sales_order:
|
||||||
@ -44,7 +42,7 @@ class ProductionOrder(Document):
|
|||||||
where name=%s and docstatus = 1""", self.sales_order, as_dict=1)[0]
|
where name=%s and docstatus = 1""", self.sales_order, as_dict=1)[0]
|
||||||
|
|
||||||
if not so.name:
|
if not so.name:
|
||||||
frappe.throw("Sales Order: %s is not valid" % self.sales_order)
|
frappe.throw(_("Sales Order {0} is not valid") % self.sales_order)
|
||||||
|
|
||||||
if not self.expected_delivery_date:
|
if not self.expected_delivery_date:
|
||||||
self.expected_delivery_date = so.delivery_date
|
self.expected_delivery_date = so.delivery_date
|
||||||
@ -115,8 +113,7 @@ class ProductionOrder(Document):
|
|||||||
stock_entry = frappe.db.sql("""select name from `tabStock Entry`
|
stock_entry = frappe.db.sql("""select name from `tabStock Entry`
|
||||||
where production_order = %s and docstatus = 1""", self.name)
|
where production_order = %s and docstatus = 1""", self.name)
|
||||||
if stock_entry:
|
if stock_entry:
|
||||||
frappe.throw("""Submitted Stock Entry %s exists against this production order.
|
frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0]))
|
||||||
Hence can not be cancelled.""" % stock_entry[0][0])
|
|
||||||
|
|
||||||
frappe.db.set(self,'status', 'Cancelled')
|
frappe.db.set(self,'status', 'Cancelled')
|
||||||
self.update_planned_qty(-self.qty)
|
self.update_planned_qty(-self.qty)
|
||||||
|
@ -152,21 +152,17 @@ class ProductionPlanningTool(Document):
|
|||||||
for d in self.get('pp_details'):
|
for d in self.get('pp_details'):
|
||||||
self.validate_bom_no(d)
|
self.validate_bom_no(d)
|
||||||
if not flt(d.planned_qty):
|
if not flt(d.planned_qty):
|
||||||
frappe.throw("Please Enter Planned Qty for item: %s at row no: %s" %
|
frappe.throw(_("Please enter Planned Qty for Item {0} at row {1}").format(d.item_code, d.idx))
|
||||||
(d.item_code, d.idx))
|
|
||||||
|
|
||||||
def validate_bom_no(self, d):
|
def validate_bom_no(self, d):
|
||||||
if not d.bom_no:
|
if not d.bom_no:
|
||||||
frappe.throw("Please enter bom no for item: %s at row no: %s" %
|
frappe.throw(_("Please enter BOM for Item {0} at row {1}").format(d.item_code, d.idx))
|
||||||
(d.item_code, d.idx))
|
|
||||||
else:
|
else:
|
||||||
bom = frappe.db.sql("""select name from `tabBOM` where name = %s and item = %s
|
bom = frappe.db.sql("""select name from `tabBOM` where name = %s and item = %s
|
||||||
and docstatus = 1 and is_active = 1""",
|
and docstatus = 1 and is_active = 1""",
|
||||||
(d.bom_no, d.item_code), as_dict = 1)
|
(d.bom_no, d.item_code), as_dict = 1)
|
||||||
if not bom:
|
if not bom:
|
||||||
frappe.throw("""Incorrect BOM No: %s entered for item: %s at row no: %s
|
frappe.throw(_("Incorrect or Inactive BOM {0} for Item {1} at row {2}").format(d.bom_no, d.item_code, d.idx))
|
||||||
May be BOM is inactive or for other item or does not exists in the system""" %
|
|
||||||
(d.bom_no, d.item_doce, d.idx))
|
|
||||||
|
|
||||||
def raise_production_order(self):
|
def raise_production_order(self):
|
||||||
"""It will raise production order (Draft) for all distinct FG items"""
|
"""It will raise production order (Draft) for all distinct FG items"""
|
||||||
|
@ -10,7 +10,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
if(this.frm.doc.__islocal) {
|
if(this.frm.doc.__islocal) {
|
||||||
var today = get_today(),
|
var today = get_today(),
|
||||||
currency = frappe.defaults.get_user_default("currency");
|
currency = frappe.defaults.get_user_default("currency");
|
||||||
|
|
||||||
$.each({
|
$.each({
|
||||||
posting_date: today,
|
posting_date: today,
|
||||||
due_date: today,
|
due_date: today,
|
||||||
@ -24,18 +24,18 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}, function(fieldname, value) {
|
}, function(fieldname, value) {
|
||||||
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
|
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
|
||||||
me.frm.set_value(fieldname, value);
|
me.frm.set_value(fieldname, value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.other_fname) {
|
if(this.other_fname) {
|
||||||
this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals;
|
this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.fname) {
|
if(this.fname) {
|
||||||
this[this.fname + "_remove"] = this.calculate_taxes_and_totals;
|
this[this.fname + "_remove"] = this.calculate_taxes_and_totals;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onload_post_render: function() {
|
onload_post_render: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.is_pos) {
|
if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.is_pos) {
|
||||||
@ -55,7 +55,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
this.frm.clear_custom_buttons();
|
this.frm.clear_custom_buttons();
|
||||||
erpnext.hide_naming_series();
|
erpnext.hide_naming_series();
|
||||||
@ -77,7 +77,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
icon = "icon-file-text";
|
icon = "icon-file-text";
|
||||||
}
|
}
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
this.$pos_btn = this.frm.appframe.add_button(btn_label, function() {
|
this.$pos_btn = this.frm.appframe.add_button(btn_label, function() {
|
||||||
me.toggle_pos();
|
me.toggle_pos();
|
||||||
}, icon);
|
}, icon);
|
||||||
@ -87,7 +87,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
// Check whether it is Selling or Buying cycle
|
// Check whether it is Selling or Buying cycle
|
||||||
var price_list = frappe.meta.has_field(cur_frm.doc.doctype, "selling_price_list") ?
|
var price_list = frappe.meta.has_field(cur_frm.doc.doctype, "selling_price_list") ?
|
||||||
this.frm.doc.selling_price_list : this.frm.doc.buying_price_list;
|
this.frm.doc.selling_price_list : this.frm.doc.buying_price_list;
|
||||||
|
|
||||||
if (!price_list)
|
if (!price_list)
|
||||||
msgprint(__("Please select Price List"))
|
msgprint(__("Please select Price List"))
|
||||||
else {
|
else {
|
||||||
@ -109,8 +109,8 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
this.frm.refresh();
|
this.frm.refresh();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
item_code: function(doc, cdt, cdn) {
|
item_code: function(doc, cdt, cdn) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var item = frappe.get_doc(cdt, cdn);
|
var item = frappe.get_doc(cdt, cdn);
|
||||||
@ -152,7 +152,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
serial_no: function(doc, cdt, cdn) {
|
serial_no: function(doc, cdt, cdn) {
|
||||||
var me = this;
|
var me = this;
|
||||||
@ -169,7 +169,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
|
var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
|
||||||
|
|
||||||
serial_nos = serial_nos.trim().split('\n');
|
serial_nos = serial_nos.trim().split('\n');
|
||||||
|
|
||||||
// Trim each string and push unique string to new list
|
// Trim each string and push unique string to new list
|
||||||
for (var x=0; x<=serial_nos.length - 1; x++) {
|
for (var x=0; x<=serial_nos.length - 1; x++) {
|
||||||
if (serial_nos[x].trim() != "" && sr_no.indexOf(serial_nos[x].trim()) == -1) {
|
if (serial_nos[x].trim() != "" && sr_no.indexOf(serial_nos[x].trim()) == -1) {
|
||||||
@ -187,18 +187,18 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
validate: function() {
|
validate: function() {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function() {
|
company: function() {
|
||||||
if(this.frm.doc.company && this.frm.fields_dict.currency) {
|
if(this.frm.doc.company && this.frm.fields_dict.currency) {
|
||||||
var company_currency = this.get_company_currency();
|
var company_currency = this.get_company_currency();
|
||||||
if (!this.frm.doc.currency) {
|
if (!this.frm.doc.currency) {
|
||||||
this.frm.set_value("currency", company_currency);
|
this.frm.set_value("currency", company_currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.frm.doc.currency == company_currency) {
|
if (this.frm.doc.currency == company_currency) {
|
||||||
this.frm.set_value("conversion_rate", 1.0);
|
this.frm.set_value("conversion_rate", 1.0);
|
||||||
}
|
}
|
||||||
@ -209,27 +209,27 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
this.frm.script_manager.trigger("currency");
|
this.frm.script_manager.trigger("currency");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get_company_currency: function() {
|
get_company_currency: function() {
|
||||||
return erpnext.get_currency(this.frm.doc.company);
|
return erpnext.get_currency(this.frm.doc.company);
|
||||||
},
|
},
|
||||||
|
|
||||||
currency: function() {
|
currency: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
this.set_dynamic_labels();
|
this.set_dynamic_labels();
|
||||||
|
|
||||||
var company_currency = this.get_company_currency();
|
var company_currency = this.get_company_currency();
|
||||||
if(this.frm.doc.currency !== company_currency) {
|
if(this.frm.doc.currency !== company_currency) {
|
||||||
this.get_exchange_rate(this.frm.doc.currency, company_currency,
|
this.get_exchange_rate(this.frm.doc.currency, company_currency,
|
||||||
function(exchange_rate) {
|
function(exchange_rate) {
|
||||||
me.frm.set_value("conversion_rate", exchange_rate);
|
me.frm.set_value("conversion_rate", exchange_rate);
|
||||||
me.conversion_rate();
|
me.conversion_rate();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.conversion_rate();
|
this.conversion_rate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
conversion_rate: function() {
|
conversion_rate: function() {
|
||||||
if(this.frm.doc.currency === this.get_company_currency()) {
|
if(this.frm.doc.currency === this.get_company_currency()) {
|
||||||
this.frm.set_value("conversion_rate", 1.0);
|
this.frm.set_value("conversion_rate", 1.0);
|
||||||
@ -240,14 +240,14 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}
|
}
|
||||||
if(flt(this.frm.doc.conversion_rate)>0.0) this.calculate_taxes_and_totals();
|
if(flt(this.frm.doc.conversion_rate)>0.0) this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
get_price_list_currency: function(buying_or_selling) {
|
get_price_list_currency: function(buying_or_selling) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var fieldname = buying_or_selling.toLowerCase() + "_price_list";
|
var fieldname = buying_or_selling.toLowerCase() + "_price_list";
|
||||||
if(this.frm.doc[fieldname]) {
|
if(this.frm.doc[fieldname]) {
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
method: "erpnext.setup.utils.get_price_list_currency",
|
method: "erpnext.setup.utils.get_price_list_currency",
|
||||||
args: {
|
args: {
|
||||||
price_list: this.frm.doc[fieldname],
|
price_list: this.frm.doc[fieldname],
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
@ -258,7 +258,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get_exchange_rate: function(from_currency, to_currency, callback) {
|
get_exchange_rate: function(from_currency, to_currency, callback) {
|
||||||
var exchange_name = from_currency + "-" + to_currency;
|
var exchange_name = from_currency + "-" + to_currency;
|
||||||
frappe.model.with_doc("Currency Exchange", exchange_name, function(name) {
|
frappe.model.with_doc("Currency Exchange", exchange_name, function(name) {
|
||||||
@ -266,14 +266,14 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
callback(exchange_doc ? flt(exchange_doc.exchange_rate) : 0);
|
callback(exchange_doc ? flt(exchange_doc.exchange_rate) : 0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
price_list_currency: function() {
|
price_list_currency: function() {
|
||||||
var me=this;
|
var me=this;
|
||||||
this.set_dynamic_labels();
|
this.set_dynamic_labels();
|
||||||
|
|
||||||
var company_currency = this.get_company_currency();
|
var company_currency = this.get_company_currency();
|
||||||
if(this.frm.doc.price_list_currency !== company_currency) {
|
if(this.frm.doc.price_list_currency !== company_currency) {
|
||||||
this.get_exchange_rate(this.frm.doc.price_list_currency, company_currency,
|
this.get_exchange_rate(this.frm.doc.price_list_currency, company_currency,
|
||||||
function(exchange_rate) {
|
function(exchange_rate) {
|
||||||
if(exchange_rate) {
|
if(exchange_rate) {
|
||||||
me.frm.set_value("plc_conversion_rate", exchange_rate);
|
me.frm.set_value("plc_conversion_rate", exchange_rate);
|
||||||
@ -284,7 +284,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
this.plc_conversion_rate();
|
this.plc_conversion_rate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
plc_conversion_rate: function() {
|
plc_conversion_rate: function() {
|
||||||
if(this.frm.doc.price_list_currency === this.get_company_currency()) {
|
if(this.frm.doc.price_list_currency === this.get_company_currency()) {
|
||||||
this.frm.set_value("plc_conversion_rate", 1.0);
|
this.frm.set_value("plc_conversion_rate", 1.0);
|
||||||
@ -294,11 +294,11 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
qty: function(doc, cdt, cdn) {
|
qty: function(doc, cdt, cdn) {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
tax_rate: function(doc, cdt, cdn) {
|
tax_rate: function(doc, cdt, cdn) {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
@ -314,30 +314,30 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
set_dynamic_labels: function() {
|
set_dynamic_labels: function() {
|
||||||
// What TODO? should we make price list system non-mandatory?
|
// What TODO? should we make price list system non-mandatory?
|
||||||
this.frm.toggle_reqd("plc_conversion_rate",
|
this.frm.toggle_reqd("plc_conversion_rate",
|
||||||
!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
|
!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
|
||||||
|
|
||||||
var company_currency = this.get_company_currency();
|
var company_currency = this.get_company_currency();
|
||||||
this.change_form_labels(company_currency);
|
this.change_form_labels(company_currency);
|
||||||
this.change_grid_labels(company_currency);
|
this.change_grid_labels(company_currency);
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
},
|
},
|
||||||
|
|
||||||
recalculate: function() {
|
recalculate: function() {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
recalculate_values: function() {
|
recalculate_values: function() {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
calculate_charges: function() {
|
calculate_charges: function() {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
included_in_print_rate: function(doc, cdt, cdn) {
|
included_in_print_rate: function(doc, cdt, cdn) {
|
||||||
var tax = frappe.get_doc(cdt, cdn);
|
var tax = frappe.get_doc(cdt, cdn);
|
||||||
try {
|
try {
|
||||||
@ -350,52 +350,32 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_on_previous_row: function(tax) {
|
validate_on_previous_row: function(tax) {
|
||||||
// validate if a valid row id is mentioned in case of
|
// validate if a valid row id is mentioned in case of
|
||||||
// On Previous Row Amount and On Previous Row Total
|
// On Previous Row Amount and On Previous Row Total
|
||||||
if(([__("On Previous Row Amount"), __("On Previous Row Total")].indexOf(tax.charge_type) != -1) &&
|
if((["On Previous Row Amount", "On Previous Row Total"].indexOf(tax.charge_type) != -1) &&
|
||||||
(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
|
(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
|
||||||
var msg = repl(__("Row") + " # %(idx)s [%(doctype)s]: " +
|
var msg = __("Please specify a valid Row ID for row {0} in table {1}", [tax.idx, __(tax.doctype)])
|
||||||
__("Please specify a valid") + " %(row_id_label)s", {
|
|
||||||
idx: tax.idx,
|
|
||||||
doctype: tax.doctype,
|
|
||||||
row_id_label: frappe.meta.get_label(tax.doctype, "row_id", tax.name)
|
|
||||||
});
|
|
||||||
frappe.throw(msg);
|
frappe.throw(msg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_inclusive_tax: function(tax) {
|
validate_inclusive_tax: function(tax) {
|
||||||
if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
|
if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
|
||||||
|
|
||||||
var actual_type_error = function() {
|
var actual_type_error = function() {
|
||||||
var msg = repl(__("For row") + " # %(idx)s [%(doctype)s]: " +
|
var msg = __("Actual type tax cannot be included in Item rate in row {0}", [tax.idx])
|
||||||
"%(charge_type_label)s = \"%(charge_type)s\" " +
|
|
||||||
__("cannot be included in Item's rate"), {
|
|
||||||
idx: tax.idx,
|
|
||||||
doctype: tax.doctype,
|
|
||||||
charge_type_label: frappe.meta.get_label(tax.doctype, "charge_type", tax.name),
|
|
||||||
charge_type: tax.charge_type
|
|
||||||
});
|
|
||||||
frappe.throw(msg);
|
frappe.throw(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
var on_previous_row_error = function(row_range) {
|
var on_previous_row_error = function(row_range) {
|
||||||
var msg = repl(__("For row") + " # %(idx)s [%(doctype)s]: " +
|
var msg = __("For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included",
|
||||||
__("to be included in Item's rate, it is required that: ") +
|
[tax.idx, __(tax.doctype), tax.charge_type, row_range])
|
||||||
" [" + __("Row") + " # %(row_range)s] " + __("also be included in Item's rate"), {
|
|
||||||
idx: tax.idx,
|
|
||||||
doctype: tax.doctype,
|
|
||||||
charge_type_label: frappe.meta.get_label(tax.doctype, "charge_type", tax.name),
|
|
||||||
charge_type: tax.charge_type,
|
|
||||||
inclusive_label: frappe.meta.get_label(tax.doctype, "included_in_print_rate", tax.name),
|
|
||||||
row_range: row_range,
|
|
||||||
});
|
|
||||||
|
|
||||||
frappe.throw(msg);
|
frappe.throw(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(cint(tax.included_in_print_rate)) {
|
if(cint(tax.included_in_print_rate)) {
|
||||||
if(tax.charge_type == "Actual") {
|
if(tax.charge_type == "Actual") {
|
||||||
// inclusive tax cannot be of type Actual
|
// inclusive tax cannot be of type Actual
|
||||||
@ -405,7 +385,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
// referred row should also be an inclusive tax
|
// referred row should also be an inclusive tax
|
||||||
on_previous_row_error(tax.row_id);
|
on_previous_row_error(tax.row_id);
|
||||||
} else if(tax.charge_type == "On Previous Row Total") {
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id),
|
var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id),
|
||||||
function(t) { return cint(t.included_in_print_rate) ? null : t; });
|
function(t) { return cint(t.included_in_print_rate) ? null : t; });
|
||||||
if(taxes_not_included.length > 0) {
|
if(taxes_not_included.length > 0) {
|
||||||
// all rows above this tax should be inclusive
|
// all rows above this tax should be inclusive
|
||||||
@ -414,26 +394,26 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_load_item_tax_rate: function(item_tax_rate) {
|
_load_item_tax_rate: function(item_tax_rate) {
|
||||||
return item_tax_rate ? JSON.parse(item_tax_rate) : {};
|
return item_tax_rate ? JSON.parse(item_tax_rate) : {};
|
||||||
},
|
},
|
||||||
|
|
||||||
_get_tax_rate: function(tax, item_tax_map) {
|
_get_tax_rate: function(tax, item_tax_map) {
|
||||||
return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
|
return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
|
||||||
flt(item_tax_map[tax.account_head], precision("rate", tax)) :
|
flt(item_tax_map[tax.account_head], precision("rate", tax)) :
|
||||||
tax.rate;
|
tax.rate;
|
||||||
},
|
},
|
||||||
|
|
||||||
get_item_wise_taxes_html: function() {
|
get_item_wise_taxes_html: function() {
|
||||||
var item_tax = {};
|
var item_tax = {};
|
||||||
var tax_accounts = [];
|
var tax_accounts = [];
|
||||||
var company_currency = this.get_company_currency();
|
var company_currency = this.get_company_currency();
|
||||||
|
|
||||||
$.each(this.get_tax_doclist(), function(i, tax) {
|
$.each(this.get_tax_doclist(), function(i, tax) {
|
||||||
var tax_amount_precision = precision("tax_amount", tax);
|
var tax_amount_precision = precision("tax_amount", tax);
|
||||||
var tax_rate_precision = precision("rate", tax);
|
var tax_rate_precision = precision("rate", tax);
|
||||||
$.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
|
$.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
|
||||||
function(item_code, tax_data) {
|
function(item_code, tax_data) {
|
||||||
if(!item_tax[item_code]) item_tax[item_code] = {};
|
if(!item_tax[item_code]) item_tax[item_code] = {};
|
||||||
if($.isArray(tax_data)) {
|
if($.isArray(tax_data)) {
|
||||||
@ -445,7 +425,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}
|
}
|
||||||
var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency,
|
var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency,
|
||||||
tax_amount_precision);
|
tax_amount_precision);
|
||||||
|
|
||||||
item_tax[item_code][tax.name] = [tax_rate, tax_amount];
|
item_tax[item_code][tax.name] = [tax_rate, tax_amount];
|
||||||
} else {
|
} else {
|
||||||
item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", ""];
|
item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", ""];
|
||||||
@ -453,10 +433,10 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
});
|
});
|
||||||
tax_accounts.push([tax.name, tax.account_head]);
|
tax_accounts.push([tax.name, tax.account_head]);
|
||||||
});
|
});
|
||||||
|
|
||||||
var headings = $.map([__("Item Name")].concat($.map(tax_accounts, function(head) { return head[1]; })),
|
var headings = $.map([__("Item Name")].concat($.map(tax_accounts, function(head) { return head[1]; })),
|
||||||
function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
|
function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
|
||||||
|
|
||||||
var distinct_item_names = [];
|
var distinct_item_names = [];
|
||||||
var distinct_items = [];
|
var distinct_items = [];
|
||||||
$.each(this.get_item_doclist(), function(i, item) {
|
$.each(this.get_item_doclist(), function(i, item) {
|
||||||
@ -465,7 +445,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
distinct_items.push(item);
|
distinct_items.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var rows = $.map(distinct_items, function(item) {
|
var rows = $.map(distinct_items, function(item) {
|
||||||
var item_tax_record = item_tax[item.item_code || item.item_name];
|
var item_tax_record = item_tax[item.item_code || item.item_name];
|
||||||
if(!item_tax_record) { return null; }
|
if(!item_tax_record) { return null; }
|
||||||
@ -478,7 +458,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}).join("\n")
|
}).join("\n")
|
||||||
});
|
});
|
||||||
}).join("\n");
|
}).join("\n");
|
||||||
|
|
||||||
if(!rows) return "";
|
if(!rows) return "";
|
||||||
return '<p><a href="#" onclick="$(\'.tax-break-up\').toggleClass(\'hide\'); return false;">Show / Hide tax break-up</a><br><br></p>\
|
return '<p><a href="#" onclick="$(\'.tax-break-up\').toggleClass(\'hide\'); return false;">Show / Hide tax break-up</a><br><br></p>\
|
||||||
<div class="tax-break-up hide" style="overflow-x: auto;"><table class="table table-bordered table-hover">\
|
<div class="tax-break-up hide" style="overflow-x: auto;"><table class="table table-bordered table-hover">\
|
||||||
@ -486,16 +466,16 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
<tbody>' + rows + '</tbody> \
|
<tbody>' + rows + '</tbody> \
|
||||||
</table></div>';
|
</table></div>';
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_company_and_party: function() {
|
validate_company_and_party: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
var valid = true;
|
var valid = true;
|
||||||
|
|
||||||
$.each(["company", "customer"], function(i, fieldname) {
|
$.each(["company", "customer"], function(i, fieldname) {
|
||||||
if(frappe.meta.has_field(me.frm.doc.doctype, fieldname)) {
|
if(frappe.meta.has_field(me.frm.doc.doctype, fieldname)) {
|
||||||
if (!me.frm.doc[fieldname]) {
|
if (!me.frm.doc[fieldname]) {
|
||||||
msgprint(__("Please specify") + ": " +
|
msgprint(__("Please specify") + ": " +
|
||||||
frappe.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
|
frappe.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
|
||||||
". " + __("It is needed to fetch Item Details."));
|
". " + __("It is needed to fetch Item Details."));
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
@ -503,25 +483,25 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
});
|
});
|
||||||
return valid;
|
return valid;
|
||||||
},
|
},
|
||||||
|
|
||||||
get_item_doclist: function() {
|
get_item_doclist: function() {
|
||||||
return this.frm.doc[this.fname] || [];
|
return this.frm.doc[this.fname] || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
get_tax_doclist: function() {
|
get_tax_doclist: function() {
|
||||||
return this.frm.doc[this.other_fname] || [];
|
return this.frm.doc[this.other_fname] || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_conversion_rate: function() {
|
validate_conversion_rate: function() {
|
||||||
this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
|
this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
|
||||||
var conversion_rate_label = frappe.meta.get_label(this.frm.doc.doctype, "conversion_rate",
|
var conversion_rate_label = frappe.meta.get_label(this.frm.doc.doctype, "conversion_rate",
|
||||||
this.frm.doc.name);
|
this.frm.doc.name);
|
||||||
var company_currency = this.get_company_currency();
|
var company_currency = this.get_company_currency();
|
||||||
|
|
||||||
if(!this.frm.doc.conversion_rate) {
|
if(!this.frm.doc.conversion_rate) {
|
||||||
frappe.throw(repl('%(conversion_rate_label)s' +
|
frappe.throw(repl('%(conversion_rate_label)s' +
|
||||||
__(' is mandatory. Maybe Currency Exchange record is not created for ') +
|
__(' is mandatory. Maybe Currency Exchange record is not created for ') +
|
||||||
'%(from_currency)s' + __(" to ") + '%(to_currency)s',
|
'%(from_currency)s' + __(" to ") + '%(to_currency)s',
|
||||||
{
|
{
|
||||||
"conversion_rate_label": conversion_rate_label,
|
"conversion_rate_label": conversion_rate_label,
|
||||||
"from_currency": this.frm.doc.currency,
|
"from_currency": this.frm.doc.currency,
|
||||||
@ -529,7 +509,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
calculate_taxes_and_totals: function() {
|
calculate_taxes_and_totals: function() {
|
||||||
this.discount_amount_applied = false;
|
this.discount_amount_applied = false;
|
||||||
this._calculate_taxes_and_totals();
|
this._calculate_taxes_and_totals();
|
||||||
@ -552,13 +532,13 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
|
|
||||||
this.show_item_wise_taxes();
|
this.show_item_wise_taxes();
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize_taxes: function() {
|
initialize_taxes: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
$.each(this.frm.tax_doclist, function(i, tax) {
|
$.each(this.frm.tax_doclist, function(i, tax) {
|
||||||
tax.item_wise_tax_detail = {};
|
tax.item_wise_tax_detail = {};
|
||||||
tax_fields = ["total", "tax_amount_after_discount_amount",
|
tax_fields = ["total", "tax_amount_after_discount_amount",
|
||||||
"tax_amount_for_current_item", "grand_total_for_current_item",
|
"tax_amount_for_current_item", "grand_total_for_current_item",
|
||||||
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
|
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
|
||||||
|
|
||||||
@ -566,17 +546,17 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
tax_fields.push("tax_amount");
|
tax_fields.push("tax_amount");
|
||||||
|
|
||||||
$.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0 });
|
$.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0 });
|
||||||
|
|
||||||
me.validate_on_previous_row(tax);
|
me.validate_on_previous_row(tax);
|
||||||
me.validate_inclusive_tax(tax);
|
me.validate_inclusive_tax(tax);
|
||||||
frappe.model.round_floats_in(tax);
|
frappe.model.round_floats_in(tax);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
calculate_taxes: function() {
|
calculate_taxes: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
var actual_tax_dict = {};
|
var actual_tax_dict = {};
|
||||||
|
|
||||||
// maintain actual tax rate based on idx
|
// maintain actual tax rate based on idx
|
||||||
$.each(this.frm.tax_doclist, function(i, tax) {
|
$.each(this.frm.tax_doclist, function(i, tax) {
|
||||||
if (tax.charge_type == "Actual") {
|
if (tax.charge_type == "Actual") {
|
||||||
@ -602,34 +582,34 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
// store tax_amount for current item as it will be used for
|
// store tax_amount for current item as it will be used for
|
||||||
// charge type = 'On Previous Row Amount'
|
// charge type = 'On Previous Row Amount'
|
||||||
tax.tax_amount_for_current_item = current_tax_amount;
|
tax.tax_amount_for_current_item = current_tax_amount;
|
||||||
|
|
||||||
// accumulate tax amount into tax.tax_amount
|
// accumulate tax amount into tax.tax_amount
|
||||||
if (!me.discount_amount_applied)
|
if (!me.discount_amount_applied)
|
||||||
tax.tax_amount += current_tax_amount;
|
tax.tax_amount += current_tax_amount;
|
||||||
|
|
||||||
tax.tax_amount_after_discount_amount += current_tax_amount;
|
tax.tax_amount_after_discount_amount += current_tax_amount;
|
||||||
|
|
||||||
// for buying
|
// for buying
|
||||||
if(tax.category) {
|
if(tax.category) {
|
||||||
// if just for valuation, do not add the tax amount in total
|
// if just for valuation, do not add the tax amount in total
|
||||||
// hence, setting it as 0 for further steps
|
// hence, setting it as 0 for further steps
|
||||||
current_tax_amount = (tax.category == "Valuation") ? 0.0 : current_tax_amount;
|
current_tax_amount = (tax.category == "Valuation") ? 0.0 : current_tax_amount;
|
||||||
|
|
||||||
current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate tax.total viz. grand total till that step
|
// Calculate tax.total viz. grand total till that step
|
||||||
// note: grand_total_for_current_item contains the contribution of
|
// note: grand_total_for_current_item contains the contribution of
|
||||||
// item's amount, previously applied tax and the current tax on that item
|
// item's amount, previously applied tax and the current tax on that item
|
||||||
if(i==0) {
|
if(i==0) {
|
||||||
tax.grand_total_for_current_item = flt(item.base_amount + current_tax_amount,
|
tax.grand_total_for_current_item = flt(item.base_amount + current_tax_amount,
|
||||||
precision("total", tax));
|
precision("total", tax));
|
||||||
} else {
|
} else {
|
||||||
tax.grand_total_for_current_item =
|
tax.grand_total_for_current_item =
|
||||||
flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
|
flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
|
||||||
precision("total", tax));
|
precision("total", tax));
|
||||||
}
|
}
|
||||||
|
|
||||||
// in tax.total, accumulate grand total for each item
|
// in tax.total, accumulate grand total for each item
|
||||||
tax.total += tax.grand_total_for_current_item;
|
tax.total += tax.grand_total_for_current_item;
|
||||||
|
|
||||||
@ -648,54 +628,54 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
round_off_totals: function(tax) {
|
round_off_totals: function(tax) {
|
||||||
tax.total = flt(tax.total, precision("total", tax));
|
tax.total = flt(tax.total, precision("total", tax));
|
||||||
tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
|
tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
|
||||||
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount,
|
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount,
|
||||||
precision("tax_amount", tax));
|
precision("tax_amount", tax));
|
||||||
},
|
},
|
||||||
|
|
||||||
adjust_discount_amount_loss: function(tax) {
|
adjust_discount_amount_loss: function(tax) {
|
||||||
var discount_amount_loss = this.frm.doc.grand_total - flt(this.frm.doc.discount_amount) - tax.total;
|
var discount_amount_loss = this.frm.doc.grand_total - flt(this.frm.doc.discount_amount) - tax.total;
|
||||||
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount +
|
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount +
|
||||||
discount_amount_loss, precision("tax_amount", tax));
|
discount_amount_loss, precision("tax_amount", tax));
|
||||||
tax.total = flt(tax.total + discount_amount_loss, precision("total", tax));
|
tax.total = flt(tax.total + discount_amount_loss, precision("total", tax));
|
||||||
},
|
},
|
||||||
|
|
||||||
get_current_tax_amount: function(item, tax, item_tax_map) {
|
get_current_tax_amount: function(item, tax, item_tax_map) {
|
||||||
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
||||||
var current_tax_amount = 0.0;
|
var current_tax_amount = 0.0;
|
||||||
|
|
||||||
if(tax.charge_type == "Actual") {
|
if(tax.charge_type == "Actual") {
|
||||||
// distribute the tax amount proportionally to each item row
|
// distribute the tax amount proportionally to each item row
|
||||||
var actual = flt(tax.rate, precision("tax_amount", tax));
|
var actual = flt(tax.rate, precision("tax_amount", tax));
|
||||||
current_tax_amount = this.frm.doc.net_total ?
|
current_tax_amount = this.frm.doc.net_total ?
|
||||||
((item.base_amount / this.frm.doc.net_total) * actual) :
|
((item.base_amount / this.frm.doc.net_total) * actual) :
|
||||||
0.0;
|
0.0;
|
||||||
|
|
||||||
} else if(tax.charge_type == "On Net Total") {
|
} else if(tax.charge_type == "On Net Total") {
|
||||||
current_tax_amount = (tax_rate / 100.0) * item.base_amount;
|
current_tax_amount = (tax_rate / 100.0) * item.base_amount;
|
||||||
|
|
||||||
} else if(tax.charge_type == "On Previous Row Amount") {
|
} else if(tax.charge_type == "On Previous Row Amount") {
|
||||||
current_tax_amount = (tax_rate / 100.0) *
|
current_tax_amount = (tax_rate / 100.0) *
|
||||||
this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
|
this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
|
||||||
|
|
||||||
} else if(tax.charge_type == "On Previous Row Total") {
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
current_tax_amount = (tax_rate / 100.0) *
|
current_tax_amount = (tax_rate / 100.0) *
|
||||||
this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item;
|
this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_tax_amount = flt(current_tax_amount, precision("tax_amount", tax));
|
current_tax_amount = flt(current_tax_amount, precision("tax_amount", tax));
|
||||||
|
|
||||||
// store tax breakup for each item
|
// store tax breakup for each item
|
||||||
tax.item_wise_tax_detail[item.item_code || item.item_name] = [tax_rate, current_tax_amount];
|
tax.item_wise_tax_detail[item.item_code || item.item_name] = [tax_rate, current_tax_amount];
|
||||||
|
|
||||||
return current_tax_amount;
|
return current_tax_amount;
|
||||||
},
|
},
|
||||||
|
|
||||||
_cleanup: function() {
|
_cleanup: function() {
|
||||||
$.each(this.frm.tax_doclist, function(i, tax) {
|
$.each(this.frm.tax_doclist, function(i, tax) {
|
||||||
$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
|
$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
|
||||||
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"],
|
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"],
|
||||||
function(i, fieldname) { delete tax[fieldname]; });
|
function(i, fieldname) { delete tax[fieldname]; });
|
||||||
|
|
||||||
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
|
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -706,17 +686,17 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
this.frm.doc.total_advance = flt(frappe.utils.sum(
|
this.frm.doc.total_advance = flt(frappe.utils.sum(
|
||||||
$.map(advance_doclist, function(adv) { return adv.allocated_amount })
|
$.map(advance_doclist, function(adv) { return adv.allocated_amount })
|
||||||
), precision("total_advance"));
|
), precision("total_advance"));
|
||||||
|
|
||||||
this.calculate_outstanding_amount();
|
this.calculate_outstanding_amount();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_set_in_company_currency: function(item, print_field, base_field) {
|
_set_in_company_currency: function(item, print_field, base_field) {
|
||||||
// set values in base currency
|
// set values in base currency
|
||||||
item[base_field] = flt(item[print_field] * this.frm.doc.conversion_rate,
|
item[base_field] = flt(item[print_field] * this.frm.doc.conversion_rate,
|
||||||
precision(base_field, item));
|
precision(base_field, item));
|
||||||
},
|
},
|
||||||
|
|
||||||
get_terms: function() {
|
get_terms: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.tc_name) {
|
if(this.frm.doc.tc_name) {
|
||||||
@ -752,4 +732,4 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
|||||||
.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
|
.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ class Customer(TransactionBase):
|
|||||||
|
|
||||||
def validate_values(self):
|
def validate_values(self):
|
||||||
if frappe.defaults.get_global_default('cust_master_name') == 'Naming Series' and not self.naming_series:
|
if frappe.defaults.get_global_default('cust_master_name') == 'Naming Series' and not self.naming_series:
|
||||||
frappe.throw("Series is Mandatory.", frappe.MandatoryError)
|
frappe.throw(_("Series is mandatory"), frappe.MandatoryError)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_values()
|
self.validate_values()
|
||||||
@ -66,7 +66,7 @@ class Customer(TransactionBase):
|
|||||||
c.is_primary_contact = 1
|
c.is_primary_contact = 1
|
||||||
try:
|
try:
|
||||||
c.save()
|
c.save()
|
||||||
except NameError, e:
|
except NameError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
@ -86,7 +86,7 @@ class Customer(TransactionBase):
|
|||||||
|
|
||||||
def validate_name_with_customer_group(self):
|
def validate_name_with_customer_group(self):
|
||||||
if frappe.db.exists("Customer Group", self.name):
|
if frappe.db.exists("Customer Group", self.name):
|
||||||
frappe.throw("A Customer Group exists with same name please change the Customer name or rename the Customer Group")
|
frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"))
|
||||||
|
|
||||||
def delete_customer_address(self):
|
def delete_customer_address(self):
|
||||||
addresses = frappe.db.sql("""select name, lead from `tabAddress`
|
addresses = frappe.db.sql("""select name, lead from `tabAddress`
|
||||||
|
@ -27,11 +27,11 @@ class Lead(SellingController):
|
|||||||
self.set_status()
|
self.set_status()
|
||||||
|
|
||||||
if self.source == 'Campaign' and not self.campaign_name and session['user'] != 'Guest':
|
if self.source == 'Campaign' and not self.campaign_name and session['user'] != 'Guest':
|
||||||
frappe.throw("Please specify campaign name")
|
frappe.throw(_("Campaign Name is required"))
|
||||||
|
|
||||||
if self.email_id:
|
if self.email_id:
|
||||||
if not validate_email_add(self.email_id):
|
if not validate_email_add(self.email_id):
|
||||||
frappe.throw('Please enter valid email id.')
|
frappe.throw(_('{0} is not a valid email id').format(self.email_id))
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
self.check_email_id_is_unique()
|
self.check_email_id_is_unique()
|
||||||
|
@ -145,7 +145,7 @@ class SalesOrder(SellingController):
|
|||||||
if quotation:
|
if quotation:
|
||||||
doc = frappe.get_doc("Quotation", quotation)
|
doc = frappe.get_doc("Quotation", quotation)
|
||||||
if doc.docstatus==2:
|
if doc.docstatus==2:
|
||||||
frappe.throw(quotation + ": " + frappe._("Quotation is cancelled."))
|
frappe.throw(_("Quotation {0} is cancelled").format(quotation))
|
||||||
|
|
||||||
doc.set_status(update=True)
|
doc.set_status(update=True)
|
||||||
|
|
||||||
|
@ -17,6 +17,4 @@ class CustomerGroup(NestedSet):
|
|||||||
|
|
||||||
def validate_name_with_customer(self):
|
def validate_name_with_customer(self):
|
||||||
if frappe.db.exists("Customer", self.name):
|
if frappe.db.exists("Customer", self.name):
|
||||||
frappe.msgprint(_("An Customer exists with same name (%s), \
|
frappe.msgprint(_("An Customer exists with same name"), raise_exception=1)
|
||||||
please change the Customer Group name or rename the Customer") %
|
|
||||||
self.name, raise_exception=1)
|
|
||||||
|
@ -1,241 +1,241 @@
|
|||||||
{
|
{
|
||||||
"creation": "2012-12-20 12:50:49.000000",
|
"creation": "2012-12-20 12:50:49.000000",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldname": "materials",
|
"fieldname": "materials",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Materials",
|
"label": "Materials",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To track item in sales and purchase documents based on their serial nos. This is can also used to track warranty details of the product.",
|
"description": "To track item in sales and purchase documents based on their serial nos. This is can also used to track warranty details of the product.",
|
||||||
"fieldname": "fs_item_serial_nos",
|
"fieldname": "fs_item_serial_nos",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Item Serial Nos",
|
"label": "Item Serial Nos",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To track items in sales and purchase documents with batch nos<br><b>Preferred Industry: Chemicals etc</b>",
|
"description": "To track items in sales and purchase documents with batch nos<br><b>Preferred Industry: Chemicals etc</b>",
|
||||||
"fieldname": "fs_item_batch_nos",
|
"fieldname": "fs_item_batch_nos",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Item Batch Nos",
|
"label": "Item Batch Nos",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To track brand name in the following documents<br>\nDelivery Note, Enuiry, Material Request, Item, Purchase Order, Purchase Voucher, Purchaser Receipt, Quotation, Sales Invoice, Sales BOM, Sales Order, Serial No",
|
"description": "To track brand name in the following documents Delivery Note, Opportunity, Material Request, Item, Purchase Order, Purchase Voucher, Purchaser Receipt, Quotation, Sales Invoice, Sales BOM, Sales Order, Serial No",
|
||||||
"fieldname": "fs_brands",
|
"fieldname": "fs_brands",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Brands",
|
"label": "Brands",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To track items using barcode. You will be able to enter items in Delivery Note and Sales Invoice by scanning barcode of item.",
|
"description": "To track items using barcode. You will be able to enter items in Delivery Note and Sales Invoice by scanning barcode of item.",
|
||||||
"fieldname": "fs_item_barcode",
|
"fieldname": "fs_item_barcode",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Item Barcode",
|
"label": "Item Barcode",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break0",
|
"fieldname": "column_break0",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "1. To maintain the customer wise item code and to make them searchable based on their code use this option",
|
"description": "1. To maintain the customer wise item code and to make them searchable based on their code use this option",
|
||||||
"fieldname": "fs_item_advanced",
|
"fieldname": "fs_item_advanced",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Item Advanced",
|
"label": "Item Advanced",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "If Sale BOM is defined, the actual BOM of the Pack is displayed as table.\nAvailable in Delivery Note and Sales Order",
|
"description": "If Sale BOM is defined, the actual BOM of the Pack is displayed as table. Available in Delivery Note and Sales Order",
|
||||||
"fieldname": "fs_packing_details",
|
"fieldname": "fs_packing_details",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Packing Details",
|
"label": "Packing Details",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To get Item Group in details table",
|
"description": "To get Item Group in details table",
|
||||||
"fieldname": "fs_item_group_in_details",
|
"fieldname": "fs_item_group_in_details",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Item Groups in Details",
|
"label": "Item Groups in Details",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sales_and_purchase",
|
"fieldname": "sales_and_purchase",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Sales and Purchase",
|
"label": "Sales and Purchase",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "All export related fields like currency, conversion rate, export total, export grand total etc are available in <br>\nDelivery Note, POS, Quotation, Sales Invoice, Sales Order etc.",
|
"description": "All export related fields like currency, conversion rate, export total, export grand total etc are available in Delivery Note, POS, Quotation, Sales Invoice, Sales Order etc.",
|
||||||
"fieldname": "fs_exports",
|
"fieldname": "fs_exports",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Exports",
|
"label": "Exports",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "All import related fields like currency, conversion rate, import total, import grand total etc are available in <br>\nPurchase Receipt, Supplier Quotation, Purchase Invoice, Purchase Order etc.",
|
"description": "All import related fields like currency, conversion rate, import total, import grand total etc are available in Purchase Receipt, Supplier Quotation, Purchase Invoice, Purchase Order etc.",
|
||||||
"fieldname": "fs_imports",
|
"fieldname": "fs_imports",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Imports",
|
"label": "Imports",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break1",
|
"fieldname": "column_break1",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Field available in Delivery Note, Quotation, Sales Invoice, Sales Order",
|
"description": "Field available in Delivery Note, Quotation, Sales Invoice, Sales Order",
|
||||||
"fieldname": "fs_discounts",
|
"fieldname": "fs_discounts",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Sales Discounts",
|
"label": "Sales Discounts",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Discount Fields will be available in Purchase Order, Purchase Receipt, Purchase Invoice",
|
"description": "Discount Fields will be available in Purchase Order, Purchase Receipt, Purchase Invoice",
|
||||||
"fieldname": "fs_purchase_discounts",
|
"fieldname": "fs_purchase_discounts",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Purchase Discounts",
|
"label": "Purchase Discounts",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To track any installation or commissioning related work after sales",
|
"description": "To track any installation or commissioning related work after sales",
|
||||||
"fieldname": "fs_after_sales_installations",
|
"fieldname": "fs_after_sales_installations",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "After Sale Installations",
|
"label": "After Sale Installations",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Available in \nBOM, Delivery Note, Purchase Invoice, Production Order, Purchase Order, Purchase Receipt, Sales Invoice, Sales Order, Stock Entry, Timesheet",
|
"description": "Available in BOM, Delivery Note, Purchase Invoice, Production Order, Purchase Order, Purchase Receipt, Sales Invoice, Sales Order, Stock Entry, Timesheet",
|
||||||
"fieldname": "fs_projects",
|
"fieldname": "fs_projects",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Projects",
|
"label": "Projects",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "If you have Sales Team and Sale Partners (Channel Partners) they can be tagged and maintain their contribution in the sales activity",
|
"description": "If you have Sales Team and Sale Partners (Channel Partners) they can be tagged and maintain their contribution in the sales activity",
|
||||||
"fieldname": "fs_sales_extras",
|
"fieldname": "fs_sales_extras",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Sales Extras",
|
"label": "Sales Extras",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "accounts",
|
"fieldname": "accounts",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Accounts",
|
"label": "Accounts",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Check if you need automatic recurring invoices. After submitting any sales invoice, Recurring section will be visible.",
|
"description": "Check if you need automatic recurring invoices. After submitting any sales invoice, Recurring section will be visible.",
|
||||||
"fieldname": "fs_recurring_invoice",
|
"fieldname": "fs_recurring_invoice",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Recurring Invoice",
|
"label": "Recurring Invoice",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break2",
|
"fieldname": "column_break2",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To enable <b>Point of Sale</b> features",
|
"description": "To enable <b>Point of Sale</b> features",
|
||||||
"fieldname": "fs_pos",
|
"fieldname": "fs_pos",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Point of Sale",
|
"label": "Point of Sale",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "To enable <b>Point of Sale</b> view",
|
"description": "To enable <b>Point of Sale</b> view",
|
||||||
"fieldname": "fs_pos_view",
|
"fieldname": "fs_pos_view",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "POS View",
|
"label": "POS View",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "production",
|
"fieldname": "production",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Manufacturing",
|
"label": "Manufacturing",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "If you involve in manufacturing activity<br>\nEnables item <b>Is Manufactured</b>",
|
"description": "If you involve in manufacturing activity. Enables Item 'Is Manufactured'",
|
||||||
"fieldname": "fs_manufacturing",
|
"fieldname": "fs_manufacturing",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Manufacturing",
|
"label": "Manufacturing",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break3",
|
"fieldname": "column_break3",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "If you follow Quality Inspection<br>\nEnables item QA Required and QA No in Purchase Receipt",
|
"description": "If you follow Quality Inspection. Enables Item QA Required and QA No in Purchase Receipt",
|
||||||
"fieldname": "fs_quality",
|
"fieldname": "fs_quality",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Quality",
|
"label": "Quality",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "miscelleneous",
|
"fieldname": "miscelleneous",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Miscelleneous",
|
"label": "Miscelleneous",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "If you have long print formats, this feature can be used to split the page to be printed on multiple pages with all headers and footers on each page",
|
"description": "If you have long print formats, this feature can be used to split the page to be printed on multiple pages with all headers and footers on each page",
|
||||||
"fieldname": "fs_page_break",
|
"fieldname": "fs_page_break",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Page Break",
|
"label": "Page Break",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break4",
|
"fieldname": "column_break4",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "fs_more_info",
|
"fieldname": "fs_more_info",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "More Info",
|
"label": "More Info",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-glass",
|
"icon": "icon-glass",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"modified": "2013-12-24 11:40:19.000000",
|
"modified": "2013-12-24 11:40:19.000000",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Features Setup",
|
"name": "Features Setup",
|
||||||
"name_case": "Title Case",
|
"name_case": "Title Case",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"report": 0,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"report": 0,
|
||||||
"role": "Administrator",
|
"role": "Administrator",
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,11 @@ class NamingSeries(Document):
|
|||||||
return {
|
return {
|
||||||
"transactions": "\n".join([''] + sorted(list(set(
|
"transactions": "\n".join([''] + sorted(list(set(
|
||||||
frappe.db.sql_list("""select parent
|
frappe.db.sql_list("""select parent
|
||||||
from `tabDocField` where fieldname='naming_series'""")
|
from `tabDocField` where fieldname='naming_series'""")
|
||||||
+ frappe.db.sql_list("""select dt from `tabCustom Field`
|
+ frappe.db.sql_list("""select dt from `tabCustom Field`
|
||||||
where fieldname='naming_series'""")
|
where fieldname='naming_series'""")
|
||||||
)))),
|
)))),
|
||||||
"prefixes": "\n".join([''] + [i[0] for i in
|
"prefixes": "\n".join([''] + [i[0] for i in
|
||||||
frappe.db.sql("""select name from tabSeries order by name""")])
|
frappe.db.sql("""select name from tabSeries order by name""")])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,16 +86,16 @@ class NamingSeries(Document):
|
|||||||
dt = DocType()
|
dt = DocType()
|
||||||
|
|
||||||
parent = list(set(
|
parent = list(set(
|
||||||
frappe.db.sql_list("""select dt.name
|
frappe.db.sql_list("""select dt.name
|
||||||
from `tabDocField` df, `tabDocType` dt
|
from `tabDocField` df, `tabDocType` dt
|
||||||
where dt.name = df.parent and df.fieldname='naming_series' and dt.name != %s""",
|
where dt.name = df.parent and df.fieldname='naming_series' and dt.name != %s""",
|
||||||
self.select_doc_for_series)
|
self.select_doc_for_series)
|
||||||
+ frappe.db.sql_list("""select dt.name
|
+ frappe.db.sql_list("""select dt.name
|
||||||
from `tabCustom Field` df, `tabDocType` dt
|
from `tabCustom Field` df, `tabDocType` dt
|
||||||
where dt.name = df.dt and df.fieldname='naming_series' and dt.name != %s""",
|
where dt.name = df.dt and df.fieldname='naming_series' and dt.name != %s""",
|
||||||
self.select_doc_for_series)
|
self.select_doc_for_series)
|
||||||
))
|
))
|
||||||
sr = [[frappe.get_meta(p).get_field("naming_series").options, p]
|
sr = [[frappe.get_meta(p).get_field("naming_series").options, p]
|
||||||
for p in parent]
|
for p in parent]
|
||||||
options = self.scrub_options_list(self.set_options.split("\n"))
|
options = self.scrub_options_list(self.set_options.split("\n"))
|
||||||
for series in options:
|
for series in options:
|
||||||
@ -104,19 +104,12 @@ class NamingSeries(Document):
|
|||||||
if i[0]:
|
if i[0]:
|
||||||
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
|
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
|
||||||
if series.split(".")[0] in existing_series:
|
if series.split(".")[0] in existing_series:
|
||||||
throw("{oops}! {sr} {series} {msg} {existing_series}. {select}".format(**{
|
frappe.throw(_("Series {0} already used in {1}").format(series,i[1]))
|
||||||
"oops": _("Oops"),
|
|
||||||
"sr": _("Series Name"),
|
|
||||||
"series": series,
|
|
||||||
"msg": _("is already in use in"),
|
|
||||||
"existing_series": i[1],
|
|
||||||
"select": _("Please select a new one")
|
|
||||||
}))
|
|
||||||
|
|
||||||
def validate_series_name(self, n):
|
def validate_series_name(self, n):
|
||||||
import re
|
import re
|
||||||
if not re.match("^[a-zA-Z0-9-/.#]*$", n):
|
if not re.match("^[a-zA-Z0-9-/.#]*$", n):
|
||||||
throw('Special Characters except "-" and "/" not allowed in naming series')
|
throw(_('Special Characters except "-" and "/" not allowed in naming series'))
|
||||||
|
|
||||||
def get_options(self, arg=''):
|
def get_options(self, arg=''):
|
||||||
return frappe.get_meta(self.select_doc_for_series).get_field("naming_series").options
|
return frappe.get_meta(self.select_doc_for_series).get_field("naming_series").options
|
||||||
@ -124,7 +117,7 @@ class NamingSeries(Document):
|
|||||||
def get_current(self, arg=None):
|
def get_current(self, arg=None):
|
||||||
"""get series current"""
|
"""get series current"""
|
||||||
if self.prefix:
|
if self.prefix:
|
||||||
self.current_value = frappe.db.get_value("Series",
|
self.current_value = frappe.db.get_value("Series",
|
||||||
self.prefix.split('.')[0], "current")
|
self.prefix.split('.')[0], "current")
|
||||||
|
|
||||||
def insert_series(self, series):
|
def insert_series(self, series):
|
||||||
@ -136,7 +129,7 @@ class NamingSeries(Document):
|
|||||||
if self.prefix:
|
if self.prefix:
|
||||||
prefix = self.prefix.split('.')[0]
|
prefix = self.prefix.split('.')[0]
|
||||||
self.insert_series(prefix)
|
self.insert_series(prefix)
|
||||||
frappe.db.sql("update `tabSeries` set current = %s where name = %s",
|
frappe.db.sql("update `tabSeries` set current = %s where name = %s",
|
||||||
(self.current_value, prefix))
|
(self.current_value, prefix))
|
||||||
msgprint(_("Series Updated Successfully"))
|
msgprint(_("Series Updated Successfully"))
|
||||||
else:
|
else:
|
||||||
@ -149,8 +142,8 @@ def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True
|
|||||||
make_property_setter(doctype, "naming_series", "reqd", 1, "Check")
|
make_property_setter(doctype, "naming_series", "reqd", 1, "Check")
|
||||||
|
|
||||||
# set values for mandatory
|
# set values for mandatory
|
||||||
frappe.db.sql("""update `tab{doctype}` set naming_series={s} where
|
frappe.db.sql("""update `tab{doctype}` set naming_series={s} where
|
||||||
ifnull(naming_series, '')=''""".format(doctype=doctype, s="%s"),
|
ifnull(naming_series, '')=''""".format(doctype=doctype, s="%s"),
|
||||||
get_default_naming_series(doctype))
|
get_default_naming_series(doctype))
|
||||||
|
|
||||||
if hide_name_field:
|
if hide_name_field:
|
||||||
@ -165,10 +158,10 @@ def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True
|
|||||||
make_property_setter(doctype, fieldname, "reqd", 1, "Check")
|
make_property_setter(doctype, fieldname, "reqd", 1, "Check")
|
||||||
|
|
||||||
# set values for mandatory
|
# set values for mandatory
|
||||||
frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=`name` where
|
frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=`name` where
|
||||||
ifnull({fieldname}, '')=''""".format(doctype=doctype, fieldname=fieldname))
|
ifnull({fieldname}, '')=''""".format(doctype=doctype, fieldname=fieldname))
|
||||||
|
|
||||||
def get_default_naming_series(doctype):
|
def get_default_naming_series(doctype):
|
||||||
naming_series = frappe.get_meta(doctype).get_field("naming_series").options or ""
|
naming_series = frappe.get_meta(doctype).get_field("naming_series").options or ""
|
||||||
naming_series = naming_series.split("\n")
|
naming_series = naming_series.split("\n")
|
||||||
return naming_series[0] or naming_series[1]
|
return naming_series[0] or naming_series[1]
|
||||||
|
@ -10,19 +10,19 @@ from frappe.utils.nestedset import NestedSet
|
|||||||
class SalesPerson(NestedSet):
|
class SalesPerson(NestedSet):
|
||||||
nsm_parent_field = 'parent_sales_person';
|
nsm_parent_field = 'parent_sales_person';
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
for d in self.get('target_details'):
|
for d in self.get('target_details'):
|
||||||
if not flt(d.target_qty) and not flt(d.target_amount):
|
if not flt(d.target_qty) and not flt(d.target_amount):
|
||||||
frappe.throw(_("Either target qty or target amount is mandatory."))
|
frappe.throw(_("Either target qty or target amount is mandatory."))
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
super(SalesPerson, self).on_update()
|
super(SalesPerson, self).on_update()
|
||||||
self.validate_one_root()
|
self.validate_one_root()
|
||||||
|
|
||||||
def get_email_id(self):
|
def get_email_id(self):
|
||||||
if self.employee:
|
if self.employee:
|
||||||
user = frappe.db.get_value("Employee", self.employee, "user_id")
|
user = frappe.db.get_value("Employee", self.employee, "user_id")
|
||||||
if not user:
|
if not user:
|
||||||
frappe.throw("User ID not set for Employee %s" % self.employee)
|
frappe.throw(_("User ID not set for Employee {0}").format(self.employee))
|
||||||
else:
|
else:
|
||||||
return frappe.db.get_value("User", user, "email") or user
|
return frappe.db.get_value("User", user, "email") or user
|
||||||
|
@ -11,8 +11,7 @@ def get_company_currency(company):
|
|||||||
if not currency:
|
if not currency:
|
||||||
currency = frappe.db.get_default("currency")
|
currency = frappe.db.get_default("currency")
|
||||||
if not currency:
|
if not currency:
|
||||||
throw(_('Please specify Default Currency in Company Master \
|
throw(_('Please specify Default Currency in Company Master and Global Defaults'))
|
||||||
and Global Defaults'))
|
|
||||||
|
|
||||||
return currency
|
return currency
|
||||||
|
|
||||||
|
@ -109,8 +109,7 @@ class Item(WebsiteGenerator):
|
|||||||
self.is_pro_applicable = "No"
|
self.is_pro_applicable = "No"
|
||||||
|
|
||||||
if self.is_pro_applicable == 'Yes' and self.is_stock_item == 'No':
|
if self.is_pro_applicable == 'Yes' and self.is_stock_item == 'No':
|
||||||
frappe.throw(_("As Production Order can be made for this item, \
|
frappe.throw(_("As Production Order can be made for this item, it must be a stock item."))
|
||||||
it must be a stock item."))
|
|
||||||
|
|
||||||
if self.has_serial_no == 'Yes' and self.is_stock_item == 'No':
|
if self.has_serial_no == 'Yes' and self.is_stock_item == 'No':
|
||||||
msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1)
|
msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1)
|
||||||
@ -123,15 +122,13 @@ class Item(WebsiteGenerator):
|
|||||||
and t2.docstatus = 1 and t1.docstatus =1 """, self.name)
|
and t2.docstatus = 1 and t1.docstatus =1 """, self.name)
|
||||||
|
|
||||||
if bom_mat and bom_mat[0][0]:
|
if bom_mat and bom_mat[0][0]:
|
||||||
frappe.throw(_("Item must be a purchase item, \
|
frappe.throw(_("Item must be a purchase item, as it is present in one or many Active BOMs"))
|
||||||
as it is present in one or many Active BOMs"))
|
|
||||||
|
|
||||||
if self.is_manufactured_item != "Yes":
|
if self.is_manufactured_item != "Yes":
|
||||||
bom = frappe.db.sql("""select name from `tabBOM` where item = %s
|
bom = frappe.db.sql("""select name from `tabBOM` where item = %s
|
||||||
and is_active = 1""", (self.name,))
|
and is_active = 1""", (self.name,))
|
||||||
if bom and bom[0][0]:
|
if bom and bom[0][0]:
|
||||||
frappe.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many \
|
frappe.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many active BOMs present for this item"""))
|
||||||
active BOMs present for this 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 """
|
||||||
|
@ -17,41 +17,27 @@ class ItemPrice(Document):
|
|||||||
self.check_duplicate_item()
|
self.check_duplicate_item()
|
||||||
self.update_price_list_details()
|
self.update_price_list_details()
|
||||||
self.update_item_details()
|
self.update_item_details()
|
||||||
|
|
||||||
def validate_item(self):
|
def validate_item(self):
|
||||||
if not frappe.db.exists("Item", self.item_code):
|
if not frappe.db.exists("Item", self.item_code):
|
||||||
throw("{doctype}: {item} {not_found}".format(**{
|
throw(_("Item {0} not found").format(self.item_code))
|
||||||
"doctype": _("Item"),
|
|
||||||
"item": self.item_code,
|
|
||||||
"not_found": _(" not found")
|
|
||||||
}))
|
|
||||||
|
|
||||||
def validate_price_list(self):
|
def validate_price_list(self):
|
||||||
enabled = frappe.db.get_value("Price List", self.price_list, "enabled")
|
enabled = frappe.db.get_value("Price List", self.price_list, "enabled")
|
||||||
if not enabled:
|
if not enabled:
|
||||||
throw("{message}: {price_list} {disabled}".format(**{
|
throw(_("Price List {0} is disabled").format(self.price_list))
|
||||||
"message": _("Price List"),
|
|
||||||
"price_list": self.price_list,
|
|
||||||
"disabled": _("is disabled.")
|
|
||||||
}))
|
|
||||||
|
|
||||||
def check_duplicate_item(self):
|
def check_duplicate_item(self):
|
||||||
if frappe.db.sql("""select name from `tabItem Price`
|
if frappe.db.sql("""select name from `tabItem Price`
|
||||||
where item_code=%s and price_list=%s and name!=%s""",
|
where item_code=%s and price_list=%s and name!=%s""",
|
||||||
(self.item_code, self.price_list, self.name)):
|
(self.item_code, self.price_list, self.name)):
|
||||||
throw("{duplicate_item}: {item_code}, {already}: {price_list}".format(**{
|
frappe.throw(_("Item {0} appears multiple times in Price List {1}").format(self.item_code, self.price_list))
|
||||||
"duplicate_item": _("Duplicate Item"),
|
|
||||||
"item_code": self.item_code,
|
|
||||||
"already": _("already available in Price List"),
|
|
||||||
"price_list": self.price_list
|
|
||||||
}), ItemPriceDuplicateItem)
|
|
||||||
|
|
||||||
def update_price_list_details(self):
|
def update_price_list_details(self):
|
||||||
self.buying, self.selling, self.currency = \
|
self.buying, self.selling, self.currency = \
|
||||||
frappe.db.get_value("Price List", {"name": self.price_list, "enabled": 1},
|
frappe.db.get_value("Price List", {"name": self.price_list, "enabled": 1},
|
||||||
["buying", "selling", "currency"])
|
["buying", "selling", "currency"])
|
||||||
|
|
||||||
def update_item_details(self):
|
def update_item_details(self):
|
||||||
self.item_name, self.item_description = frappe.db.get_value("Item",
|
self.item_name, self.item_description = frappe.db.get_value("Item",
|
||||||
self.item_code, ["item_name", "description"])
|
self.item_code, ["item_name", "description"])
|
||||||
|
|
@ -8,7 +8,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from frappe.utils import cstr, flt
|
from frappe.utils import cstr, flt
|
||||||
from frappe import msgprint, _
|
from frappe import _
|
||||||
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
class MaterialRequest(BuyingController):
|
class MaterialRequest(BuyingController):
|
||||||
@ -43,9 +43,7 @@ class MaterialRequest(BuyingController):
|
|||||||
actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0
|
actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0
|
||||||
|
|
||||||
if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty):
|
if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty):
|
||||||
frappe.throw("You can raise indent of maximum qty: %s for item: %s against sales order: %s\
|
frappe.throw(_("Material Request of maximum {0} can be made for Item {1} against Sales Order {2}").format(actual_so_qty - already_indented, item, so_no))
|
||||||
\n Anyway, you can add more qty in new row for the same item."
|
|
||||||
% (actual_so_qty - already_indented, item, so_no))
|
|
||||||
|
|
||||||
def validate_schedule_date(self):
|
def validate_schedule_date(self):
|
||||||
for d in self.get('indent_details'):
|
for d in self.get('indent_details'):
|
||||||
|
@ -27,8 +27,7 @@ class SerialNo(StockController):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if self.get("__islocal") and self.warehouse:
|
if self.get("__islocal") and self.warehouse:
|
||||||
frappe.throw(_("New Serial No cannot have Warehouse. Warehouse must be \
|
frappe.throw(_("New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError)
|
||||||
set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError)
|
|
||||||
|
|
||||||
self.set_maintenance_status()
|
self.set_maintenance_status()
|
||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
@ -166,8 +165,7 @@ class SerialNo(StockController):
|
|||||||
if self.status == 'Delivered':
|
if self.status == 'Delivered':
|
||||||
frappe.throw(_("Delivered Serial No ") + self.name + _(" can not be deleted"))
|
frappe.throw(_("Delivered Serial No ") + self.name + _(" can not be deleted"))
|
||||||
if self.warehouse:
|
if self.warehouse:
|
||||||
frappe.throw(_("Cannot delete Serial No in warehouse. \
|
frappe.throw(_("Cannot delete Serial No in warehouse. First remove from warehouse, then delete.") + ": " + self.name)
|
||||||
First remove from warehouse, then delete.") + ": " + self.name)
|
|
||||||
|
|
||||||
def before_rename(self, old, new, merge=False):
|
def before_rename(self, old, new, merge=False):
|
||||||
if merge:
|
if merge:
|
||||||
|
@ -14,45 +14,45 @@ class StockReconciliation(StockController):
|
|||||||
def setup(self):
|
def setup(self):
|
||||||
self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"]
|
self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"]
|
||||||
self.entries = []
|
self.entries = []
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_data()
|
self.validate_data()
|
||||||
self.validate_expense_account()
|
self.validate_expense_account()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.insert_stock_ledger_entries()
|
self.insert_stock_ledger_entries()
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.delete_and_repost_sle()
|
self.delete_and_repost_sle()
|
||||||
self.make_cancel_gl_entries()
|
self.make_cancel_gl_entries()
|
||||||
|
|
||||||
def validate_data(self):
|
def validate_data(self):
|
||||||
if not self.reconciliation_json:
|
if not self.reconciliation_json:
|
||||||
return
|
return
|
||||||
|
|
||||||
data = json.loads(self.reconciliation_json)
|
data = json.loads(self.reconciliation_json)
|
||||||
|
|
||||||
# strip out extra columns (if any)
|
# strip out extra columns (if any)
|
||||||
data = [row[:4] for row in data]
|
data = [row[:4] for row in data]
|
||||||
|
|
||||||
if self.head_row not in data:
|
if self.head_row not in data:
|
||||||
msgprint(_("""Wrong Template: Unable to find head row."""),
|
msgprint(_("""Wrong Template: Unable to find head row."""),
|
||||||
raise_exception=1)
|
raise_exception=1)
|
||||||
|
|
||||||
# remove the help part and save the json
|
# remove the help part and save the json
|
||||||
head_row_no = 0
|
head_row_no = 0
|
||||||
if data.index(self.head_row) != 0:
|
if data.index(self.head_row) != 0:
|
||||||
head_row_no = data.index(self.head_row)
|
head_row_no = data.index(self.head_row)
|
||||||
data = data[head_row_no:]
|
data = data[head_row_no:]
|
||||||
self.reconciliation_json = json.dumps(data)
|
self.reconciliation_json = json.dumps(data)
|
||||||
|
|
||||||
def _get_msg(row_num, msg):
|
def _get_msg(row_num, msg):
|
||||||
return _("Row # ") + ("%d: " % (row_num+head_row_no+2)) + _(msg)
|
return _("Row # ") + ("%d: " % (row_num+head_row_no+2)) + _(msg)
|
||||||
|
|
||||||
self.validation_messages = []
|
self.validation_messages = []
|
||||||
item_warehouse_combinations = []
|
item_warehouse_combinations = []
|
||||||
|
|
||||||
# validate no of rows
|
# validate no of rows
|
||||||
rows = data[1:]
|
rows = data[1:]
|
||||||
if len(rows) > 100:
|
if len(rows) > 100:
|
||||||
@ -64,69 +64,66 @@ class StockReconciliation(StockController):
|
|||||||
self.validation_messages.append(_get_msg(row_num, "Duplicate entry"))
|
self.validation_messages.append(_get_msg(row_num, "Duplicate entry"))
|
||||||
else:
|
else:
|
||||||
item_warehouse_combinations.append([row[0], row[1]])
|
item_warehouse_combinations.append([row[0], row[1]])
|
||||||
|
|
||||||
self.validate_item(row[0], row_num+head_row_no+2)
|
self.validate_item(row[0], row_num+head_row_no+2)
|
||||||
# note: warehouse will be validated through link validation
|
# note: warehouse will be validated through link validation
|
||||||
|
|
||||||
# if both not specified
|
# if both not specified
|
||||||
if row[2] == "" and row[3] == "":
|
if row[2] == "" and row[3] == "":
|
||||||
self.validation_messages.append(_get_msg(row_num,
|
self.validation_messages.append(_get_msg(row_num,
|
||||||
"Please specify either Quantity or Valuation Rate or both"))
|
"Please specify either Quantity or Valuation Rate or both"))
|
||||||
|
|
||||||
# do not allow negative quantity
|
# do not allow negative quantity
|
||||||
if flt(row[2]) < 0:
|
if flt(row[2]) < 0:
|
||||||
self.validation_messages.append(_get_msg(row_num,
|
self.validation_messages.append(_get_msg(row_num,
|
||||||
"Negative Quantity is not allowed"))
|
"Negative Quantity is not allowed"))
|
||||||
|
|
||||||
# do not allow negative valuation
|
# do not allow negative valuation
|
||||||
if flt(row[3]) < 0:
|
if flt(row[3]) < 0:
|
||||||
self.validation_messages.append(_get_msg(row_num,
|
self.validation_messages.append(_get_msg(row_num,
|
||||||
"Negative Valuation Rate is not allowed"))
|
"Negative Valuation Rate is not allowed"))
|
||||||
|
|
||||||
# throw all validation messages
|
# throw all validation messages
|
||||||
if self.validation_messages:
|
if self.validation_messages:
|
||||||
for msg in self.validation_messages:
|
for msg in self.validation_messages:
|
||||||
msgprint(msg)
|
msgprint(msg)
|
||||||
|
|
||||||
raise frappe.ValidationError
|
raise frappe.ValidationError
|
||||||
|
|
||||||
def validate_item(self, item_code, row_num):
|
def validate_item(self, item_code, row_num):
|
||||||
from erpnext.stock.doctype.item.item import validate_end_of_life, \
|
from erpnext.stock.doctype.item.item import validate_end_of_life, \
|
||||||
validate_is_stock_item, validate_cancelled_item
|
validate_is_stock_item, validate_cancelled_item
|
||||||
|
|
||||||
# using try except to catch all validation msgs and display together
|
# using try except to catch all validation msgs and display together
|
||||||
|
|
||||||
try:
|
try:
|
||||||
item = frappe.get_doc("Item", item_code)
|
item = frappe.get_doc("Item", item_code)
|
||||||
|
|
||||||
# end of life and stock item
|
# end of life and stock item
|
||||||
validate_end_of_life(item_code, item.end_of_life, verbose=0)
|
validate_end_of_life(item_code, item.end_of_life, verbose=0)
|
||||||
validate_is_stock_item(item_code, item.is_stock_item, verbose=0)
|
validate_is_stock_item(item_code, item.is_stock_item, verbose=0)
|
||||||
|
|
||||||
# item should not be serialized
|
# item should not be serialized
|
||||||
if item.has_serial_no == "Yes":
|
if item.has_serial_no == "Yes":
|
||||||
raise frappe.ValidationError, (_("Serialized Item: '") + item_code +
|
raise frappe.ValidationError, _("Serialized Item {0} cannot be updated using Stock Reconciliation").format(item_code)
|
||||||
_("""' can not be managed using Stock Reconciliation.\
|
|
||||||
You can add/delete Serial No directly, \
|
|
||||||
to modify stock of this item."""))
|
|
||||||
|
|
||||||
# docstatus should be < 2
|
# docstatus should be < 2
|
||||||
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
||||||
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.validation_messages.append(_("Row # ") + ("%d: " % (row_num)) + cstr(e))
|
self.validation_messages.append(_("Row # ") + ("%d: " % (row_num)) + cstr(e))
|
||||||
|
|
||||||
def insert_stock_ledger_entries(self):
|
def insert_stock_ledger_entries(self):
|
||||||
""" find difference between current and expected entries
|
""" find difference between current and expected entries
|
||||||
and create stock ledger entries based on the difference"""
|
and create stock ledger entries based on the difference"""
|
||||||
from erpnext.stock.utils import get_valuation_method
|
from erpnext.stock.utils import get_valuation_method
|
||||||
from erpnext.stock.stock_ledger import get_previous_sle
|
from erpnext.stock.stock_ledger import get_previous_sle
|
||||||
|
|
||||||
row_template = ["item_code", "warehouse", "qty", "valuation_rate"]
|
row_template = ["item_code", "warehouse", "qty", "valuation_rate"]
|
||||||
|
|
||||||
if not self.reconciliation_json:
|
if not self.reconciliation_json:
|
||||||
msgprint(_("""Stock Reconciliation file not uploaded"""), raise_exception=1)
|
msgprint(_("""Stock Reconciliation file not uploaded"""), raise_exception=1)
|
||||||
|
|
||||||
data = json.loads(self.reconciliation_json)
|
data = json.loads(self.reconciliation_json)
|
||||||
for row_num, row in enumerate(data[data.index(self.head_row)+1:]):
|
for row_num, row in enumerate(data[data.index(self.head_row)+1:]):
|
||||||
row = frappe._dict(zip(row_template, row))
|
row = frappe._dict(zip(row_template, row))
|
||||||
@ -141,22 +138,22 @@ class StockReconciliation(StockController):
|
|||||||
# check valuation rate mandatory
|
# check valuation rate mandatory
|
||||||
if row.qty != "" and not row.valuation_rate and \
|
if row.qty != "" and not row.valuation_rate and \
|
||||||
flt(previous_sle.get("qty_after_transaction")) <= 0:
|
flt(previous_sle.get("qty_after_transaction")) <= 0:
|
||||||
frappe.throw(_("As existing qty for item: ") + row.item_code +
|
frappe.throw(_("As existing qty for item: ") + row.item_code +
|
||||||
_(" at warehouse: ") + row.warehouse +
|
_(" at warehouse: ") + row.warehouse +
|
||||||
_(" is less than equals to zero in the system, valuation rate is mandatory for this item"))
|
_(" is less than equals to zero in the system, valuation rate is mandatory for this item"))
|
||||||
|
|
||||||
change_in_qty = row.qty != "" and \
|
change_in_qty = row.qty != "" and \
|
||||||
(flt(row.qty) - flt(previous_sle.get("qty_after_transaction")))
|
(flt(row.qty) - flt(previous_sle.get("qty_after_transaction")))
|
||||||
|
|
||||||
change_in_rate = row.valuation_rate != "" and \
|
change_in_rate = row.valuation_rate != "" and \
|
||||||
(flt(row.valuation_rate) - flt(previous_sle.get("valuation_rate")))
|
(flt(row.valuation_rate) - flt(previous_sle.get("valuation_rate")))
|
||||||
|
|
||||||
if get_valuation_method(row.item_code) == "Moving Average":
|
if get_valuation_method(row.item_code) == "Moving Average":
|
||||||
self.sle_for_moving_avg(row, previous_sle, change_in_qty, change_in_rate)
|
self.sle_for_moving_avg(row, previous_sle, change_in_qty, change_in_rate)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.sle_for_fifo(row, previous_sle, change_in_qty, change_in_rate)
|
self.sle_for_fifo(row, previous_sle, change_in_qty, change_in_rate)
|
||||||
|
|
||||||
def sle_for_moving_avg(self, row, previous_sle, change_in_qty, change_in_rate):
|
def sle_for_moving_avg(self, row, previous_sle, change_in_qty, change_in_rate):
|
||||||
"""Insert Stock Ledger Entries for Moving Average valuation"""
|
"""Insert Stock Ledger Entries for Moving Average valuation"""
|
||||||
def _get_incoming_rate(qty, valuation_rate, previous_qty, previous_valuation_rate):
|
def _get_incoming_rate(qty, valuation_rate, previous_qty, previous_valuation_rate):
|
||||||
@ -167,73 +164,73 @@ class StockReconciliation(StockController):
|
|||||||
valuation_rate = previous_valuation_rate
|
valuation_rate = previous_valuation_rate
|
||||||
return (qty * valuation_rate - previous_qty * previous_valuation_rate) \
|
return (qty * valuation_rate - previous_qty * previous_valuation_rate) \
|
||||||
/ flt(qty - previous_qty)
|
/ flt(qty - previous_qty)
|
||||||
|
|
||||||
if change_in_qty:
|
if change_in_qty:
|
||||||
# if change in qty, irrespective of change in rate
|
# if change in qty, irrespective of change in rate
|
||||||
incoming_rate = _get_incoming_rate(flt(row.qty), flt(row.valuation_rate),
|
incoming_rate = _get_incoming_rate(flt(row.qty), flt(row.valuation_rate),
|
||||||
flt(previous_sle.get("qty_after_transaction")),
|
flt(previous_sle.get("qty_after_transaction")),
|
||||||
flt(previous_sle.get("valuation_rate")))
|
flt(previous_sle.get("valuation_rate")))
|
||||||
|
|
||||||
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry"
|
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry"
|
||||||
self.insert_entries({"actual_qty": change_in_qty, "incoming_rate": incoming_rate}, row)
|
self.insert_entries({"actual_qty": change_in_qty, "incoming_rate": incoming_rate}, row)
|
||||||
|
|
||||||
elif change_in_rate and flt(previous_sle.get("qty_after_transaction")) > 0:
|
elif change_in_rate and flt(previous_sle.get("qty_after_transaction")) > 0:
|
||||||
# if no change in qty, but change in rate
|
# if no change in qty, but change in rate
|
||||||
# and positive actual stock before this reconciliation
|
# and positive actual stock before this reconciliation
|
||||||
incoming_rate = _get_incoming_rate(
|
incoming_rate = _get_incoming_rate(
|
||||||
flt(previous_sle.get("qty_after_transaction"))+1, flt(row.valuation_rate),
|
flt(previous_sle.get("qty_after_transaction"))+1, flt(row.valuation_rate),
|
||||||
flt(previous_sle.get("qty_after_transaction")),
|
flt(previous_sle.get("qty_after_transaction")),
|
||||||
flt(previous_sle.get("valuation_rate")))
|
flt(previous_sle.get("valuation_rate")))
|
||||||
|
|
||||||
# +1 entry
|
# +1 entry
|
||||||
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment +1"
|
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment +1"
|
||||||
self.insert_entries({"actual_qty": 1, "incoming_rate": incoming_rate}, row)
|
self.insert_entries({"actual_qty": 1, "incoming_rate": incoming_rate}, row)
|
||||||
|
|
||||||
# -1 entry
|
# -1 entry
|
||||||
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment -1"
|
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment -1"
|
||||||
self.insert_entries({"actual_qty": -1}, row)
|
self.insert_entries({"actual_qty": -1}, row)
|
||||||
|
|
||||||
def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate):
|
def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate):
|
||||||
"""Insert Stock Ledger Entries for FIFO valuation"""
|
"""Insert Stock Ledger Entries for FIFO valuation"""
|
||||||
previous_stock_queue = json.loads(previous_sle.get("stock_queue") or "[]")
|
previous_stock_queue = json.loads(previous_sle.get("stock_queue") or "[]")
|
||||||
previous_stock_qty = sum((batch[0] for batch in previous_stock_queue))
|
previous_stock_qty = sum((batch[0] for batch in previous_stock_queue))
|
||||||
previous_stock_value = sum((batch[0] * batch[1] for batch in \
|
previous_stock_value = sum((batch[0] * batch[1] for batch in \
|
||||||
previous_stock_queue))
|
previous_stock_queue))
|
||||||
|
|
||||||
def _insert_entries():
|
def _insert_entries():
|
||||||
if previous_stock_queue != [[row.qty, row.valuation_rate]]:
|
if previous_stock_queue != [[row.qty, row.valuation_rate]]:
|
||||||
# make entry as per attachment
|
# make entry as per attachment
|
||||||
if row.qty:
|
if row.qty:
|
||||||
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry"
|
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry"
|
||||||
self.insert_entries({"actual_qty": row.qty,
|
self.insert_entries({"actual_qty": row.qty,
|
||||||
"incoming_rate": flt(row.valuation_rate)}, row)
|
"incoming_rate": flt(row.valuation_rate)}, row)
|
||||||
|
|
||||||
# Make reverse entry
|
# Make reverse entry
|
||||||
if previous_stock_qty:
|
if previous_stock_qty:
|
||||||
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Reverse Entry"
|
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Reverse Entry"
|
||||||
self.insert_entries({"actual_qty": -1 * previous_stock_qty,
|
self.insert_entries({"actual_qty": -1 * previous_stock_qty,
|
||||||
"incoming_rate": previous_stock_qty < 0 and
|
"incoming_rate": previous_stock_qty < 0 and
|
||||||
flt(row.valuation_rate) or 0}, row)
|
flt(row.valuation_rate) or 0}, row)
|
||||||
|
|
||||||
|
|
||||||
if change_in_qty:
|
if change_in_qty:
|
||||||
if row.valuation_rate == "":
|
if row.valuation_rate == "":
|
||||||
# dont want change in valuation
|
# dont want change in valuation
|
||||||
if previous_stock_qty > 0:
|
if previous_stock_qty > 0:
|
||||||
# set valuation_rate as previous valuation_rate
|
# set valuation_rate as previous valuation_rate
|
||||||
row.valuation_rate = previous_stock_value / flt(previous_stock_qty)
|
row.valuation_rate = previous_stock_value / flt(previous_stock_qty)
|
||||||
|
|
||||||
_insert_entries()
|
_insert_entries()
|
||||||
|
|
||||||
elif change_in_rate and previous_stock_qty > 0:
|
elif change_in_rate and previous_stock_qty > 0:
|
||||||
# if no change in qty, but change in rate
|
# if no change in qty, but change in rate
|
||||||
# and positive actual stock before this reconciliation
|
# and positive actual stock before this reconciliation
|
||||||
|
|
||||||
row.qty = previous_stock_qty
|
row.qty = previous_stock_qty
|
||||||
_insert_entries()
|
_insert_entries()
|
||||||
|
|
||||||
def insert_entries(self, opts, row):
|
def insert_entries(self, opts, row):
|
||||||
"""Insert Stock Ledger Entries"""
|
"""Insert Stock Ledger Entries"""
|
||||||
args = frappe._dict({
|
args = frappe._dict({
|
||||||
"doctype": "Stock Ledger Entry",
|
"doctype": "Stock Ledger Entry",
|
||||||
"item_code": row.item_code,
|
"item_code": row.item_code,
|
||||||
@ -253,19 +250,19 @@ class StockReconciliation(StockController):
|
|||||||
|
|
||||||
# append to entries
|
# append to entries
|
||||||
self.entries.append(args)
|
self.entries.append(args)
|
||||||
|
|
||||||
def delete_and_repost_sle(self):
|
def delete_and_repost_sle(self):
|
||||||
""" Delete Stock Ledger Entries related to this voucher
|
""" Delete Stock Ledger Entries related to this voucher
|
||||||
and repost future Stock Ledger Entries"""
|
and repost future Stock Ledger Entries"""
|
||||||
|
|
||||||
existing_entries = frappe.db.sql("""select distinct item_code, warehouse
|
existing_entries = frappe.db.sql("""select distinct item_code, warehouse
|
||||||
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
|
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
|
||||||
(self.doctype, self.name), as_dict=1)
|
(self.doctype, self.name), as_dict=1)
|
||||||
|
|
||||||
# delete entries
|
# delete entries
|
||||||
frappe.db.sql("""delete from `tabStock Ledger Entry`
|
frappe.db.sql("""delete from `tabStock Ledger Entry`
|
||||||
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
|
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
|
||||||
|
|
||||||
# repost future entries for selected item_code, warehouse
|
# repost future entries for selected item_code, warehouse
|
||||||
for entries in existing_entries:
|
for entries in existing_entries:
|
||||||
update_entries_after({
|
update_entries_after({
|
||||||
@ -274,29 +271,26 @@ class StockReconciliation(StockController):
|
|||||||
"posting_date": self.posting_date,
|
"posting_date": self.posting_date,
|
||||||
"posting_time": self.posting_time
|
"posting_time": self.posting_time
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
if not self.cost_center:
|
if not self.cost_center:
|
||||||
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
||||||
|
|
||||||
return super(StockReconciliation, self).get_gl_entries(warehouse_account,
|
return super(StockReconciliation, self).get_gl_entries(warehouse_account,
|
||||||
self.expense_account, self.cost_center)
|
self.expense_account, self.cost_center)
|
||||||
|
|
||||||
def validate_expense_account(self):
|
def validate_expense_account(self):
|
||||||
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.expense_account:
|
if not self.expense_account:
|
||||||
msgprint(_("Please enter Expense Account"), raise_exception=1)
|
msgprint(_("Please enter Expense Account"), raise_exception=1)
|
||||||
elif not frappe.db.sql("""select * from `tabStock Ledger Entry`"""):
|
elif not frappe.db.sql("""select * from `tabStock Ledger Entry`"""):
|
||||||
if frappe.db.get_value("Account", self.expense_account,
|
if frappe.db.get_value("Account", self.expense_account,
|
||||||
"report_type") == "Profit and Loss":
|
"report_type") == "Profit and Loss":
|
||||||
msgprint(_("""Expense Account can not be a PL Account, as this stock \
|
frappe.throw(_("'Profit and Loss' type Account {0} used be set for Opening Entry").format(self.expense_account))
|
||||||
reconciliation is an opening entry. \
|
|
||||||
Please select 'Temporary Account (Liabilities)' or relevant account"""),
|
|
||||||
raise_exception=1)
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def upload():
|
def upload():
|
||||||
from frappe.utils.datautils import read_csv_content_from_uploaded_file
|
from frappe.utils.datautils import read_csv_content_from_uploaded_file
|
||||||
return read_csv_content_from_uploaded_file()
|
return read_csv_content_from_uploaded_file()
|
||||||
|
@ -65,8 +65,7 @@ class Warehouse(Document):
|
|||||||
if parent_account:
|
if parent_account:
|
||||||
self.create_account_under = parent_account
|
self.create_account_under = parent_account
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Please enter account group under which account \
|
frappe.throw(_("Please enter parent account group for warehouse account"))
|
||||||
for warehouse ") + self.name +_(" will be created"))
|
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
# delete bin
|
# delete bin
|
||||||
@ -75,8 +74,7 @@ class Warehouse(Document):
|
|||||||
for d in bins:
|
for d in bins:
|
||||||
if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or \
|
if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or \
|
||||||
d['indented_qty'] or d['projected_qty'] or d['planned_qty']:
|
d['indented_qty'] or d['projected_qty'] or d['planned_qty']:
|
||||||
throw("""Warehouse: %s can not be deleted as qty exists for item: %s"""
|
throw(_("Warehouse {0} can not be deleted as quantity exists for Item {1}").format(self.name, d['item_code']))
|
||||||
% (self.name, d['item_code']))
|
|
||||||
else:
|
else:
|
||||||
frappe.db.sql("delete from `tabBin` where name = %s", d['name'])
|
frappe.db.sql("delete from `tabBin` where name = %s", d['name'])
|
||||||
|
|
||||||
@ -87,8 +85,7 @@ class Warehouse(Document):
|
|||||||
|
|
||||||
if frappe.db.sql("""select name from `tabStock Ledger Entry`
|
if frappe.db.sql("""select name from `tabStock Ledger Entry`
|
||||||
where warehouse = %s""", self.name):
|
where warehouse = %s""", self.name):
|
||||||
throw(_("""Warehouse can not be deleted as stock ledger entry
|
throw(_("Warehouse can not be deleted as stock ledger entry exists for this warehouse."))
|
||||||
exists for this warehouse."""))
|
|
||||||
|
|
||||||
def before_rename(self, olddn, newdn, merge=False):
|
def before_rename(self, olddn, newdn, merge=False):
|
||||||
# Add company abbr if not provided
|
# Add company abbr if not provided
|
||||||
|
@ -11,19 +11,19 @@ from erpnext.utilities.transaction_base import TransactionBase, delete_events
|
|||||||
from erpnext.stock.utils import get_valid_serial_nos
|
from erpnext.stock.utils import get_valid_serial_nos
|
||||||
|
|
||||||
class MaintenanceSchedule(TransactionBase):
|
class MaintenanceSchedule(TransactionBase):
|
||||||
|
|
||||||
def get_item_details(self, item_code):
|
def get_item_details(self, item_code):
|
||||||
item = frappe.db.sql("""select item_name, description from `tabItem`
|
item = frappe.db.sql("""select item_name, description from `tabItem`
|
||||||
where name=%s""", (item_code), as_dict=1)
|
where name=%s""", (item_code), as_dict=1)
|
||||||
ret = {
|
ret = {
|
||||||
'item_name': item and item[0]['item_name'] or '',
|
'item_name': item and item[0]['item_name'] or '',
|
||||||
'description' : item and item[0]['description'] or ''
|
'description' : item and item[0]['description'] or ''
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def generate_schedule(self):
|
def generate_schedule(self):
|
||||||
self.set('maintenance_schedule_detail', [])
|
self.set('maintenance_schedule_detail', [])
|
||||||
frappe.db.sql("""delete from `tabMaintenance Schedule Detail`
|
frappe.db.sql("""delete from `tabMaintenance Schedule Detail`
|
||||||
where parent=%s""", (self.name))
|
where parent=%s""", (self.name))
|
||||||
count = 1
|
count = 1
|
||||||
for d in self.get('item_maintenance_detail'):
|
for d in self.get('item_maintenance_detail'):
|
||||||
@ -41,7 +41,7 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
count = count + 1
|
count = count + 1
|
||||||
child.sales_person = d.sales_person
|
child.sales_person = d.sales_person
|
||||||
child.save(1)
|
child.save(1)
|
||||||
|
|
||||||
self.on_update()
|
self.on_update()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
@ -61,8 +61,8 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
sp = frappe.get_doc("Sales Person", d.sales_person)
|
sp = frappe.get_doc("Sales Person", d.sales_person)
|
||||||
email_map[d.sales_person] = sp.get_email_id()
|
email_map[d.sales_person] = sp.get_email_id()
|
||||||
|
|
||||||
scheduled_date = frappe.db.sql("""select scheduled_date from
|
scheduled_date = frappe.db.sql("""select scheduled_date from
|
||||||
`tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and
|
`tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and
|
||||||
parent=%s""", (d.sales_person, d.item_code, self.name), as_dict=1)
|
parent=%s""", (d.sales_person, d.item_code, self.name), as_dict=1)
|
||||||
|
|
||||||
for key in scheduled_date:
|
for key in scheduled_date:
|
||||||
@ -80,10 +80,10 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
"ref_name": self.name
|
"ref_name": self.name
|
||||||
}).insert(ignore_permissions=1)
|
}).insert(ignore_permissions=1)
|
||||||
|
|
||||||
frappe.db.set(self, 'status', 'Submitted')
|
frappe.db.set(self, 'status', 'Submitted')
|
||||||
|
|
||||||
def create_schedule_list(self, start_date, end_date, no_of_visit, sales_person):
|
def create_schedule_list(self, start_date, end_date, no_of_visit, sales_person):
|
||||||
schedule_list = []
|
schedule_list = []
|
||||||
start_date_copy = start_date
|
start_date_copy = start_date
|
||||||
date_diff = (getdate(end_date) - getdate(start_date)).days
|
date_diff = (getdate(end_date) - getdate(start_date)).days
|
||||||
add_by = date_diff / no_of_visit
|
add_by = date_diff / no_of_visit
|
||||||
@ -92,7 +92,7 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
if (getdate(start_date_copy) < getdate(end_date)):
|
if (getdate(start_date_copy) < getdate(end_date)):
|
||||||
start_date_copy = add_days(start_date_copy, add_by)
|
start_date_copy = add_days(start_date_copy, add_by)
|
||||||
if len(schedule_list) < no_of_visit:
|
if len(schedule_list) < no_of_visit:
|
||||||
schedule_date = self.validate_schedule_date_for_holiday_list(getdate(start_date_copy),
|
schedule_date = self.validate_schedule_date_for_holiday_list(getdate(start_date_copy),
|
||||||
sales_person)
|
sales_person)
|
||||||
if schedule_date > getdate(end_date):
|
if schedule_date > getdate(end_date):
|
||||||
schedule_date = getdate(end_date)
|
schedule_date = getdate(end_date)
|
||||||
@ -112,17 +112,17 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
|
|
||||||
if fy_details and fy_details[0]:
|
if fy_details and fy_details[0]:
|
||||||
# check holiday list in employee master
|
# check holiday list in employee master
|
||||||
holiday_list = frappe.db.sql_list("""select h.holiday_date from `tabEmployee` emp,
|
holiday_list = frappe.db.sql_list("""select h.holiday_date from `tabEmployee` emp,
|
||||||
`tabSales Person` sp, `tabHoliday` h, `tabHoliday List` hl
|
`tabSales Person` sp, `tabHoliday` h, `tabHoliday List` hl
|
||||||
where sp.name=%s and emp.name=sp.employee
|
where sp.name=%s and emp.name=sp.employee
|
||||||
and hl.name=emp.holiday_list and
|
and hl.name=emp.holiday_list and
|
||||||
h.parent=hl.name and
|
h.parent=hl.name and
|
||||||
hl.fiscal_year=%s""", (sales_person, fy_details[0]))
|
hl.fiscal_year=%s""", (sales_person, fy_details[0]))
|
||||||
if not holiday_list:
|
if not holiday_list:
|
||||||
# check global holiday list
|
# check global holiday list
|
||||||
holiday_list = frappe.db.sql("""select h.holiday_date from
|
holiday_list = frappe.db.sql("""select h.holiday_date from
|
||||||
`tabHoliday` h, `tabHoliday List` hl
|
`tabHoliday` h, `tabHoliday List` hl
|
||||||
where h.parent=hl.name and ifnull(hl.is_default, 0) = 1
|
where h.parent=hl.name and ifnull(hl.is_default, 0) = 1
|
||||||
and hl.fiscal_year=%s""", fy_details[0])
|
and hl.fiscal_year=%s""", fy_details[0])
|
||||||
|
|
||||||
if not validated and holiday_list:
|
if not validated and holiday_list:
|
||||||
@ -140,14 +140,14 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
|
|
||||||
period = (getdate(args['end_date']) - getdate(args['start_date'])).days + 1
|
period = (getdate(args['end_date']) - getdate(args['start_date'])).days + 1
|
||||||
|
|
||||||
if (args['periodicity'] == 'Yearly' or args['periodicity'] == 'Half Yearly' or
|
if (args['periodicity'] == 'Yearly' or args['periodicity'] == 'Half Yearly' or
|
||||||
args['periodicity'] == 'Quarterly') and period < 365:
|
args['periodicity'] == 'Quarterly') and period < 365:
|
||||||
throw(cstr(args['periodicity']) + " periodicity can be set for period of atleast 1 year or more only")
|
throw(cstr(args['periodicity']) + " periodicity can be set for period of atleast 1 year or more only")
|
||||||
elif args['periodicity'] == 'Monthly' and period < 30:
|
elif args['periodicity'] == 'Monthly' and period < 30:
|
||||||
throw("Monthly periodicity can be set for period of atleast 1 month or more")
|
throw("Monthly periodicity can be set for period of atleast 1 month or more")
|
||||||
elif args['periodicity'] == 'Weekly' and period < 7:
|
elif args['periodicity'] == 'Weekly' and period < 7:
|
||||||
throw("Weekly periodicity can be set for period of atleast 1 week or more")
|
throw("Weekly periodicity can be set for period of atleast 1 week or more")
|
||||||
|
|
||||||
def get_no_of_visits(self, arg):
|
def get_no_of_visits(self, arg):
|
||||||
args = eval(arg)
|
args = eval(arg)
|
||||||
self.validate_period(arg)
|
self.validate_period(arg)
|
||||||
@ -159,19 +159,19 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
elif args['periodicity'] == 'Monthly':
|
elif args['periodicity'] == 'Monthly':
|
||||||
count = period/30
|
count = period/30
|
||||||
elif args['periodicity'] == 'Quarterly':
|
elif args['periodicity'] == 'Quarterly':
|
||||||
count = period/91
|
count = period/91
|
||||||
elif args['periodicity'] == 'Half Yearly':
|
elif args['periodicity'] == 'Half Yearly':
|
||||||
count = period/182
|
count = period/182
|
||||||
elif args['periodicity'] == 'Yearly':
|
elif args['periodicity'] == 'Yearly':
|
||||||
count = period/365
|
count = period/365
|
||||||
|
|
||||||
ret = {'no_of_visits' : count}
|
ret = {'no_of_visits' : count}
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def validate_maintenance_detail(self):
|
def validate_maintenance_detail(self):
|
||||||
if not self.get('item_maintenance_detail'):
|
if not self.get('item_maintenance_detail'):
|
||||||
throw(_("Please enter Maintaince Details first"))
|
throw(_("Please enter Maintaince Details first"))
|
||||||
|
|
||||||
for d in self.get('item_maintenance_detail'):
|
for d in self.get('item_maintenance_detail'):
|
||||||
if not d.item_code:
|
if not d.item_code:
|
||||||
throw(_("Please select item code"))
|
throw(_("Please select item code"))
|
||||||
@ -181,23 +181,23 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
throw(_("Please mention no of visits required"))
|
throw(_("Please mention no of visits required"))
|
||||||
elif not d.sales_person:
|
elif not d.sales_person:
|
||||||
throw(_("Please select Incharge Person's name"))
|
throw(_("Please select Incharge Person's name"))
|
||||||
|
|
||||||
if getdate(d.start_date) >= getdate(d.end_date):
|
if getdate(d.start_date) >= getdate(d.end_date):
|
||||||
throw(_("Start date should be less than end date for item") + " " + d.item_code)
|
throw(_("Start date should be less than end date for item") + " " + d.item_code)
|
||||||
|
|
||||||
def validate_sales_order(self):
|
def validate_sales_order(self):
|
||||||
for d in self.get('item_maintenance_detail'):
|
for d in self.get('item_maintenance_detail'):
|
||||||
if d.prevdoc_docname:
|
if d.prevdoc_docname:
|
||||||
chk = frappe.db.sql("""select ms.name from `tabMaintenance Schedule` ms,
|
chk = frappe.db.sql("""select ms.name from `tabMaintenance Schedule` ms,
|
||||||
`tabMaintenance Schedule Item` msi where msi.parent=ms.name and
|
`tabMaintenance Schedule Item` msi where msi.parent=ms.name and
|
||||||
msi.prevdoc_docname=%s and ms.docstatus=1""", d.prevdoc_docname)
|
msi.prevdoc_docname=%s and ms.docstatus=1""", d.prevdoc_docname)
|
||||||
if chk:
|
if chk:
|
||||||
throw("Maintenance Schedule against " + d.prevdoc_docname + " already exist")
|
throw("Maintenance Schedule against " + d.prevdoc_docname + " already exist")
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_maintenance_detail()
|
self.validate_maintenance_detail()
|
||||||
self.validate_sales_order()
|
self.validate_sales_order()
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
frappe.db.set(self, 'status', 'Draft')
|
frappe.db.set(self, 'status', 'Draft')
|
||||||
|
|
||||||
@ -209,21 +209,20 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
|
|
||||||
def validate_serial_no(self, serial_nos, amc_start_date):
|
def validate_serial_no(self, serial_nos, amc_start_date):
|
||||||
for serial_no in serial_nos:
|
for serial_no in serial_nos:
|
||||||
sr_details = frappe.db.get_value("Serial No", serial_no,
|
sr_details = frappe.db.get_value("Serial No", serial_no,
|
||||||
["warranty_expiry_date", "amc_expiry_date", "status", "delivery_date"], as_dict=1)
|
["warranty_expiry_date", "amc_expiry_date", "status", "delivery_date"], as_dict=1)
|
||||||
|
|
||||||
if sr_details.warranty_expiry_date and sr_details.warranty_expiry_date>=amc_start_date:
|
if sr_details.warranty_expiry_date and sr_details.warranty_expiry_date>=amc_start_date:
|
||||||
throw("""Serial No: %s is already under warranty upto %s.
|
throw("""Serial No: %s is already under warranty upto %s.
|
||||||
Please check AMC Start Date.""" % (serial_no, sr_details.warranty_expiry_date))
|
Please check AMC Start Date.""" % (serial_no, sr_details.warranty_expiry_date))
|
||||||
|
|
||||||
if sr_details.amc_expiry_date and sr_details.amc_expiry_date >= amc_start_date:
|
if sr_details.amc_expiry_date and sr_details.amc_expiry_date >= amc_start_date:
|
||||||
throw("""Serial No: %s is already under AMC upto %s.
|
throw("""Serial No: %s is already under AMC upto %s.
|
||||||
Please check AMC Start Date.""" % (serial_no, sr_details.amc_expiry_date))
|
Please check AMC Start Date.""" % (serial_no, sr_details.amc_expiry_date))
|
||||||
|
|
||||||
if sr_details.status=="Delivered" and sr_details.delivery_date and \
|
if sr_details.status=="Delivered" and sr_details.delivery_date and \
|
||||||
sr_details.delivery_date >= amc_start_date:
|
sr_details.delivery_date >= amc_start_date:
|
||||||
throw(_("Maintenance start date can not be before \
|
throw(_("Maintenance start date can not be before delivery date for Serial No {0}").format(serial_no))
|
||||||
delivery date for serial no: ") + serial_no)
|
|
||||||
|
|
||||||
def validate_schedule(self):
|
def validate_schedule(self):
|
||||||
item_lst1 =[]
|
item_lst1 =[]
|
||||||
@ -231,26 +230,25 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
for d in self.get('item_maintenance_detail'):
|
for d in self.get('item_maintenance_detail'):
|
||||||
if d.item_code not in item_lst1:
|
if d.item_code not in item_lst1:
|
||||||
item_lst1.append(d.item_code)
|
item_lst1.append(d.item_code)
|
||||||
|
|
||||||
for m in self.get('maintenance_schedule_detail'):
|
for m in self.get('maintenance_schedule_detail'):
|
||||||
if m.item_code not in item_lst2:
|
if m.item_code not in item_lst2:
|
||||||
item_lst2.append(m.item_code)
|
item_lst2.append(m.item_code)
|
||||||
|
|
||||||
if len(item_lst1) != len(item_lst2):
|
if len(item_lst1) != len(item_lst2):
|
||||||
throw(_("Maintenance Schedule is not generated for all the items. \
|
throw(_("Maintenance Schedule is not generated for all the items. Please click on 'Generate Schedule'"))
|
||||||
Please click on 'Generate Schedule'"))
|
|
||||||
else:
|
else:
|
||||||
for x in item_lst1:
|
for x in item_lst1:
|
||||||
if x not in item_lst2:
|
if x not in item_lst2:
|
||||||
throw(_("Maintenance Schedule is not generated for item ") + x +
|
throw(_("Maintenance Schedule is not generated for item ") + x +
|
||||||
_(". Please click on 'Generate Schedule'"))
|
_(". Please click on 'Generate Schedule'"))
|
||||||
|
|
||||||
def check_serial_no_added(self):
|
def check_serial_no_added(self):
|
||||||
serial_present =[]
|
serial_present =[]
|
||||||
for d in self.get('item_maintenance_detail'):
|
for d in self.get('item_maintenance_detail'):
|
||||||
if d.serial_no:
|
if d.serial_no:
|
||||||
serial_present.append(d.item_code)
|
serial_present.append(d.item_code)
|
||||||
|
|
||||||
for m in self.get('maintenance_schedule_detail'):
|
for m in self.get('maintenance_schedule_detail'):
|
||||||
if serial_present:
|
if serial_present:
|
||||||
if m.item_code in serial_present and not m.serial_no:
|
if m.item_code in serial_present and not m.serial_no:
|
||||||
@ -270,13 +268,13 @@ class MaintenanceSchedule(TransactionBase):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_maintenance_visit(source_name, target_doc=None):
|
def make_maintenance_visit(source_name, target_doc=None):
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
|
||||||
def update_status(source, target, parent):
|
def update_status(source, target, parent):
|
||||||
target.maintenance_type = "Scheduled"
|
target.maintenance_type = "Scheduled"
|
||||||
|
|
||||||
doclist = get_mapped_doc("Maintenance Schedule", source_name, {
|
doclist = get_mapped_doc("Maintenance Schedule", source_name, {
|
||||||
"Maintenance Schedule": {
|
"Maintenance Schedule": {
|
||||||
"doctype": "Maintenance Visit",
|
"doctype": "Maintenance Visit",
|
||||||
"field_map": {
|
"field_map": {
|
||||||
"name": "maintenance_schedule"
|
"name": "maintenance_schedule"
|
||||||
},
|
},
|
||||||
@ -284,15 +282,15 @@ def make_maintenance_visit(source_name, target_doc=None):
|
|||||||
"docstatus": ["=", 1]
|
"docstatus": ["=", 1]
|
||||||
},
|
},
|
||||||
"postprocess": update_status
|
"postprocess": update_status
|
||||||
},
|
},
|
||||||
"Maintenance Schedule Item": {
|
"Maintenance Schedule Item": {
|
||||||
"doctype": "Maintenance Visit Purpose",
|
"doctype": "Maintenance Visit Purpose",
|
||||||
"field_map": {
|
"field_map": {
|
||||||
"parent": "prevdoc_docname",
|
"parent": "prevdoc_docname",
|
||||||
"parenttype": "prevdoc_doctype",
|
"parenttype": "prevdoc_doctype",
|
||||||
"sales_person": "service_person"
|
"sales_person": "service_person"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, target_doc)
|
}, target_doc)
|
||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
Loading…
x
Reference in New Issue
Block a user