Replaced doc, doc.fields frappe/frappe#478

This commit is contained in:
Anand Doshi 2014-03-28 13:55:00 +05:30
parent 67d6a4e3aa
commit f78d1aee28
142 changed files with 2443 additions and 2444 deletions

View File

@ -15,13 +15,13 @@ class Account(Document):
nsm_parent_field = 'parent_account' nsm_parent_field = 'parent_account'
def autoname(self): def autoname(self):
self.doc.name = self.doc.account_name.strip() + ' - ' + \ self.name = self.account_name.strip() + ' - ' + \
frappe.db.get_value("Company", self.doc.company, "abbr") frappe.db.get_value("Company", self.company, "abbr")
def get_address(self): def get_address(self):
return { return {
'address': frappe.db.get_value(self.doc.master_type, 'address': frappe.db.get_value(self.master_type,
self.doc.master_name, "address") self.master_name, "address")
} }
def validate(self): def validate(self):
@ -33,54 +33,54 @@ class Account(Document):
self.validate_warehouse_account() self.validate_warehouse_account()
self.validate_frozen_accounts_modifier() self.validate_frozen_accounts_modifier()
if not self.doc.parent_account: if not self.parent_account:
self.doc.parent_account = '' self.parent_account = ''
def validate_master_name(self): def validate_master_name(self):
"""Remind to add master name""" """Remind to add master name"""
if self.doc.master_type in ('Customer', 'Supplier') or self.doc.account_type == "Warehouse": if self.master_type in ('Customer', 'Supplier') or self.account_type == "Warehouse":
if not self.doc.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.doc.master_type or self.doc.account_type, elif not frappe.db.exists(self.master_type or self.account_type,
self.doc.master_name): 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.doc.parent_account: if self.parent_account:
par = frappe.db.sql("""select name, group_or_ledger, report_type par = frappe.db.sql("""select name, group_or_ledger, report_type
from tabAccount where name =%s""", self.doc.parent_account, as_dict=1) from tabAccount where name =%s""", self.parent_account, as_dict=1)
if not par: if not par:
throw(_("Parent account does not exists")) throw(_("Parent account does not exists"))
elif par[0]["name"] == self.doc.name: elif par[0]["name"] == self.name:
throw(_("You can not assign itself as parent account")) throw(_("You can not assign itself as parent account"))
elif par[0]["group_or_ledger"] != 'Group': elif par[0]["group_or_ledger"] != 'Group':
throw(_("Parent account can not be a ledger")) throw(_("Parent account can not be a ledger"))
if par[0]["report_type"]: if par[0]["report_type"]:
self.doc.report_type = par[0]["report_type"] self.report_type = par[0]["report_type"]
def validate_duplicate_account(self): def validate_duplicate_account(self):
if self.doc.fields.get('__islocal') or not self.doc.name: if self.get('__islocal') or not self.name:
company_abbr = frappe.db.get_value("Company", self.doc.company, "abbr") company_abbr = frappe.db.get_value("Company", self.company, "abbr")
if frappe.db.sql("""select name from tabAccount where name=%s""", if frappe.db.sql("""select name from tabAccount where name=%s""",
(self.doc.account_name + " - " + company_abbr)): (self.account_name + " - " + company_abbr)):
throw("{name}: {acc_name} {exist}, {rename}".format(**{ throw("{name}: {acc_name} {exist}, {rename}".format(**{
"name": _("Account Name"), "name": _("Account Name"),
"acc_name": self.doc.account_name, "acc_name": self.account_name,
"exist": _("already exists"), "exist": _("already exists"),
"rename": _("please rename") "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.doc.name): if frappe.db.exists("Account", self.name):
if not frappe.db.get_value("Account", self.doc.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.doc.name, "freeze_account") old_value = frappe.db.get_value("Account", self.name, "freeze_account")
if old_value and old_value != self.doc.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 \
@ -91,50 +91,50 @@ class Account(Document):
if self.check_if_child_exists(): if self.check_if_child_exists():
throw("{acc}: {account_name} {child}. {msg}".format(**{ throw("{acc}: {account_name} {child}. {msg}".format(**{
"acc": _("Account"), "acc": _("Account"),
"account_name": self.doc.name, "account_name": self.name,
"child": _("has existing child"), "child": _("has existing child"),
"msg": _("You can not convert this account to ledger") "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 can not be converted to ledger."))
else: else:
self.doc.group_or_ledger = 'Ledger' self.group_or_ledger = 'Ledger'
self.doc.save() self.save()
return 1 return 1
def convert_ledger_to_group(self): def convert_ledger_to_group(self):
if self.check_gle_exists(): if self.check_gle_exists():
throw(_("Account with existing transaction can not be converted to group.")) throw(_("Account with existing transaction can not be converted to group."))
elif self.doc.master_type or self.doc.account_type: elif self.master_type or self.account_type:
throw(_("Cannot covert to Group because Master Type or Account Type is selected.")) throw(_("Cannot covert to Group because Master Type or Account Type is selected."))
else: else:
self.doc.group_or_ledger = 'Group' self.group_or_ledger = 'Group'
self.doc.save() self.save()
return 1 return 1
# Check if any previous balance exists # Check if any previous balance exists
def check_gle_exists(self): def check_gle_exists(self):
return frappe.db.get_value("GL Entry", {"account": self.doc.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.doc.name) and docstatus != 2""", self.name)
def validate_mandatory(self): def validate_mandatory(self):
if not self.doc.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.doc.account_type == "Warehouse": if self.account_type == "Warehouse":
old_warehouse = cstr(frappe.db.get_value("Account", self.doc.name, "master_name")) old_warehouse = cstr(frappe.db.get_value("Account", self.name, "master_name"))
if old_warehouse != cstr(self.doc.master_name): if old_warehouse != cstr(self.master_name):
if old_warehouse: if old_warehouse:
self.validate_warehouse(old_warehouse) self.validate_warehouse(old_warehouse)
if self.doc.master_name: if self.master_name:
self.validate_warehouse(self.doc.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"))
@ -163,10 +163,10 @@ class Account(Document):
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.doc.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.doc.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
@ -175,11 +175,11 @@ class Account(Document):
throw("""Total Outstanding amount (%s) for <b>%s</b> can not be \ throw("""Total Outstanding amount (%s) for <b>%s</b> can not be \
greater than credit limit (%s). To change your credit limit settings, \ greater than credit limit (%s). To change your credit limit settings, \
please update in the <b>%s</b> master""" % (fmt_money(total_outstanding), please update in the <b>%s</b> master""" % (fmt_money(total_outstanding),
self.doc.name, fmt_money(credit_limit), credit_limit_from)) 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.doc.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():
@ -195,7 +195,7 @@ class Account(Document):
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.doc.company) new_account = get_name_with_abbr(new, self.company)
# Validate properties before merging # Validate properties before merging
if merge: if merge:
@ -205,7 +205,7 @@ class Account(Document):
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.doc.group_or_ledger, self.doc.report_type, self.doc.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. properties are same in both records.
Group or Ledger, Report Type, Company""")) Group or Ledger, Report Type, Company"""))

View File

@ -13,9 +13,9 @@ from frappe.model.document import Document
class AccountsSettings(Document): class AccountsSettings(Document):
def on_update(self): def on_update(self):
frappe.db.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock) frappe.db.set_default("auto_accounting_for_stock", self.auto_accounting_for_stock)
if cint(self.doc.auto_accounting_for_stock): if cint(self.auto_accounting_for_stock):
# set default perpetual account in company # set default perpetual account in company
for company in frappe.db.sql("select name from tabCompany"): for company in frappe.db.sql("select name from tabCompany"):
frappe.bean("Company", company[0]).save() frappe.bean("Company", company[0]).save()

View File

@ -12,17 +12,17 @@ from frappe.model.document import Document
class BankReconciliation(Document): class BankReconciliation(Document):
def get_details(self): def get_details(self):
if not (self.doc.bank_account and self.doc.from_date and self.doc.to_date): if not (self.bank_account and self.from_date and self.to_date):
msgprint("Bank Account, From Date and To Date are Mandatory") msgprint("Bank Account, From Date and To Date are Mandatory")
return return
dl = frappe.db.sql("select t1.name, t1.cheque_no, t1.cheque_date, t2.debit, t2.credit, t1.posting_date, t2.against_account from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2 where t2.parent = t1.name and t2.account = %s and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '') and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1", (self.doc.bank_account, self.doc.from_date, self.doc.to_date)) dl = frappe.db.sql("select t1.name, t1.cheque_no, t1.cheque_date, t2.debit, t2.credit, t1.posting_date, t2.against_account from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2 where t2.parent = t1.name and t2.account = %s and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '') and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1", (self.bank_account, self.from_date, self.to_date))
self.set('entries', []) self.set('entries', [])
self.doc.total_amount = 0.0 self.total_amount = 0.0
for d in dl: for d in dl:
nl = self.doc.append('entries', {}) nl = self.append('entries', {})
nl.posting_date = cstr(d[5]) nl.posting_date = cstr(d[5])
nl.voucher_id = cstr(d[0]) nl.voucher_id = cstr(d[0])
nl.cheque_number = cstr(d[1]) nl.cheque_number = cstr(d[1])
@ -30,7 +30,7 @@ class BankReconciliation(Document):
nl.debit = flt(d[3]) nl.debit = flt(d[3])
nl.credit = flt(d[4]) nl.credit = flt(d[4])
nl.against_account = cstr(d[6]) nl.against_account = cstr(d[6])
self.doc.total_amount += flt(flt(d[4]) - flt(d[3])) self.total_amount += flt(flt(d[4]) - flt(d[3]))
def update_details(self): def update_details(self):
vouchers = [] vouchers = []

View File

@ -28,7 +28,7 @@ class CForm(Document):
frappe.msgprint("C-form is not applicable for Invoice: %s" % frappe.msgprint("C-form is not applicable for Invoice: %s" %
d.invoice_no, raise_exception=1) d.invoice_no, raise_exception=1)
elif inv[0][1] and inv[0][1] != self.doc.name: elif inv[0][1] and inv[0][1] != self.name:
frappe.msgprint("""Invoice %s is tagged in another C-form: %s. frappe.msgprint("""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""" %
@ -44,19 +44,19 @@ class CForm(Document):
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 frappe.db.sql("""update `tabSales Invoice` set c_form_no=null
where c_form_no=%s""", self.doc.name) 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 frappe.db.sql("""update `tabSales Invoice` set c_form_no=%s, modified=%s
where name in (%s)""" % ('%s', '%s', ', '.join(['%s'] * len(inv))), where name in (%s)""" % ('%s', '%s', ', '.join(['%s'] * len(inv))),
tuple([self.doc.name, self.doc.modified] + 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'), ('%s', ', '.join(['%s']*len(inv)), '%s'),
tuple([self.doc.modified] + inv + [self.doc.name])) tuple([self.modified] + inv + [self.name]))
else: else:
frappe.msgprint("Please enter atleast 1 invoice in the table", raise_exception=1) frappe.msgprint("Please enter atleast 1 invoice in the table", raise_exception=1)

View File

@ -15,7 +15,7 @@ class ChartOfAccounts(Document):
def create_accounts(self, company): def create_accounts(self, company):
chart = {} chart = {}
with open(os.path.join(os.path.dirname(__file__), "charts", with open(os.path.join(os.path.dirname(__file__), "charts",
self.doc.source_file), "r") as f: self.source_file), "r") as f:
chart = json.loads(f.read()) chart = json.loads(f.read())
from erpnext.accounts.doctype.chart_of_accounts.charts.account_properties \ from erpnext.accounts.doctype.chart_of_accounts.charts.account_properties \
@ -49,15 +49,15 @@ class ChartOfAccounts(Document):
accounts.append(account_name_in_db) accounts.append(account_name_in_db)
# set report_type for all parents where blank # set report_type for all parents where blank
if not account.doc.report_type or account.doc.report_type == 'None': if not account.report_type or account.report_type == 'None':
self.no_report_type = True self.no_report_type = True
elif self.no_report_type: elif self.no_report_type:
frappe.db.sql("""update tabAccount set report_type=%s frappe.db.sql("""update tabAccount set report_type=%s
where lft<=%s and rgt>=%s and ifnull(report_type, '')=''""", where lft<=%s and rgt>=%s and ifnull(report_type, '')=''""",
(account.doc.report_type, account.doc.lft, account.doc.rgt)) (account.report_type, account.lft, account.rgt))
if child.get("children"): if child.get("children"):
_import_accounts(child.get("children"), account.doc.name) _import_accounts(child.get("children"), account.name)
_import_accounts(chart.get("root").get("children"), None) _import_accounts(chart.get("root").get("children"), None)

View File

@ -19,7 +19,7 @@ def import_charts():
"source_file": fname, "source_file": fname,
"country": country "country": country
}).insert() }).insert()
print bean.doc.name.encode("utf-8") print bean.name.encode("utf-8")
else: else:
print "No chart for: " + chart.get("name").encode("utf-8") print "No chart for: " + chart.get("name").encode("utf-8")

View File

@ -14,47 +14,47 @@ class CostCenter(DocTypeNestedSet):
def autoname(self): def autoname(self):
company_abbr = frappe.db.sql("select abbr from tabCompany where name=%s", company_abbr = frappe.db.sql("select abbr from tabCompany where name=%s",
self.doc.company)[0][0] self.company)[0][0]
self.doc.name = self.doc.cost_center_name.strip() + ' - ' + company_abbr self.name = self.cost_center_name.strip() + ' - ' + company_abbr
def validate_mandatory(self): def validate_mandatory(self):
if not self.doc.group_or_ledger: if not self.group_or_ledger:
msgprint("Please select Group or Ledger value", raise_exception=1) msgprint("Please select Group or Ledger value", raise_exception=1)
if self.doc.cost_center_name != self.doc.company and not self.doc.parent_cost_center: if self.cost_center_name != self.company and not self.parent_cost_center:
msgprint("Please enter parent cost center", raise_exception=1) msgprint("Please enter parent cost center", raise_exception=1)
elif self.doc.cost_center_name == self.doc.company and self.doc.parent_cost_center: elif self.cost_center_name == self.company and self.parent_cost_center:
msgprint(_("Root cannot have a parent cost center"), raise_exception=1) msgprint(_("Root cannot have a parent cost center"), raise_exception=1)
def convert_group_to_ledger(self): def convert_group_to_ledger(self):
if self.check_if_child_exists(): if self.check_if_child_exists():
msgprint("Cost Center: %s has existing child. You can not convert this cost center to ledger" % (self.doc.name), raise_exception=1) msgprint("Cost Center: %s has existing child. You can not convert this cost center to ledger" % (self.name), raise_exception=1)
elif self.check_gle_exists(): elif self.check_gle_exists():
msgprint("Cost Center with existing transaction can not be converted to ledger.", raise_exception=1) msgprint("Cost Center with existing transaction can not be converted to ledger.", raise_exception=1)
else: else:
self.doc.group_or_ledger = 'Ledger' self.group_or_ledger = 'Ledger'
self.doc.save() self.save()
return 1 return 1
def convert_ledger_to_group(self): def convert_ledger_to_group(self):
if self.check_gle_exists(): if self.check_gle_exists():
msgprint("Cost Center with existing transaction can not be converted to group.", raise_exception=1) msgprint("Cost Center with existing transaction can not be converted to group.", raise_exception=1)
else: else:
self.doc.group_or_ledger = 'Group' self.group_or_ledger = 'Group'
self.doc.save() self.save()
return 1 return 1
def check_gle_exists(self): def check_gle_exists(self):
return frappe.db.get_value("GL Entry", {"cost_center": self.doc.name}) return frappe.db.get_value("GL Entry", {"cost_center": self.name})
def check_if_child_exists(self): def check_if_child_exists(self):
return frappe.db.sql("select name from `tabCost Center` where \ return frappe.db.sql("select name from `tabCost Center` where \
parent_cost_center = %s and docstatus != 2", self.doc.name) parent_cost_center = %s and docstatus != 2", self.name)
def validate_budget_details(self): def validate_budget_details(self):
check_acc_list = [] check_acc_list = []
for d in self.get('budget_details'): for d in self.get('budget_details'):
if self.doc.group_or_ledger=="Group": if self.group_or_ledger=="Group":
msgprint("Budget cannot be set for Group Cost Centers", raise_exception=1) msgprint("Budget cannot be set for Group Cost Centers", raise_exception=1)
if [d.account, d.fiscal_year] in check_acc_list: if [d.account, d.fiscal_year] in check_acc_list:
@ -66,7 +66,7 @@ class CostCenter(DocTypeNestedSet):
""" """
Cost Center name must be unique Cost Center name must be unique
""" """
if (self.doc.fields.get("__islocal") or not self.doc.name) and frappe.db.sql("select name from `tabCost Center` where cost_center_name = %s and company=%s", (self.doc.cost_center_name, self.doc.company)): if (self.get("__islocal") or not self.name) and frappe.db.sql("select name from `tabCost Center` where cost_center_name = %s and company=%s", (self.cost_center_name, self.company)):
msgprint("Cost Center Name already exists, please rename", raise_exception=1) msgprint("Cost Center Name already exists, please rename", raise_exception=1)
self.validate_mandatory() self.validate_mandatory()
@ -75,7 +75,7 @@ class CostCenter(DocTypeNestedSet):
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
from erpnext.setup.doctype.company.company import get_name_with_abbr from erpnext.setup.doctype.company.company import get_name_with_abbr
new_cost_center = get_name_with_abbr(newdn, self.doc.company) new_cost_center = get_name_with_abbr(newdn, self.company)
# Validate properties before merging # Validate properties before merging
super(DocType, self).before_rename(olddn, new_cost_center, merge, "group_or_ledger") super(DocType, self).before_rename(olddn, new_cost_center, merge, "group_or_ledger")

View File

@ -11,35 +11,35 @@ from frappe.model.document import Document
class FiscalYear(Document): class FiscalYear(Document):
def set_as_default(self): def set_as_default(self):
frappe.db.set_value("Global Defaults", None, "current_fiscal_year", self.doc.name) frappe.db.set_value("Global Defaults", None, "current_fiscal_year", self.name)
frappe.get_obj("Global Defaults").on_update() frappe.get_obj("Global Defaults").on_update()
# clear cache # clear cache
frappe.clear_cache() frappe.clear_cache()
msgprint(self.doc.name + _(""" is now the default Fiscal Year. \ msgprint(self.name + _(""" is now the default Fiscal Year. \
Please refresh your browser for the change to take effect.""")) Please refresh your browser for the change to take effect."""))
def validate(self): def validate(self):
year_start_end_dates = frappe.db.sql("""select year_start_date, year_end_date year_start_end_dates = frappe.db.sql("""select year_start_date, year_end_date
from `tabFiscal Year` where name=%s""", (self.doc.name)) from `tabFiscal Year` where name=%s""", (self.name))
if year_start_end_dates: if year_start_end_dates:
if getdate(self.doc.year_start_date) != year_start_end_dates[0][0] or getdate(self.doc.year_end_date) != year_start_end_dates[0][1]: if getdate(self.year_start_date) != year_start_end_dates[0][0] or getdate(self.year_end_date) != year_start_end_dates[0][1]:
frappe.throw(_("Cannot change Year Start Date and Year End Date once the Fiscal Year is saved.")) frappe.throw(_("Cannot change Year Start Date and Year End Date once the Fiscal Year is saved."))
def on_update(self): def on_update(self):
# validate year start date and year end date # validate year start date and year end date
if getdate(self.doc.year_start_date) > getdate(self.doc.year_end_date): if getdate(self.year_start_date) > getdate(self.year_end_date):
frappe.throw(_("Year Start Date should not be greater than Year End Date")) frappe.throw(_("Year Start Date should not be greater than Year End Date"))
if (getdate(self.doc.year_end_date) - getdate(self.doc.year_start_date)).days > 366: if (getdate(self.year_end_date) - getdate(self.year_start_date)).days > 366:
frappe.throw(_("Year Start Date and Year End Date are not within Fiscal Year.")) frappe.throw(_("Year Start Date and Year End Date are not within Fiscal Year."))
year_start_end_dates = frappe.db.sql("""select name, year_start_date, year_end_date year_start_end_dates = frappe.db.sql("""select name, year_start_date, year_end_date
from `tabFiscal Year` where name!=%s""", (self.doc.name)) from `tabFiscal Year` where name!=%s""", (self.name))
for fiscal_year, ysd, yed in year_start_end_dates: for fiscal_year, ysd, yed in year_start_end_dates:
if (getdate(self.doc.year_start_date) == ysd and getdate(self.doc.year_end_date) == yed) \ if (getdate(self.year_start_date) == ysd and getdate(self.year_end_date) == yed) \
and (not frappe.flags.in_test): and (not frappe.flags.in_test):
frappe.throw(_("Year Start Date and Year End Date are already set in Fiscal Year: ") + fiscal_year) frappe.throw(_("Year Start Date and Year End Date are already set in Fiscal Year: ") + fiscal_year)

View File

@ -20,42 +20,42 @@ class GlEntry(Document):
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'): def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj) self.validate_account_details(adv_adj)
validate_frozen_account(self.doc.account, adv_adj) validate_frozen_account(self.account, adv_adj)
check_freezing_date(self.doc.posting_date, adv_adj) check_freezing_date(self.posting_date, adv_adj)
validate_balance_type(self.doc.account, adv_adj) validate_balance_type(self.account, adv_adj)
# Update outstanding amt on against voucher # Update outstanding amt on against voucher
if self.doc.against_voucher and self.doc.against_voucher_type != "POS" \ if self.against_voucher and self.against_voucher_type != "POS" \
and update_outstanding == 'Yes': and update_outstanding == 'Yes':
update_outstanding_amt(self.doc.account, self.doc.against_voucher_type, update_outstanding_amt(self.account, self.against_voucher_type,
self.doc.against_voucher) self.against_voucher)
def check_mandatory(self): def check_mandatory(self):
mandatory = ['account','remarks','voucher_type','voucher_no','fiscal_year','company'] mandatory = ['account','remarks','voucher_type','voucher_no','fiscal_year','company']
for k in mandatory: for k in mandatory:
if not self.doc.fields.get(k): if not self.get(k):
frappe.throw(k + _(" is mandatory for GL Entry")) frappe.throw(k + _(" is mandatory for GL Entry"))
# Zero value transaction is not allowed # Zero value transaction is not allowed
if not (flt(self.doc.debit) or flt(self.doc.credit)): if not (flt(self.debit) or flt(self.credit)):
frappe.throw(_("GL Entry: Debit or Credit amount is mandatory for ") + frappe.throw(_("GL Entry: Debit or Credit amount is mandatory for ") +
self.doc.account) self.account)
def pl_must_have_cost_center(self): def pl_must_have_cost_center(self):
if frappe.db.get_value("Account", self.doc.account, "report_type") == "Profit and Loss": if frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss":
if not self.doc.cost_center and self.doc.voucher_type != 'Period Closing Voucher': if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
frappe.throw(_("Cost Center must be specified for Profit and Loss type account: ") frappe.throw(_("Cost Center must be specified for Profit and Loss type account: ")
+ self.doc.account) + self.account)
elif self.doc.cost_center: elif self.cost_center:
self.doc.cost_center = None self.cost_center = None
def validate_posting_date(self): def validate_posting_date(self):
from erpnext.accounts.utils import validate_fiscal_year from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.posting_date, self.doc.fiscal_year, "Posting Date") validate_fiscal_year(self.posting_date, self.fiscal_year, "Posting Date")
def check_pl_account(self): def check_pl_account(self):
if self.doc.is_opening=='Yes' and \ if self.is_opening=='Yes' and \
frappe.db.get_value("Account", self.doc.account, "report_type")=="Profit and Loss": frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss":
frappe.throw(_("For opening balance entry, account can not be \ frappe.throw(_("For opening balance entry, account can not be \
a Profit and Loss type account")) a Profit and Loss type account"))
@ -63,32 +63,32 @@ class GlEntry(Document):
"""Account must be ledger, active and not freezed""" """Account must be ledger, active and not freezed"""
ret = frappe.db.sql("""select group_or_ledger, docstatus, company ret = frappe.db.sql("""select group_or_ledger, docstatus, company
from tabAccount where name=%s""", self.doc.account, as_dict=1)[0] from tabAccount where name=%s""", self.account, as_dict=1)[0]
if ret.group_or_ledger=='Group': if ret.group_or_ledger=='Group':
frappe.throw(_("Account") + ": " + self.doc.account + _(" is not a ledger")) frappe.throw(_("Account") + ": " + self.account + _(" is not a ledger"))
if ret.docstatus==2: if ret.docstatus==2:
frappe.throw(_("Account") + ": " + self.doc.account + _(" is not active")) frappe.throw(_("Account") + ": " + self.account + _(" is not active"))
if ret.company != self.doc.company: if ret.company != self.company:
frappe.throw(_("Account") + ": " + self.doc.account + frappe.throw(_("Account") + ": " + self.account +
_(" does not belong to the company") + ": " + self.doc.company) _(" does not belong to the company") + ": " + self.company)
def validate_cost_center(self): def validate_cost_center(self):
if not hasattr(self, "cost_center_company"): if not hasattr(self, "cost_center_company"):
self.cost_center_company = {} self.cost_center_company = {}
def _get_cost_center_company(): def _get_cost_center_company():
if not self.cost_center_company.get(self.doc.cost_center): if not self.cost_center_company.get(self.cost_center):
self.cost_center_company[self.doc.cost_center] = frappe.db.get_value( self.cost_center_company[self.cost_center] = frappe.db.get_value(
"Cost Center", self.doc.cost_center, "company") "Cost Center", self.cost_center, "company")
return self.cost_center_company[self.doc.cost_center] return self.cost_center_company[self.cost_center]
if self.doc.cost_center and _get_cost_center_company() != self.doc.company: if self.cost_center and _get_cost_center_company() != self.company:
frappe.throw(_("Cost Center") + ": " + self.doc.cost_center + frappe.throw(_("Cost Center") + ": " + self.cost_center +
_(" does not belong to the company") + ": " + self.doc.company) _(" does not belong to the company") + ": " + self.company)
def validate_balance_type(account, adv_adj=False): def validate_balance_type(account, adv_adj=False):
if not adv_adj and account: if not adv_adj and account:

View File

@ -18,10 +18,10 @@ class JournalVoucher(AccountsController):
self.is_approving_authority = -1 self.is_approving_authority = -1
def validate(self): def validate(self):
if not self.doc.is_opening: if not self.is_opening:
self.doc.is_opening='No' self.is_opening='No'
self.doc.clearance_date = None self.clearance_date = None
super(DocType, self).validate_date_with_fiscal_year() super(DocType, self).validate_date_with_fiscal_year()
@ -37,21 +37,21 @@ class JournalVoucher(AccountsController):
def on_submit(self): def on_submit(self):
if self.doc.voucher_type in ['Bank Voucher', 'Contra Voucher', 'Journal Entry']: if self.voucher_type in ['Bank Voucher', 'Contra Voucher', 'Journal Entry']:
self.check_credit_days() self.check_credit_days()
self.make_gl_entries() self.make_gl_entries()
self.check_credit_limit() self.check_credit_limit()
def on_cancel(self): def on_cancel(self):
from erpnext.accounts.utils import remove_against_link_from_jv from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_jv") remove_against_link_from_jv(self.doctype, self.name, "against_jv")
self.make_gl_entries(1) self.make_gl_entries(1)
def on_trash(self): def on_trash(self):
pass pass
#if self.doc.amended_from: #if self.amended_from:
# frappe.delete_doc("Journal Voucher", self.doc.amended_from) # frappe.delete_doc("Journal Voucher", self.amended_from)
def validate_debit_credit(self): def validate_debit_credit(self):
for d in self.get('entries'): for d in self.get('entries'):
@ -60,12 +60,12 @@ class JournalVoucher(AccountsController):
raise_exception=1) raise_exception=1)
def validate_cheque_info(self): def validate_cheque_info(self):
if self.doc.voucher_type in ['Bank Voucher']: if self.voucher_type in ['Bank Voucher']:
if not self.doc.cheque_no or not self.doc.cheque_date: if not self.cheque_no or not self.cheque_date:
msgprint("Reference No & Reference Date is required for %s" % msgprint("Reference No & Reference Date is required for %s" %
self.doc.voucher_type, raise_exception=1) self.voucher_type, raise_exception=1)
if self.doc.cheque_date and not self.doc.cheque_no: if self.cheque_date and not self.cheque_no:
msgprint("Reference No is mandatory if you entered Reference Date", raise_exception=1) msgprint("Reference No is mandatory if you entered Reference Date", raise_exception=1)
def validate_entries_for_advance(self): def validate_entries_for_advance(self):
@ -81,7 +81,7 @@ class JournalVoucher(AccountsController):
def validate_against_jv(self): def validate_against_jv(self):
for d in self.get('entries'): for d in self.get('entries'):
if d.against_jv: if d.against_jv:
if d.against_jv == self.doc.name: if d.against_jv == self.name:
msgprint("You can not enter current voucher in 'Against JV' column", msgprint("You can not enter current voucher in 'Against JV' column",
raise_exception=1) raise_exception=1)
elif not frappe.db.sql("""select name from `tabJournal Voucher Detail` elif not frappe.db.sql("""select name from `tabJournal Voucher Detail`
@ -99,12 +99,12 @@ class JournalVoucher(AccountsController):
if flt(d.debit)>0 and (d.account not in debit_list): debit_list.append(d.account) if flt(d.debit)>0 and (d.account not in debit_list): debit_list.append(d.account)
if flt(d.credit)>0 and (d.account not in credit_list): credit_list.append(d.account) if flt(d.credit)>0 and (d.account not in credit_list): credit_list.append(d.account)
self.doc.total_debit = debit self.total_debit = debit
self.doc.total_credit = credit self.total_credit = credit
if abs(self.doc.total_debit-self.doc.total_credit) > 0.001: if abs(self.total_debit-self.total_credit) > 0.001:
msgprint("Debit must be equal to Credit. The difference is %s" % msgprint("Debit must be equal to Credit. The difference is %s" %
(self.doc.total_debit-self.doc.total_credit), raise_exception=1) (self.total_debit-self.total_credit), raise_exception=1)
# update against account # update against account
for d in self.get('entries'): for d in self.get('entries'):
@ -113,10 +113,10 @@ class JournalVoucher(AccountsController):
def create_remarks(self): def create_remarks(self):
r = [] r = []
if self.doc.cheque_no : if self.cheque_no :
if self.doc.cheque_date: if self.cheque_date:
r.append('Via Reference #%s dated %s' % r.append('Via Reference #%s dated %s' %
(self.doc.cheque_no, formatdate(self.doc.cheque_date))) (self.cheque_no, formatdate(self.cheque_date)))
else : else :
msgprint("Please enter Reference date", raise_exception=1) msgprint("Please enter Reference date", raise_exception=1)
@ -135,17 +135,17 @@ class JournalVoucher(AccountsController):
(cstr(bill_no[0][2]), fmt_money(flt(d.debit)), bill_no[0][0], (cstr(bill_no[0][2]), fmt_money(flt(d.debit)), bill_no[0][0],
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d')) or '')) bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d')) or ''))
if self.doc.user_remark: if self.user_remark:
r.append("User Remark : %s"%self.doc.user_remark) r.append("User Remark : %s"%self.user_remark)
if r: if r:
self.doc.remark = ("\n").join(r) self.remark = ("\n").join(r)
else: else:
frappe.msgprint("User Remarks is mandatory", raise_exception=1) frappe.msgprint("User Remarks is mandatory", raise_exception=1)
def set_aging_date(self): def set_aging_date(self):
if self.doc.is_opening != 'Yes': if self.is_opening != 'Yes':
self.doc.aging_date = self.doc.posting_date self.aging_date = self.posting_date
else: else:
# check account type whether supplier or customer # check account type whether supplier or customer
exists = False exists = False
@ -156,10 +156,10 @@ class JournalVoucher(AccountsController):
break break
# If customer/supplier account, aging date is mandatory # If customer/supplier account, aging date is mandatory
if exists and not self.doc.aging_date: if exists and not self.aging_date:
msgprint("Aging Date is mandatory for opening entry", raise_exception=1) msgprint("Aging Date is mandatory for opening entry", raise_exception=1)
else: else:
self.doc.aging_date = self.doc.posting_date self.aging_date = self.posting_date
def set_print_format_fields(self): def set_print_format_fields(self):
for d in self.get('entries'): for d in self.get('entries'):
@ -167,22 +167,22 @@ class JournalVoucher(AccountsController):
["account_type", "master_type"]) ["account_type", "master_type"])
if master_type in ['Supplier', 'Customer']: if master_type in ['Supplier', 'Customer']:
if not self.doc.pay_to_recd_from: if not self.pay_to_recd_from:
self.doc.pay_to_recd_from = frappe.db.get_value(master_type, self.pay_to_recd_from = frappe.db.get_value(master_type,
' - '.join(d.account.split(' - ')[:-1]), ' - '.join(d.account.split(' - ')[:-1]),
master_type == 'Customer' and 'customer_name' or 'supplier_name') master_type == 'Customer' and 'customer_name' or 'supplier_name')
if account_type in ['Bank', 'Cash']: if account_type in ['Bank', 'Cash']:
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
amt = flt(d.debit) and d.debit or d.credit amt = flt(d.debit) and d.debit or d.credit
self.doc.total_amount = company_currency + ' ' + cstr(amt) self.total_amount = company_currency + ' ' + cstr(amt)
from frappe.utils import money_in_words from frappe.utils import money_in_words
self.doc.total_amount_in_words = money_in_words(amt, company_currency) self.total_amount_in_words = money_in_words(amt, company_currency)
def check_credit_days(self): def check_credit_days(self):
date_diff = 0 date_diff = 0
if self.doc.cheque_date: if self.cheque_date:
date_diff = (getdate(self.doc.cheque_date)-getdate(self.doc.posting_date)).days date_diff = (getdate(self.cheque_date)-getdate(self.posting_date)).days
if date_diff <= 0: return if date_diff <= 0: return
@ -204,7 +204,7 @@ class JournalVoucher(AccountsController):
if not self.credit_days_for[ac]: if not self.credit_days_for[ac]:
if self.credit_days_global==-1: if self.credit_days_global==-1:
self.credit_days_global = cint(frappe.db.get_value("Company", self.credit_days_global = cint(frappe.db.get_value("Company",
self.doc.company, "credit_days")) self.company, "credit_days"))
return self.credit_days_global return self.credit_days_global
else: else:
@ -255,7 +255,7 @@ class JournalVoucher(AccountsController):
or (d.against_invoice and "Sales Invoice") or (d.against_invoice and "Sales Invoice")
or (d.against_jv and "Journal Voucher")), or (d.against_jv and "Journal Voucher")),
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv, "against_voucher": d.against_voucher or d.against_invoice or d.against_jv,
"remarks": self.doc.remark, "remarks": self.remark,
"cost_center": d.cost_center "cost_center": d.cost_center
}) })
) )
@ -273,8 +273,8 @@ class JournalVoucher(AccountsController):
if not self.get('entries'): if not self.get('entries'):
msgprint("Please enter atleast 1 entry in 'GL Entries' table") msgprint("Please enter atleast 1 entry in 'GL Entries' table")
else: else:
flag, self.doc.total_debit, self.doc.total_credit = 0, 0, 0 flag, self.total_debit, self.total_credit = 0, 0, 0
diff = flt(self.doc.difference, 2) diff = flt(self.difference, 2)
# If any row without amount, set the diff on that row # If any row without amount, set the diff on that row
for d in self.get('entries'): for d in self.get('entries'):
@ -287,7 +287,7 @@ class JournalVoucher(AccountsController):
# Set the diff in a new row # Set the diff in a new row
if flag == 0 and diff != 0: if flag == 0 and diff != 0:
jd = self.doc.append('entries', {}) jd = self.append('entries', {})
if diff>0: if diff>0:
jd.credit = abs(diff) jd.credit = abs(diff)
elif diff<0: elif diff<0:
@ -295,43 +295,43 @@ class JournalVoucher(AccountsController):
# Set the total debit, total credit and difference # Set the total debit, total credit and difference
for d in self.get('entries'): for d in self.get('entries'):
self.doc.total_debit += flt(d.debit, 2) self.total_debit += flt(d.debit, 2)
self.doc.total_credit += flt(d.credit, 2) self.total_credit += flt(d.credit, 2)
self.doc.difference = flt(self.doc.total_debit, 2) - flt(self.doc.total_credit, 2) self.difference = flt(self.total_debit, 2) - flt(self.total_credit, 2)
def get_outstanding_invoices(self): def get_outstanding_invoices(self):
self.set('entries', []) self.set('entries', [])
total = 0 total = 0
for d in self.get_values(): for d in self.get_values():
total += flt(d[2]) total += flt(d[2])
jd = self.doc.append('entries', {}) jd = self.append('entries', {})
jd.account = cstr(d[1]) jd.account = cstr(d[1])
if self.doc.write_off_based_on == 'Accounts Receivable': if self.write_off_based_on == 'Accounts Receivable':
jd.credit = flt(d[2]) jd.credit = flt(d[2])
jd.against_invoice = cstr(d[0]) jd.against_invoice = cstr(d[0])
elif self.doc.write_off_based_on == 'Accounts Payable': elif self.write_off_based_on == 'Accounts Payable':
jd.debit = flt(d[2]) jd.debit = flt(d[2])
jd.against_voucher = cstr(d[0]) jd.against_voucher = cstr(d[0])
jd.save(1) jd.save(1)
jd = self.doc.append('entries', {}) jd = self.append('entries', {})
if self.doc.write_off_based_on == 'Accounts Receivable': if self.write_off_based_on == 'Accounts Receivable':
jd.debit = total jd.debit = total
elif self.doc.write_off_based_on == 'Accounts Payable': elif self.write_off_based_on == 'Accounts Payable':
jd.credit = total jd.credit = total
jd.save(1) jd.save(1)
def get_values(self): def get_values(self):
cond = (flt(self.doc.write_off_amount) > 0) and \ cond = (flt(self.write_off_amount) > 0) and \
' and outstanding_amount <= '+ self.doc.write_off_amount or '' ' and outstanding_amount <= '+ self.write_off_amount or ''
if self.doc.write_off_based_on == 'Accounts Receivable': if self.write_off_based_on == 'Accounts Receivable':
return frappe.db.sql("""select name, debit_to, outstanding_amount return frappe.db.sql("""select name, debit_to, outstanding_amount
from `tabSales Invoice` where docstatus = 1 and company = %s from `tabSales Invoice` where docstatus = 1 and company = %s
and outstanding_amount > 0 %s""" % ('%s', cond), self.doc.company) and outstanding_amount > 0 %s""" % ('%s', cond), self.company)
elif self.doc.write_off_based_on == 'Accounts Payable': elif self.write_off_based_on == 'Accounts Payable':
return frappe.db.sql("""select name, credit_to, outstanding_amount return frappe.db.sql("""select name, credit_to, outstanding_amount
from `tabPurchase Invoice` where docstatus = 1 and company = %s from `tabPurchase Invoice` where docstatus = 1 and company = %s
and outstanding_amount > 0 %s""" % ('%s', cond), self.doc.company) and outstanding_amount > 0 %s""" % ('%s', cond), self.company)
@frappe.whitelist() @frappe.whitelist()
def get_default_bank_cash_account(company, voucher_type): def get_default_bank_cash_account(company, voucher_type):
@ -349,16 +349,16 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
si = frappe.bean("Sales Invoice", sales_invoice) si = frappe.bean("Sales Invoice", sales_invoice)
jv = get_payment_entry(si.doc) jv = get_payment_entry(si.doc)
jv.doc.remark = 'Payment received against Sales Invoice %(name)s. %(remarks)s' % si.doc.fields jv.remark = 'Payment received against Sales Invoice %(name)s. %(remarks)s' % si.fields
# credit customer # credit customer
jv.doclist[1].account = si.doc.debit_to jv.doclist[1].account = si.debit_to
jv.doclist[1].balance = get_balance_on(si.doc.debit_to) jv.doclist[1].balance = get_balance_on(si.debit_to)
jv.doclist[1].credit = si.doc.outstanding_amount jv.doclist[1].credit = si.outstanding_amount
jv.doclist[1].against_invoice = si.doc.name jv.doclist[1].against_invoice = si.name
# debit bank # debit bank
jv.doclist[2].debit = si.doc.outstanding_amount jv.doclist[2].debit = si.outstanding_amount
return [d.fields for d in jv.doclist] return [d.fields for d in jv.doclist]
@ -367,16 +367,16 @@ def get_payment_entry_from_purchase_invoice(purchase_invoice):
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
pi = frappe.bean("Purchase Invoice", purchase_invoice) pi = frappe.bean("Purchase Invoice", purchase_invoice)
jv = get_payment_entry(pi.doc) jv = get_payment_entry(pi.doc)
jv.doc.remark = 'Payment against Purchase Invoice %(name)s. %(remarks)s' % pi.doc.fields jv.remark = 'Payment against Purchase Invoice %(name)s. %(remarks)s' % pi.fields
# credit supplier # credit supplier
jv.doclist[1].account = pi.doc.credit_to jv.doclist[1].account = pi.credit_to
jv.doclist[1].balance = get_balance_on(pi.doc.credit_to) jv.doclist[1].balance = get_balance_on(pi.credit_to)
jv.doclist[1].debit = pi.doc.outstanding_amount jv.doclist[1].debit = pi.outstanding_amount
jv.doclist[1].against_voucher = pi.doc.name jv.doclist[1].against_voucher = pi.name
# credit bank # credit bank
jv.doclist[2].credit = pi.doc.outstanding_amount jv.doclist[2].credit = pi.outstanding_amount
return [d.fields for d in jv.doclist] return [d.fields for d in jv.doclist]
@ -384,10 +384,10 @@ def get_payment_entry(doc):
bank_account = get_default_bank_cash_account(doc.company, "Bank Voucher") bank_account = get_default_bank_cash_account(doc.company, "Bank Voucher")
jv = frappe.new_bean('Journal Voucher') jv = frappe.new_bean('Journal Voucher')
jv.doc.voucher_type = 'Bank Voucher' jv.voucher_type = 'Bank Voucher'
jv.doc.company = doc.company jv.company = doc.company
jv.doc.fiscal_year = doc.fiscal_year jv.fiscal_year = doc.fiscal_year
d1 = jv.append("entries") d1 = jv.append("entries")
d2 = jv.append("entries") d2 = jv.append("entries")

View File

@ -14,24 +14,24 @@ class TestJournalVoucher(unittest.TestCase):
jv_invoice.submit() jv_invoice.submit()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.doc.name)) where against_jv=%s""", jv_invoice.name))
jv_payment = frappe.bean(copy=test_records[0]) jv_payment = frappe.bean(copy=test_records[0])
jv_payment.doclist[1].against_jv = jv_invoice.doc.name jv_payment.doclist[1].against_jv = jv_invoice.name
jv_payment.insert() jv_payment.insert()
jv_payment.submit() jv_payment.submit()
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.doc.name)) where against_jv=%s""", jv_invoice.name))
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s and credit=400""", jv_invoice.doc.name)) where against_jv=%s and credit=400""", jv_invoice.name))
# cancel jv_invoice # cancel jv_invoice
jv_invoice.cancel() jv_invoice.cancel()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.doc.name)) where against_jv=%s""", jv_invoice.name))
def test_jv_against_stock_account(self): def test_jv_against_stock_account(self):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
@ -58,7 +58,7 @@ class TestJournalVoucher(unittest.TestCase):
jv.insert() jv.insert()
jv.submit() jv.submit()
self.assertTrue(frappe.db.get_value("GL Entry", self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv.doc.name})) {"voucher_type": "Journal Voucher", "voucher_no": jv.name}))
def test_monthly_budget_crossed_stop(self): def test_monthly_budget_crossed_stop(self):
from erpnext.accounts.utils import BudgetError from erpnext.accounts.utils import BudgetError
@ -84,7 +84,7 @@ class TestJournalVoucher(unittest.TestCase):
frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop") frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop")
jv = frappe.bean(copy=test_records[0]) jv = frappe.bean(copy=test_records[0])
jv.doc.posting_date = "2013-08-12" jv.posting_date = "2013-08-12"
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC" jv.doclist[2].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 150000.0 jv.doclist[2].debit = 150000.0
@ -108,7 +108,7 @@ class TestJournalVoucher(unittest.TestCase):
jv.submit() jv.submit()
self.assertTrue(frappe.db.get_value("GL Entry", self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv.doc.name})) {"voucher_type": "Journal Voucher", "voucher_no": jv.name}))
jv1 = frappe.bean(copy=test_records[0]) jv1 = frappe.bean(copy=test_records[0])
jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
@ -118,7 +118,7 @@ class TestJournalVoucher(unittest.TestCase):
jv1.submit() jv1.submit()
self.assertTrue(frappe.db.get_value("GL Entry", self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv1.doc.name})) {"voucher_type": "Journal Voucher", "voucher_no": jv1.name}))
self.assertRaises(BudgetError, jv.cancel) self.assertRaises(BudgetError, jv.cancel)

View File

@ -15,13 +15,13 @@ class PaymentToInvoiceMatchingTool(Document):
total_amount = frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) total_amount = frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry` from `tabGL Entry`
where voucher_type = %s and voucher_no = %s where voucher_type = %s and voucher_no = %s
and account = %s""", (self.doc.voucher_type, self.doc.voucher_no, self.doc.account)) and account = %s""", (self.voucher_type, self.voucher_no, self.account))
total_amount = total_amount and flt(total_amount[0][0]) or 0 total_amount = total_amount and flt(total_amount[0][0]) or 0
reconciled_payment = frappe.db.sql(""" reconciled_payment = frappe.db.sql("""
select abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))) from `tabGL Entry` where select abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))) from `tabGL Entry` where
against_voucher = %s and voucher_no != %s against_voucher = %s and voucher_no != %s
and account = %s""", (self.doc.voucher_no, self.doc.voucher_no, self.doc.account)) and account = %s""", (self.voucher_no, self.voucher_no, self.account))
reconciled_payment = reconciled_payment and flt(reconciled_payment[0][0]) or 0 reconciled_payment = reconciled_payment and flt(reconciled_payment[0][0]) or 0
ret = { ret = {
@ -44,15 +44,15 @@ class PaymentToInvoiceMatchingTool(Document):
def get_gl_entries(self): def get_gl_entries(self):
self.validate_mandatory() self.validate_mandatory()
cond = self.doc.from_date and " and t1.posting_date >= '" + self.doc.from_date + "'" or "" cond = self.from_date and " and t1.posting_date >= '" + self.from_date + "'" or ""
cond += self.doc.to_date and " and t1.posting_date <= '" + self.doc.to_date + "'"or "" cond += self.to_date and " and t1.posting_date <= '" + self.to_date + "'"or ""
if self.doc.amt_greater_than: if self.amt_greater_than:
cond += ' and abs(ifnull(t2.debit, 0) - ifnull(t2.credit, 0)) >= ' + \ cond += ' and abs(ifnull(t2.debit, 0) - ifnull(t2.credit, 0)) >= ' + \
self.doc.amt_greater_than self.amt_greater_than
if self.doc.amt_less_than: if self.amt_less_than:
cond += ' and abs(ifnull(t2.debit, 0) - ifnull(t2.credit, 0)) >= ' + \ cond += ' and abs(ifnull(t2.debit, 0) - ifnull(t2.credit, 0)) >= ' + \
self.doc.amt_less_than self.amt_less_than
gle = frappe.db.sql(""" gle = frappe.db.sql("""
select t1.name as voucher_no, t1.posting_date, t1.total_debit as total_amt, select t1.name as voucher_no, t1.posting_date, t1.total_debit as total_amt,
@ -62,13 +62,13 @@ class PaymentToInvoiceMatchingTool(Document):
where t1.name = t2.parent and t1.docstatus = 1 and t2.account = %s where t1.name = t2.parent and t1.docstatus = 1 and t2.account = %s
and ifnull(t2.against_voucher, '')='' and ifnull(t2.against_invoice, '')='' and ifnull(t2.against_voucher, '')='' and ifnull(t2.against_invoice, '')=''
and ifnull(t2.against_jv, '')='' and t1.name != %s %s group by t1.name, t2.name """ % and ifnull(t2.against_jv, '')='' and t1.name != %s %s group by t1.name, t2.name """ %
('%s', '%s', cond), (self.doc.account, self.doc.voucher_no), as_dict=1) ('%s', '%s', cond), (self.account, self.voucher_no), as_dict=1)
return gle return gle
def create_payment_table(self, gle): def create_payment_table(self, gle):
for d in gle: for d in gle:
ch = self.doc.append('ir_payment_details', {}) ch = self.append('ir_payment_details', {})
ch.voucher_no = d.get('voucher_no') ch.voucher_no = d.get('voucher_no')
ch.posting_date = d.get('posting_date') ch.posting_date = d.get('posting_date')
ch.amt_due = flt(d.get('amt_due')) ch.amt_due = flt(d.get('amt_due'))
@ -78,7 +78,7 @@ class PaymentToInvoiceMatchingTool(Document):
ch.voucher_detail_no = d.get('voucher_detail_no') ch.voucher_detail_no = d.get('voucher_detail_no')
def validate_mandatory(self): def validate_mandatory(self):
if not self.doc.account: if not self.account:
msgprint("Please select Account first", raise_exception=1) msgprint("Please select Account first", raise_exception=1)
def reconcile(self): def reconcile(self):
@ -88,8 +88,8 @@ class PaymentToInvoiceMatchingTool(Document):
2. split into multiple rows if partially adjusted, assign against voucher 2. split into multiple rows if partially adjusted, assign against voucher
3. submit payment voucher 3. submit payment voucher
""" """
if not self.doc.voucher_no or not frappe.db.sql("""select name from `tab%s` if not self.voucher_no or not frappe.db.sql("""select name from `tab%s`
where name = %s""" % (self.doc.voucher_type, '%s'), self.doc.voucher_no): where name = %s""" % (self.voucher_type, '%s'), self.voucher_no):
frappe.throw(_("Please select valid Voucher No to proceed")) frappe.throw(_("Please select valid Voucher No to proceed"))
lst = [] lst = []
@ -98,11 +98,11 @@ class PaymentToInvoiceMatchingTool(Document):
args = { args = {
'voucher_no' : d.voucher_no, 'voucher_no' : d.voucher_no,
'voucher_detail_no' : d.voucher_detail_no, 'voucher_detail_no' : d.voucher_detail_no,
'against_voucher_type' : self.doc.voucher_type, 'against_voucher_type' : self.voucher_type,
'against_voucher' : self.doc.voucher_no, 'against_voucher' : self.voucher_no,
'account' : self.doc.account, 'account' : self.account,
'is_advance' : 'No', 'is_advance' : 'No',
# 'dr_or_cr' : self.doc.account_type=='debit' and 'credit' or 'debit', # 'dr_or_cr' : self.account_type=='debit' and 'credit' or 'debit',
'unadjusted_amt' : flt(d.amt_due), 'unadjusted_amt' : flt(d.amt_due),
'allocated_amt' : flt(d.amt_to_be_reconciled) 'allocated_amt' : flt(d.amt_to_be_reconciled)
} }

View File

@ -19,24 +19,24 @@ class PeriodClosingVoucher(AccountsController):
def on_cancel(self): def on_cancel(self):
frappe.db.sql("""delete from `tabGL Entry` frappe.db.sql("""delete from `tabGL Entry`
where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.doc.name) where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.name)
def validate_account_head(self): def validate_account_head(self):
if frappe.db.get_value("Account", self.doc.closing_account_head, "report_type") \ if frappe.db.get_value("Account", self.closing_account_head, "report_type") \
!= "Balance Sheet": != "Balance Sheet":
frappe.throw(_("Account") + ": " + self.doc.closing_account_head + frappe.throw(_("Account") + ": " + self.closing_account_head +
_("must be a Liability account")) _("must be a Liability account"))
def validate_posting_date(self): def validate_posting_date(self):
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year
self.year_start_date = get_fiscal_year(self.doc.posting_date, self.doc.fiscal_year)[1] self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year)[1]
pce = frappe.db.sql("""select name from `tabPeriod Closing Voucher` pce = frappe.db.sql("""select name from `tabPeriod Closing Voucher`
where posting_date > %s and fiscal_year = %s and docstatus = 1""", where posting_date > %s and fiscal_year = %s and docstatus = 1""",
(self.doc.posting_date, self.doc.fiscal_year)) (self.posting_date, self.fiscal_year))
if pce and pce[0][0]: if pce and pce[0][0]:
frappe.throw(_("Another Period Closing Entry") + ": " + cstr(pce[0][0]) + frappe.throw(_("Another Period Closing Entry") + ": " + cstr(pce[0][0]) +
_("has been made after posting date") + ": " + self.doc.posting_date) _("has been made after posting date") + ": " + self.posting_date)
def get_pl_balances(self): def get_pl_balances(self):
"""Get balance for pl accounts""" """Get balance for pl accounts"""
@ -47,7 +47,7 @@ class PeriodClosingVoucher(AccountsController):
and t2.docstatus < 2 and t2.company = %s and t2.docstatus < 2 and t2.company = %s
and t1.posting_date between %s and %s and t1.posting_date between %s and %s
group by t1.account group by t1.account
""", (self.doc.company, self.year_start_date, self.doc.posting_date), as_dict=1) """, (self.company, self.year_start_date, self.posting_date), as_dict=1)
def make_gl_entries(self): def make_gl_entries(self):
gl_entries = [] gl_entries = []
@ -65,7 +65,7 @@ class PeriodClosingVoucher(AccountsController):
if net_pl_balance: if net_pl_balance:
gl_entries.append(self.get_gl_dict({ gl_entries.append(self.get_gl_dict({
"account": self.doc.closing_account_head, "account": self.closing_account_head,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0, "debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0 "credit": abs(net_pl_balance) if net_pl_balance < 0 else 0
})) }))

View File

@ -29,7 +29,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s
order by account asc, debit asc""", pcv.doc.name, as_dict=1) order by account asc, debit asc""", pcv.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)

View File

@ -24,30 +24,30 @@ class PosSetting(Document):
def check_for_duplicate(self): def check_for_duplicate(self):
res = frappe.db.sql("""select name, user from `tabPOS Setting` res = frappe.db.sql("""select name, user from `tabPOS Setting`
where ifnull(user, '') = %s and name != %s and company = %s""", where ifnull(user, '') = %s and name != %s and company = %s""",
(self.doc.user, self.doc.name, self.doc.company)) (self.user, self.name, self.company))
if res: if res:
if res[0][1]: if res[0][1]:
msgprint("POS Setting '%s' already created for user: '%s' and company: '%s'" % msgprint("POS Setting '%s' already created for user: '%s' and company: '%s'" %
(res[0][0], res[0][1], self.doc.company), raise_exception=1) (res[0][0], res[0][1], self.company), raise_exception=1)
else: else:
msgprint("Global POS Setting already created - %s for this company: '%s'" % msgprint("Global POS Setting already created - %s for this company: '%s'" %
(res[0][0], self.doc.company), raise_exception=1) (res[0][0], self.company), raise_exception=1)
def validate_expense_account(self): def validate_expense_account(self):
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \ if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
and not self.doc.expense_account: and not self.expense_account:
msgprint(_("Expense Account is mandatory"), raise_exception=1) msgprint(_("Expense Account is mandatory"), raise_exception=1)
def validate_all_link_fields(self): def validate_all_link_fields(self):
accounts = {"Account": [self.doc.cash_bank_account, self.doc.income_account, accounts = {"Account": [self.cash_bank_account, self.income_account,
self.doc.expense_account], "Cost Center": [self.doc.cost_center], self.expense_account], "Cost Center": [self.cost_center],
"Warehouse": [self.doc.warehouse]} "Warehouse": [self.warehouse]}
for link_dt, dn_list in accounts.items(): for link_dt, dn_list in accounts.items():
for link_dn in dn_list: for link_dn in dn_list:
if link_dn and not frappe.db.exists({"doctype": link_dt, if link_dn and not frappe.db.exists({"doctype": link_dt,
"company": self.doc.company, "name": link_dn}): "company": self.company, "name": link_dn}):
frappe.throw(link_dn +_(" does not belong to ") + self.doc.company) frappe.throw(link_dn +_(" does not belong to ") + self.company)
def on_update(self): def on_update(self):
self.set_defaults() self.set_defaults()
@ -59,7 +59,7 @@ class PosSetting(Document):
frappe.defaults.clear_default("is_pos") frappe.defaults.clear_default("is_pos")
if not include_current_pos: if not include_current_pos:
condition = " where name != '%s'" % self.doc.name.replace("'", "\'") condition = " where name != '%s'" % self.name.replace("'", "\'")
else: else:
condition = "" condition = ""

View File

@ -16,14 +16,14 @@ class PricingRule(DocListController):
def validate_mandatory(self): def validate_mandatory(self):
for field in ["apply_on", "applicable_for", "price_or_discount"]: for field in ["apply_on", "applicable_for", "price_or_discount"]:
val = self.doc.fields.get("applicable_for") val = self.get("applicable_for")
if val and not self.doc.fields.get(frappe.scrub(val)): if val and not self.get(frappe.scrub(val)):
throw("{fname} {msg}".format(fname = _(val), msg = _(" is mandatory")), throw("{fname} {msg}".format(fname = _(val), msg = _(" is mandatory")),
frappe.MandatoryError) frappe.MandatoryError)
def cleanup_fields_value(self): def cleanup_fields_value(self):
for logic_field in ["apply_on", "applicable_for", "price_or_discount"]: for logic_field in ["apply_on", "applicable_for", "price_or_discount"]:
fieldname = frappe.scrub(self.doc.fields.get(logic_field) or "") fieldname = frappe.scrub(self.get(logic_field) or "")
# reset all values except for the logic field # reset all values except for the logic field
options = (self.meta.get_options(logic_field) or "").split("\n") options = (self.meta.get_options(logic_field) or "").split("\n")
@ -32,5 +32,5 @@ class PricingRule(DocListController):
f = frappe.scrub(f) f = frappe.scrub(f)
if f!=fieldname: if f!=fieldname:
self.doc.fields[f] = None self.set(f, None)

View File

@ -39,18 +39,18 @@ class TestPricingRule(unittest.TestCase):
self.assertEquals(details.get("discount_percentage"), 10) self.assertEquals(details.get("discount_percentage"), 10)
prule = frappe.bean(copy=test_record) prule = frappe.bean(copy=test_record)
prule.doc.applicable_for = "Customer" prule.applicable_for = "Customer"
self.assertRaises(MandatoryError, prule.insert) self.assertRaises(MandatoryError, prule.insert)
prule.doc.customer = "_Test Customer" prule.customer = "_Test Customer"
prule.doc.discount_percentage = 20 prule.discount_percentage = 20
prule.insert() prule.insert()
details = get_item_details(args) details = get_item_details(args)
self.assertEquals(details.get("discount_percentage"), 20) self.assertEquals(details.get("discount_percentage"), 20)
prule = frappe.bean(copy=test_record) prule = frappe.bean(copy=test_record)
prule.doc.apply_on = "Item Group" prule.apply_on = "Item Group"
prule.doc.item_group = "All Item Groups" prule.item_group = "All Item Groups"
prule.doc.discount_percentage = 15 prule.discount_percentage = 15
prule.insert() prule.insert()
args.customer = None args.customer = None
@ -58,10 +58,10 @@ class TestPricingRule(unittest.TestCase):
self.assertEquals(details.get("discount_percentage"), 10) self.assertEquals(details.get("discount_percentage"), 10)
prule = frappe.bean(copy=test_record) prule = frappe.bean(copy=test_record)
prule.doc.applicable_for = "Campaign" prule.applicable_for = "Campaign"
prule.doc.campaign = "_Test Campaign" prule.campaign = "_Test Campaign"
prule.doc.discount_percentage = 5 prule.discount_percentage = 5
prule.doc.priority = 8 prule.priority = 8
prule.insert() prule.insert()
args.campaign = "_Test Campaign" args.campaign = "_Test Campaign"

View File

@ -31,8 +31,8 @@ class PurchaseInvoice(BuyingController):
}] }]
def validate(self): def validate(self):
if not self.doc.is_opening: if not self.is_opening:
self.doc.is_opening = 'No' self.is_opening = 'No'
super(DocType, self).validate() super(DocType, self).validate()
@ -56,16 +56,16 @@ class PurchaseInvoice(BuyingController):
"purchase_receipt_details") "purchase_receipt_details")
def set_missing_values(self, for_validate=False): def set_missing_values(self, for_validate=False):
if not self.doc.credit_to: if not self.credit_to:
self.doc.credit_to = get_party_account(self.doc.company, self.doc.supplier, "Supplier") self.credit_to = get_party_account(self.company, self.supplier, "Supplier")
if not self.doc.due_date: if not self.due_date:
self.doc.due_date = get_due_date(self.doc.posting_date, self.doc.supplier, "Supplier", self.due_date = get_due_date(self.posting_date, self.supplier, "Supplier",
self.doc.credit_to, self.doc.company) self.credit_to, self.company)
super(DocType, self).set_missing_values(for_validate) super(DocType, self).set_missing_values(for_validate)
def get_advances(self): def get_advances(self):
super(DocType, self).get_advances(self.doc.credit_to, super(DocType, self).get_advances(self.credit_to,
"Purchase Invoice Advance", "advance_allocation_details", "debit") "Purchase Invoice Advance", "advance_allocation_details", "debit")
def check_active_purchase_items(self): def check_active_purchase_items(self):
@ -80,44 +80,44 @@ class PurchaseInvoice(BuyingController):
raise Exception raise Exception
def check_conversion_rate(self): def check_conversion_rate(self):
default_currency = get_company_currency(self.doc.company) default_currency = get_company_currency(self.company)
if not default_currency: if not default_currency:
msgprint('Message: Please enter default currency in Company Master') msgprint('Message: Please enter default currency in Company Master')
raise Exception raise Exception
if (self.doc.currency == default_currency and flt(self.doc.conversion_rate) != 1.00) or not self.doc.conversion_rate or (self.doc.currency != default_currency and flt(self.doc.conversion_rate) == 1.00): if (self.currency == default_currency and flt(self.conversion_rate) != 1.00) or not self.conversion_rate or (self.currency != default_currency and flt(self.conversion_rate) == 1.00):
msgprint("Message: Please Enter Appropriate Conversion Rate.") msgprint("Message: Please Enter Appropriate Conversion Rate.")
raise Exception raise Exception
def validate_bill_no(self): def validate_bill_no(self):
if self.doc.bill_no and self.doc.bill_no.lower().strip() \ if self.bill_no and self.bill_no.lower().strip() \
not in ['na', 'not applicable', 'none']: not in ['na', 'not applicable', 'none']:
b_no = frappe.db.sql("""select bill_no, name, ifnull(is_opening,'') from `tabPurchase Invoice` b_no = frappe.db.sql("""select bill_no, name, ifnull(is_opening,'') from `tabPurchase Invoice`
where bill_no = %s and credit_to = %s and docstatus = 1 and name != %s""", where bill_no = %s and credit_to = %s and docstatus = 1 and name != %s""",
(self.doc.bill_no, self.doc.credit_to, self.doc.name)) (self.bill_no, self.credit_to, self.name))
if b_no and cstr(b_no[0][2]) == cstr(self.doc.is_opening): if b_no and cstr(b_no[0][2]) == cstr(self.is_opening):
msgprint("Please check you have already booked expense against Bill No. %s \ msgprint("Please check you have already booked expense against Bill No. %s \
in Purchase Invoice %s" % (cstr(b_no[0][0]), cstr(b_no[0][1])), in Purchase Invoice %s" % (cstr(b_no[0][0]), cstr(b_no[0][1])),
raise_exception=1) raise_exception=1)
if not self.doc.remarks and self.doc.bill_date: if not self.remarks and self.bill_date:
self.doc.remarks = (self.doc.remarks or '') + "\n" + ("Against Bill %s dated %s" self.remarks = (self.remarks or '') + "\n" + ("Against Bill %s dated %s"
% (self.doc.bill_no, formatdate(self.doc.bill_date))) % (self.bill_no, formatdate(self.bill_date)))
if not self.doc.remarks: if not self.remarks:
self.doc.remarks = "No Remarks" self.remarks = "No Remarks"
def validate_credit_acc(self): def validate_credit_acc(self):
if frappe.db.get_value("Account", self.doc.credit_to, "report_type") != "Balance Sheet": if frappe.db.get_value("Account", self.credit_to, "report_type") != "Balance Sheet":
frappe.throw(_("Account must be a balance sheet account")) frappe.throw(_("Account must be a balance sheet account"))
# Validate Acc Head of Supplier and Credit To Account entered # Validate Acc Head of Supplier and Credit To Account entered
# ------------------------------------------------------------ # ------------------------------------------------------------
def check_for_acc_head_of_supplier(self): def check_for_acc_head_of_supplier(self):
if self.doc.supplier and self.doc.credit_to: if self.supplier and self.credit_to:
acc_head = frappe.db.sql("select master_name from `tabAccount` where name = %s", self.doc.credit_to) acc_head = frappe.db.sql("select master_name from `tabAccount` where name = %s", self.credit_to)
if (acc_head and cstr(acc_head[0][0]) != cstr(self.doc.supplier)) or (not acc_head and (self.doc.credit_to != cstr(self.doc.supplier) + " - " + self.company_abbr)): if (acc_head and cstr(acc_head[0][0]) != cstr(self.supplier)) or (not acc_head and (self.credit_to != cstr(self.supplier) + " - " + self.company_abbr)):
msgprint("Credit To: %s do not match with Supplier: %s for Company: %s.\n If both correctly entered, please select Master Type and Master Name in account master." %(self.doc.credit_to,self.doc.supplier,self.doc.company), raise_exception=1) msgprint("Credit To: %s do not match with Supplier: %s for Company: %s.\n If both correctly entered, please select Master Type and Master Name in account master." %(self.credit_to,self.supplier,self.company), raise_exception=1)
# Check for Stopped PO # Check for Stopped PO
# --------------------- # ---------------------
@ -171,9 +171,9 @@ class PurchaseInvoice(BuyingController):
def set_aging_date(self): def set_aging_date(self):
if self.doc.is_opening != 'Yes': if self.is_opening != 'Yes':
self.doc.aging_date = self.doc.posting_date self.aging_date = self.posting_date
elif not self.doc.aging_date: elif not self.aging_date:
msgprint("Aging Date is mandatory for opening entry") msgprint("Aging Date is mandatory for opening entry")
raise Exception raise Exception
@ -187,7 +187,7 @@ class PurchaseInvoice(BuyingController):
stock_items = self.get_stock_items() stock_items = self.get_stock_items()
for item in self.get("entries"): for item in self.get("entries"):
if auto_accounting_for_stock and item.item_code in stock_items \ if auto_accounting_for_stock and item.item_code in stock_items \
and self.doc.is_opening == 'No': and self.is_opening == 'No':
# in case of auto inventory accounting, against expense account is always # in case of auto inventory accounting, against expense account is always
# Stock Received But Not Billed for a stock item # Stock Received But Not Billed for a stock item
item.expense_account = stock_not_billed_account item.expense_account = stock_not_billed_account
@ -204,7 +204,7 @@ class PurchaseInvoice(BuyingController):
# if no auto_accounting_for_stock or not a stock item # if no auto_accounting_for_stock or not a stock item
against_accounts.append(item.expense_account) against_accounts.append(item.expense_account)
self.doc.against_expense_account = ",".join(against_accounts) self.against_expense_account = ",".join(against_accounts)
def po_required(self): def po_required(self):
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes': if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
@ -221,7 +221,7 @@ class PurchaseInvoice(BuyingController):
raise Exception raise Exception
def validate_write_off_account(self): def validate_write_off_account(self):
if self.doc.write_off_amount and not self.doc.write_off_account: if self.write_off_amount and not self.write_off_account:
msgprint("Please enter Write Off Account", raise_exception=1) msgprint("Please enter Write Off Account", raise_exception=1)
def check_prev_docstatus(self): def check_prev_docstatus(self):
@ -251,8 +251,8 @@ class PurchaseInvoice(BuyingController):
'voucher_no' : d.journal_voucher, 'voucher_no' : d.journal_voucher,
'voucher_detail_no' : d.jv_detail_no, 'voucher_detail_no' : d.jv_detail_no,
'against_voucher_type' : 'Purchase Invoice', 'against_voucher_type' : 'Purchase Invoice',
'against_voucher' : self.doc.name, 'against_voucher' : self.name,
'account' : self.doc.credit_to, 'account' : self.credit_to,
'is_advance' : 'Yes', 'is_advance' : 'Yes',
'dr_or_cr' : 'debit', 'dr_or_cr' : 'debit',
'unadjusted_amt' : flt(d.advance_amount), 'unadjusted_amt' : flt(d.advance_amount),
@ -267,8 +267,8 @@ class PurchaseInvoice(BuyingController):
def on_submit(self): def on_submit(self):
self.check_prev_docstatus() self.check_prev_docstatus()
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, get_obj('Authorization Control').validate_approving_authority(self.doctype,
self.doc.company, self.doc.grand_total) self.company, self.grand_total)
# this sequence because outstanding may get -negative # this sequence because outstanding may get -negative
self.make_gl_entries() self.make_gl_entries()
@ -283,15 +283,15 @@ class PurchaseInvoice(BuyingController):
gl_entries = [] gl_entries = []
# parent's gl entry # parent's gl entry
if self.doc.grand_total: if self.grand_total:
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.credit_to, "account": self.credit_to,
"against": self.doc.against_expense_account, "against": self.against_expense_account,
"credit": self.doc.total_amount_to_pay, "credit": self.total_amount_to_pay,
"remarks": self.doc.remarks, "remarks": self.remarks,
"against_voucher": self.doc.name, "against_voucher": self.name,
"against_voucher_type": self.doc.doctype, "against_voucher_type": self.doctype,
}) })
) )
@ -302,10 +302,10 @@ class PurchaseInvoice(BuyingController):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": tax.account_head, "account": tax.account_head,
"against": self.doc.credit_to, "against": self.credit_to,
"debit": tax.add_deduct_tax == "Add" and tax.tax_amount or 0, "debit": tax.add_deduct_tax == "Add" and tax.tax_amount or 0,
"credit": tax.add_deduct_tax == "Deduct" and tax.tax_amount or 0, "credit": tax.add_deduct_tax == "Deduct" and tax.tax_amount or 0,
"remarks": self.doc.remarks, "remarks": self.remarks,
"cost_center": tax.cost_center "cost_center": tax.cost_center
}) })
) )
@ -337,9 +337,9 @@ class PurchaseInvoice(BuyingController):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": item.expense_account, "account": item.expense_account,
"against": self.doc.credit_to, "against": self.credit_to,
"debit": valuation_amt, "debit": valuation_amt,
"remarks": self.doc.remarks or "Accounting Entry for Stock" "remarks": self.remarks or "Accounting Entry for Stock"
}) })
) )
@ -348,9 +348,9 @@ class PurchaseInvoice(BuyingController):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": item.expense_account, "account": item.expense_account,
"against": self.doc.credit_to, "against": self.credit_to,
"debit": item.base_amount, "debit": item.base_amount,
"remarks": self.doc.remarks, "remarks": self.remarks,
"cost_center": item.cost_center "cost_center": item.cost_center
}) })
) )
@ -366,32 +366,32 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict({ self.get_gl_dict({
"account": expenses_included_in_valuation, "account": expenses_included_in_valuation,
"cost_center": cost_center, "cost_center": cost_center,
"against": self.doc.credit_to, "against": self.credit_to,
"credit": amount, "credit": amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock" "remarks": self.remarks or "Accounting Entry for Stock"
}) })
) )
# writeoff account includes petty difference in the invoice amount # writeoff account includes petty difference in the invoice amount
# and the amount that is paid # and the amount that is paid
if self.doc.write_off_account and flt(self.doc.write_off_amount): if self.write_off_account and flt(self.write_off_amount):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.write_off_account, "account": self.write_off_account,
"against": self.doc.credit_to, "against": self.credit_to,
"credit": flt(self.doc.write_off_amount), "credit": flt(self.write_off_amount),
"remarks": self.doc.remarks, "remarks": self.remarks,
"cost_center": self.doc.write_off_cost_center "cost_center": self.write_off_cost_center
}) })
) )
if gl_entries: if gl_entries:
from erpnext.accounts.general_ledger import make_gl_entries from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2)) make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
def on_cancel(self): def on_cancel(self):
from erpnext.accounts.utils import remove_against_link_from_jv from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_voucher") remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
self.update_prevdoc_status() self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order") self.update_billing_status_for_zero_amount_refdoc("Purchase Order")

View File

@ -51,7 +51,7 @@ class TestPurchaseInvoice(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""", pi.doc.name, as_dict=1) order by account asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = sorted([ expected_values = sorted([
@ -83,7 +83,7 @@ class TestPurchaseInvoice(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""", pi.doc.name, as_dict=1) order by account asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = sorted([ expected_values = sorted([
@ -175,28 +175,28 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.bean(copy=test_records[0]) pi = frappe.bean(copy=test_records[0])
pi.append("advance_allocation_details", { pi.append("advance_allocation_details", {
"journal_voucher": jv.doc.name, "journal_voucher": jv.name,
"jv_detail_no": jv.doclist[1].name, "jv_detail_no": jv.doclist[1].name,
"advance_amount": 400, "advance_amount": 400,
"allocated_amount": 300, "allocated_amount": 300,
"remarks": jv.doc.remark "remarks": jv.remark
}) })
pi.insert() pi.insert()
pi.submit() pi.submit()
pi.load_from_db() pi.load_from_db()
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_voucher=%s""", pi.doc.name)) where against_voucher=%s""", pi.name))
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_voucher=%s and debit=300""", pi.doc.name)) where against_voucher=%s and debit=300""", pi.name))
self.assertEqual(pi.doc.outstanding_amount, 1212.30) self.assertEqual(pi.outstanding_amount, 1212.30)
pi.cancel() pi.cancel()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_voucher=%s""", pi.doc.name)) where against_voucher=%s""", pi.name))
test_records = [ test_records = [
[ [

View File

@ -52,17 +52,17 @@ class SalesInvoice(SellingController):
self.clear_unallocated_advances("Sales Invoice Advance", "advance_adjustment_details") self.clear_unallocated_advances("Sales Invoice Advance", "advance_adjustment_details")
self.add_remarks() self.add_remarks()
if cint(self.doc.is_pos): if cint(self.is_pos):
self.validate_pos() self.validate_pos()
self.validate_write_off_account() self.validate_write_off_account()
if cint(self.doc.update_stock): if cint(self.update_stock):
self.validate_item_code() self.validate_item_code()
self.update_current_stock() self.update_current_stock()
self.validate_delivery_note() self.validate_delivery_note()
if not self.doc.is_opening: if not self.is_opening:
self.doc.is_opening = 'No' self.is_opening = 'No'
self.set_aging_date() self.set_aging_date()
self.set_against_income_account() self.set_against_income_account()
@ -73,13 +73,13 @@ class SalesInvoice(SellingController):
"delivery_note_details") "delivery_note_details")
def on_submit(self): def on_submit(self):
if cint(self.doc.update_stock) == 1: if cint(self.update_stock) == 1:
self.update_stock_ledger() self.update_stock_ledger()
else: else:
# Check for Approving Authority # Check for Approving Authority
if not self.doc.recurring_id: if not self.recurring_id:
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, get_obj('Authorization Control').validate_approving_authority(self.doctype,
self.doc.company, self.doc.grand_total, self) self.company, self.grand_total, self)
self.check_prev_docstatus() self.check_prev_docstatus()
@ -89,26 +89,26 @@ class SalesInvoice(SellingController):
# this sequence because outstanding may get -ve # this sequence because outstanding may get -ve
self.make_gl_entries() self.make_gl_entries()
self.check_credit_limit(self.doc.debit_to) self.check_credit_limit(self.debit_to)
if not cint(self.doc.is_pos) == 1: if not cint(self.is_pos) == 1:
self.update_against_document_in_jv() self.update_against_document_in_jv()
self.update_c_form() self.update_c_form()
self.update_time_log_batch(self.doc.name) self.update_time_log_batch(self.name)
self.convert_to_recurring() self.convert_to_recurring()
def before_cancel(self): def before_cancel(self):
self.update_time_log_batch(None) self.update_time_log_batch(None)
def on_cancel(self): def on_cancel(self):
if cint(self.doc.update_stock) == 1: if cint(self.update_stock) == 1:
self.update_stock_ledger() self.update_stock_ledger()
self.check_stop_sales_order("sales_order") self.check_stop_sales_order("sales_order")
from erpnext.accounts.utils import remove_against_link_from_jv from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_invoice") remove_against_link_from_jv(self.doctype, self.name, "against_invoice")
self.update_status_updater_args() self.update_status_updater_args()
self.update_prevdoc_status() self.update_prevdoc_status()
@ -117,7 +117,7 @@ class SalesInvoice(SellingController):
self.make_cancel_gl_entries() self.make_cancel_gl_entries()
def update_status_updater_args(self): def update_status_updater_args(self):
if cint(self.doc.update_stock): if cint(self.update_stock):
self.status_updater.append({ self.status_updater.append({
'source_dt':'Sales Invoice Item', 'source_dt':'Sales Invoice Item',
'target_dt':'Sales Order Item', 'target_dt':'Sales Order Item',
@ -140,16 +140,16 @@ class SalesInvoice(SellingController):
self.convert_to_recurring() self.convert_to_recurring()
def get_portal_page(self): def get_portal_page(self):
return "invoice" if self.doc.docstatus==1 else None return "invoice" if self.docstatus==1 else None
def set_missing_values(self, for_validate=False): def set_missing_values(self, for_validate=False):
self.set_pos_fields(for_validate) self.set_pos_fields(for_validate)
if not self.doc.debit_to: if not self.debit_to:
self.doc.debit_to = get_party_account(self.doc.company, self.doc.customer, "Customer") self.debit_to = get_party_account(self.company, self.customer, "Customer")
if not self.doc.due_date: if not self.due_date:
self.doc.due_date = get_due_date(self.doc.posting_date, self.doc.customer, "Customer", self.due_date = get_due_date(self.posting_date, self.customer, "Customer",
self.doc.debit_to, self.doc.company) self.debit_to, self.company)
super(DocType, self).set_missing_values(for_validate) super(DocType, self).set_missing_values(for_validate)
@ -157,7 +157,7 @@ class SalesInvoice(SellingController):
for d in self.doclist.get({"doctype":"Sales Invoice Item"}): for d in self.doclist.get({"doctype":"Sales Invoice Item"}):
if d.time_log_batch: if d.time_log_batch:
tlb = frappe.bean("Time Log Batch", d.time_log_batch) tlb = frappe.bean("Time Log Batch", d.time_log_batch)
tlb.doc.sales_invoice = sales_invoice tlb.sales_invoice = sales_invoice
tlb.update_after_submit() tlb.update_after_submit()
def validate_time_logs_are_submitted(self): def validate_time_logs_are_submitted(self):
@ -170,48 +170,48 @@ class SalesInvoice(SellingController):
def set_pos_fields(self, for_validate=False): def set_pos_fields(self, for_validate=False):
"""Set retail related fields from pos settings""" """Set retail related fields from pos settings"""
if cint(self.doc.is_pos) != 1: if cint(self.is_pos) != 1:
return return
from erpnext.stock.get_item_details import get_pos_settings_item_details, get_pos_settings from erpnext.stock.get_item_details import get_pos_settings_item_details, get_pos_settings
pos = get_pos_settings(self.doc.company) pos = get_pos_settings(self.company)
if pos: if pos:
if not for_validate and not self.doc.customer: if not for_validate and not self.customer:
self.doc.customer = pos.customer self.customer = pos.customer
# self.set_customer_defaults() # self.set_customer_defaults()
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name', for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account'): 'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account'):
if (not for_validate) or (for_validate and not self.doc.fields.get(fieldname)): if (not for_validate) or (for_validate and not self.get(fieldname)):
self.doc.fields[fieldname] = pos.get(fieldname) self.set(fieldname, pos.get(fieldname))
if not for_validate: if not for_validate:
self.doc.update_stock = cint(pos.get("update_stock")) self.update_stock = cint(pos.get("update_stock"))
# set pos values in items # set pos values in items
for item in self.get("entries"): for item in self.get("entries"):
if item.fields.get('item_code'): if item.get('item_code'):
for fname, val in get_pos_settings_item_details(pos, for fname, val in get_pos_settings_item_details(pos,
frappe._dict(item.fields), pos).items(): frappe._dict(item.fields), pos).items():
if (not for_validate) or (for_validate and not item.fields.get(fname)): if (not for_validate) or (for_validate and not item.get(fname)):
item.fields[fname] = val item.set(fname, val)
# fetch terms # fetch terms
if self.doc.tc_name and not self.doc.terms: if self.tc_name and not self.terms:
self.doc.terms = frappe.db.get_value("Terms and Conditions", self.doc.tc_name, "terms") self.terms = frappe.db.get_value("Terms and Conditions", self.tc_name, "terms")
# fetch charges # fetch charges
if self.doc.charge and not len(self.get("other_charges")): if self.charge and not len(self.get("other_charges")):
self.set_taxes("other_charges", "taxes_and_charges") self.set_taxes("other_charges", "taxes_and_charges")
def get_advances(self): def get_advances(self):
super(DocType, self).get_advances(self.doc.debit_to, super(DocType, self).get_advances(self.debit_to,
"Sales Invoice Advance", "advance_adjustment_details", "credit") "Sales Invoice Advance", "advance_adjustment_details", "credit")
def get_company_abbr(self): def get_company_abbr(self):
return frappe.db.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
def update_against_document_in_jv(self): def update_against_document_in_jv(self):
""" """
@ -228,8 +228,8 @@ class SalesInvoice(SellingController):
'voucher_no' : d.journal_voucher, 'voucher_no' : d.journal_voucher,
'voucher_detail_no' : d.jv_detail_no, 'voucher_detail_no' : d.jv_detail_no,
'against_voucher_type' : 'Sales Invoice', 'against_voucher_type' : 'Sales Invoice',
'against_voucher' : self.doc.name, 'against_voucher' : self.name,
'account' : self.doc.debit_to, 'account' : self.debit_to,
'is_advance' : 'Yes', 'is_advance' : 'Yes',
'dr_or_cr' : 'credit', 'dr_or_cr' : 'credit',
'unadjusted_amt' : flt(d.advance_amount), 'unadjusted_amt' : flt(d.advance_amount),
@ -243,17 +243,17 @@ class SalesInvoice(SellingController):
def validate_customer_account(self): def validate_customer_account(self):
"""Validates Debit To Account and Customer Matches""" """Validates Debit To Account and Customer Matches"""
if self.doc.customer and self.doc.debit_to and not cint(self.doc.is_pos): if self.customer and self.debit_to and not cint(self.is_pos):
acc_head = frappe.db.sql("select master_name from `tabAccount` where name = %s and docstatus != 2", self.doc.debit_to) acc_head = frappe.db.sql("select master_name from `tabAccount` where name = %s and docstatus != 2", self.debit_to)
if (acc_head and cstr(acc_head[0][0]) != cstr(self.doc.customer)) or \ if (acc_head and cstr(acc_head[0][0]) != cstr(self.customer)) or \
(not acc_head and (self.doc.debit_to != cstr(self.doc.customer) + " - " + self.get_company_abbr())): (not acc_head and (self.debit_to != cstr(self.customer) + " - " + self.get_company_abbr())):
msgprint("Debit To: %s do not match with Customer: %s for Company: %s.\n If both correctly entered, please select Master Type \ msgprint("Debit To: %s do not match with Customer: %s for Company: %s.\n If both correctly entered, please select Master Type \
and Master Name in account master." %(self.doc.debit_to, self.doc.customer,self.doc.company), raise_exception=1) and Master Name in account master." %(self.debit_to, self.customer,self.company), raise_exception=1)
def validate_debit_acc(self): def validate_debit_acc(self):
if frappe.db.get_value("Account", self.doc.debit_to, "report_type") != "Balance Sheet": if frappe.db.get_value("Account", self.debit_to, "report_type") != "Balance Sheet":
frappe.throw(_("Account must be a balance sheet account")) frappe.throw(_("Account must be a balance sheet account"))
def validate_fixed_asset_account(self): def validate_fixed_asset_account(self):
@ -300,9 +300,9 @@ class SalesInvoice(SellingController):
def set_aging_date(self): def set_aging_date(self):
if self.doc.is_opening != 'Yes': if self.is_opening != 'Yes':
self.doc.aging_date = self.doc.posting_date self.aging_date = self.posting_date
elif not self.doc.aging_date: elif not self.aging_date:
msgprint("Aging Date is mandatory for opening entry") msgprint("Aging Date is mandatory for opening entry")
raise Exception raise Exception
@ -313,11 +313,11 @@ class SalesInvoice(SellingController):
for d in self.get('entries'): for d in self.get('entries'):
if d.income_account not in against_acc: if d.income_account not in against_acc:
against_acc.append(d.income_account) against_acc.append(d.income_account)
self.doc.against_income_account = ','.join(against_acc) self.against_income_account = ','.join(against_acc)
def add_remarks(self): def add_remarks(self):
if not self.doc.remarks: self.doc.remarks = 'No Remarks' if not self.remarks: self.remarks = 'No Remarks'
def so_dn_required(self): def so_dn_required(self):
@ -333,20 +333,20 @@ class SalesInvoice(SellingController):
def validate_proj_cust(self): def validate_proj_cust(self):
"""check for does customer belong to same project as entered..""" """check for does customer belong to same project as entered.."""
if self.doc.project_name and self.doc.customer: if self.project_name and self.customer:
res = frappe.db.sql("""select name from `tabProject` res = frappe.db.sql("""select name from `tabProject`
where name = %s and (customer = %s or where name = %s and (customer = %s or
ifnull(customer,'')='')""", (self.doc.project_name, self.doc.customer)) ifnull(customer,'')='')""", (self.project_name, self.customer))
if not res: if not res:
msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in that project."%(self.doc.customer,self.doc.project_name)) msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in that project."%(self.customer,self.project_name))
raise Exception raise Exception
def validate_pos(self): def validate_pos(self):
if not self.doc.cash_bank_account and flt(self.doc.paid_amount): if not self.cash_bank_account and flt(self.paid_amount):
msgprint("Cash/Bank Account is mandatory for POS, for making payment entry") msgprint("Cash/Bank Account is mandatory for POS, for making payment entry")
raise Exception raise Exception
if flt(self.doc.paid_amount) + flt(self.doc.write_off_amount) \ if flt(self.paid_amount) + flt(self.write_off_amount) \
- flt(self.doc.grand_total) > 1/(10**(self.precision("grand_total") + 1)): - flt(self.grand_total) > 1/(10**(self.precision("grand_total") + 1)):
frappe.throw(_("""(Paid amount + Write Off Amount) can not be \ frappe.throw(_("""(Paid amount + Write Off Amount) can not be \
greater than Grand Total""")) greater than Grand Total"""))
@ -364,15 +364,15 @@ class SalesInvoice(SellingController):
def validate_write_off_account(self): def validate_write_off_account(self):
if flt(self.doc.write_off_amount) and not self.doc.write_off_account: if flt(self.write_off_amount) and not self.write_off_account:
msgprint("Please enter Write Off Account", raise_exception=1) msgprint("Please enter Write Off Account", raise_exception=1)
def validate_c_form(self): def validate_c_form(self):
""" Blank C-form no if C-form applicable marked as 'No'""" """ Blank C-form no if C-form applicable marked as 'No'"""
if self.doc.amended_from and self.doc.c_form_applicable == 'No' and self.doc.c_form_no: if self.amended_from and self.c_form_applicable == 'No' and self.c_form_no:
frappe.db.sql("""delete from `tabC-Form Invoice Detail` where invoice_no = %s frappe.db.sql("""delete from `tabC-Form Invoice Detail` where invoice_no = %s
and parent = %s""", (self.doc.amended_from, self.doc.c_form_no)) and parent = %s""", (self.amended_from, self.c_form_no))
frappe.db.set(self.doc, 'c_form_no', '') frappe.db.set(self.doc, 'c_form_no', '')
@ -391,11 +391,11 @@ class SalesInvoice(SellingController):
def get_warehouse(self): def get_warehouse(self):
w = frappe.db.sql("""select warehouse from `tabPOS Setting` w = frappe.db.sql("""select warehouse from `tabPOS Setting`
where ifnull(user,'') = %s and company = %s""", where ifnull(user,'') = %s and company = %s""",
(frappe.session['user'], self.doc.company)) (frappe.session['user'], self.company))
w = w and w[0][0] or '' w = w and w[0][0] or ''
if not w: if not w:
ps = frappe.db.sql("""select name, warehouse from `tabPOS Setting` ps = frappe.db.sql("""select name, warehouse from `tabPOS Setting`
where ifnull(user,'') = '' and company = %s""", self.doc.company) where ifnull(user,'') = '' and company = %s""", self.company)
if not ps: if not ps:
msgprint("To make POS entry, please create POS Setting from Accounts --> POS Setting page and refresh the system.", raise_exception=True) msgprint("To make POS entry, please create POS Setting from Accounts --> POS Setting page and refresh the system.", raise_exception=True)
elif not ps[0][1]: elif not ps[0][1]:
@ -405,9 +405,9 @@ class SalesInvoice(SellingController):
return w return w
def on_update(self): def on_update(self):
if cint(self.doc.update_stock) == 1: if cint(self.update_stock) == 1:
# Set default warehouse from pos setting # Set default warehouse from pos setting
if cint(self.doc.is_pos) == 1: if cint(self.is_pos) == 1:
w = self.get_warehouse() w = self.get_warehouse()
if w: if w:
for d in self.get('entries'): for d in self.get('entries'):
@ -419,11 +419,11 @@ class SalesInvoice(SellingController):
else: else:
self.set('packing_details', []) self.set('packing_details', [])
if cint(self.doc.is_pos) == 1: if cint(self.is_pos) == 1:
if flt(self.doc.paid_amount) == 0: if flt(self.paid_amount) == 0:
if self.doc.cash_bank_account: if self.cash_bank_account:
frappe.db.set(self.doc, 'paid_amount', frappe.db.set(self.doc, 'paid_amount',
(flt(self.doc.grand_total) - flt(self.doc.write_off_amount))) (flt(self.grand_total) - flt(self.write_off_amount)))
else: else:
# show message that the amount is not paid # show message that the amount is not paid
frappe.db.set(self.doc,'paid_amount',0) frappe.db.set(self.doc,'paid_amount',0)
@ -465,16 +465,16 @@ class SalesInvoice(SellingController):
if gl_entries: if gl_entries:
from erpnext.accounts.general_ledger import make_gl_entries from erpnext.accounts.general_ledger import make_gl_entries
update_outstanding = cint(self.doc.is_pos) and self.doc.write_off_account \ update_outstanding = cint(self.is_pos) and self.write_off_account \
and 'No' or 'Yes' and 'No' or 'Yes'
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2), make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False) update_outstanding=update_outstanding, merge_entries=False)
if repost_future_gle and cint(self.doc.update_stock) \ if repost_future_gle and cint(self.update_stock) \
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
items, warehouse_account = self.get_items_and_warehouse_accounts() items, warehouse_account = self.get_items_and_warehouse_accounts()
from controllers.stock_controller import update_gl_entries_after from controllers.stock_controller import update_gl_entries_after
update_gl_entries_after(self.doc.posting_date, self.doc.posting_time, update_gl_entries_after(self.posting_date, self.posting_time,
warehouse_account, items) warehouse_account, items)
def get_gl_entries(self, warehouse_account=None): def get_gl_entries(self, warehouse_account=None):
@ -496,15 +496,15 @@ class SalesInvoice(SellingController):
return gl_entries return gl_entries
def make_customer_gl_entry(self, gl_entries): def make_customer_gl_entry(self, gl_entries):
if self.doc.grand_total: if self.grand_total:
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.debit_to, "account": self.debit_to,
"against": self.doc.against_income_account, "against": self.against_income_account,
"debit": self.doc.grand_total, "debit": self.grand_total,
"remarks": self.doc.remarks, "remarks": self.remarks,
"against_voucher": self.doc.name, "against_voucher": self.name,
"against_voucher_type": self.doc.doctype, "against_voucher_type": self.doctype,
}) })
) )
@ -514,9 +514,9 @@ class SalesInvoice(SellingController):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": tax.account_head, "account": tax.account_head,
"against": self.doc.debit_to, "against": self.debit_to,
"credit": flt(tax.tax_amount_after_discount_amount), "credit": flt(tax.tax_amount_after_discount_amount),
"remarks": self.doc.remarks, "remarks": self.remarks,
"cost_center": tax.cost_center "cost_center": tax.cost_center
}) })
) )
@ -528,101 +528,101 @@ class SalesInvoice(SellingController):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": item.income_account, "account": item.income_account,
"against": self.doc.debit_to, "against": self.debit_to,
"credit": item.base_amount, "credit": item.base_amount,
"remarks": self.doc.remarks, "remarks": self.remarks,
"cost_center": item.cost_center "cost_center": item.cost_center
}) })
) )
# expense account gl entries # expense account gl entries
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \ if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
and cint(self.doc.update_stock): and cint(self.update_stock):
gl_entries += super(DocType, self).get_gl_entries() gl_entries += super(DocType, self).get_gl_entries()
def make_pos_gl_entries(self, gl_entries): def make_pos_gl_entries(self, gl_entries):
if cint(self.doc.is_pos) and self.doc.cash_bank_account and self.doc.paid_amount: if cint(self.is_pos) and self.cash_bank_account and self.paid_amount:
# POS, make payment entries # POS, make payment entries
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.debit_to, "account": self.debit_to,
"against": self.doc.cash_bank_account, "against": self.cash_bank_account,
"credit": self.doc.paid_amount, "credit": self.paid_amount,
"remarks": self.doc.remarks, "remarks": self.remarks,
"against_voucher": self.doc.name, "against_voucher": self.name,
"against_voucher_type": self.doc.doctype, "against_voucher_type": self.doctype,
}) })
) )
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.cash_bank_account, "account": self.cash_bank_account,
"against": self.doc.debit_to, "against": self.debit_to,
"debit": self.doc.paid_amount, "debit": self.paid_amount,
"remarks": self.doc.remarks, "remarks": self.remarks,
}) })
) )
# write off entries, applicable if only pos # write off entries, applicable if only pos
if self.doc.write_off_account and self.doc.write_off_amount: if self.write_off_account and self.write_off_amount:
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.debit_to, "account": self.debit_to,
"against": self.doc.write_off_account, "against": self.write_off_account,
"credit": self.doc.write_off_amount, "credit": self.write_off_amount,
"remarks": self.doc.remarks, "remarks": self.remarks,
"against_voucher": self.doc.name, "against_voucher": self.name,
"against_voucher_type": self.doc.doctype, "against_voucher_type": self.doctype,
}) })
) )
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.doc.write_off_account, "account": self.write_off_account,
"against": self.doc.debit_to, "against": self.debit_to,
"debit": self.doc.write_off_amount, "debit": self.write_off_amount,
"remarks": self.doc.remarks, "remarks": self.remarks,
"cost_center": self.doc.write_off_cost_center "cost_center": self.write_off_cost_center
}) })
) )
def update_c_form(self): def update_c_form(self):
"""Update amended id in C-form""" """Update amended id in C-form"""
if self.doc.c_form_no and self.doc.amended_from: if self.c_form_no and self.amended_from:
frappe.db.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s, frappe.db.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s,
invoice_date = %s, territory = %s, net_total = %s, invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""", grand_total = %s where invoice_no = %s and parent = %s""",
(self.doc.name, self.doc.amended_from, self.doc.c_form_no)) (self.name, self.amended_from, self.c_form_no))
def validate_recurring_invoice(self): def validate_recurring_invoice(self):
if self.doc.convert_into_recurring_invoice: if self.convert_into_recurring_invoice:
self.validate_notification_email_id() self.validate_notification_email_id()
if not self.doc.recurring_type: if not self.recurring_type:
msgprint(_("Please select: ") + self.meta.get_label("recurring_type"), msgprint(_("Please select: ") + self.meta.get_label("recurring_type"),
raise_exception=1) raise_exception=1)
elif not (self.doc.invoice_period_from_date and \ elif not (self.invoice_period_from_date and \
self.doc.invoice_period_to_date): self.invoice_period_to_date):
msgprint(comma_and([self.meta.get_label("invoice_period_from_date"), msgprint(comma_and([self.meta.get_label("invoice_period_from_date"),
self.meta.get_label("invoice_period_to_date")]) self.meta.get_label("invoice_period_to_date")])
+ _(": Mandatory for a Recurring Invoice."), + _(": Mandatory for a Recurring Invoice."),
raise_exception=True) raise_exception=True)
def convert_to_recurring(self): def convert_to_recurring(self):
if self.doc.convert_into_recurring_invoice: if self.convert_into_recurring_invoice:
if not self.doc.recurring_id: if not self.recurring_id:
frappe.db.set(self.doc, "recurring_id", frappe.db.set(self.doc, "recurring_id",
make_autoname("RECINV/.#####")) make_autoname("RECINV/.#####"))
self.set_next_date() self.set_next_date()
elif self.doc.recurring_id: elif self.recurring_id:
frappe.db.sql("""update `tabSales Invoice` frappe.db.sql("""update `tabSales Invoice`
set convert_into_recurring_invoice = 0 set convert_into_recurring_invoice = 0
where recurring_id = %s""", (self.doc.recurring_id,)) where recurring_id = %s""", (self.recurring_id,))
def validate_notification_email_id(self): def validate_notification_email_id(self):
if self.doc.notification_email_address: if self.notification_email_address:
email_list = filter(None, [cstr(email).strip() for email in email_list = filter(None, [cstr(email).strip() for email in
self.doc.notification_email_address.replace("\n", "").split(",")]) self.notification_email_address.replace("\n", "").split(",")])
from frappe.utils import validate_email_add from frappe.utils import validate_email_add
for email in email_list: for email in email_list:
@ -637,13 +637,13 @@ class SalesInvoice(SellingController):
def set_next_date(self): def set_next_date(self):
""" Set next date on which auto invoice will be created""" """ Set next date on which auto invoice will be created"""
if not self.doc.repeat_on_day_of_month: if not self.repeat_on_day_of_month:
msgprint("""Please enter 'Repeat on Day of Month' field value. msgprint("""Please enter 'Repeat on Day of Month' field value.
The day of the month on which auto invoice The day of the month on which auto invoice
will be generated e.g. 05, 28 etc.""", raise_exception=1) will be generated e.g. 05, 28 etc.""", raise_exception=1)
next_date = get_next_date(self.doc.posting_date, next_date = get_next_date(self.posting_date,
month_map[self.doc.recurring_type], cint(self.doc.repeat_on_day_of_month)) month_map[self.recurring_type], cint(self.repeat_on_day_of_month))
frappe.db.set(self.doc, 'next_date', next_date) frappe.db.set(self.doc, 'next_date', next_date)
@ -684,7 +684,7 @@ def manage_recurring_invoices(next_date=None, commit=True):
frappe.db.begin() frappe.db.begin()
frappe.db.sql("update `tabSales Invoice` set \ frappe.db.sql("update `tabSales Invoice` set \
convert_into_recurring_invoice = 0 where name = %s", ref_invoice) convert_into_recurring_invoice = 0 where name = %s", ref_invoice)
notify_errors(ref_invoice, ref_wrapper.doc.customer, ref_wrapper.doc.owner) notify_errors(ref_invoice, ref_wrapper.customer, ref_wrapper.owner)
frappe.db.commit() frappe.db.commit()
exception_list.append(frappe.get_traceback()) exception_list.append(frappe.get_traceback())
@ -701,30 +701,30 @@ def make_new_invoice(ref_wrapper, posting_date):
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year
new_invoice = clone(ref_wrapper) new_invoice = clone(ref_wrapper)
mcount = month_map[ref_wrapper.doc.recurring_type] mcount = month_map[ref_wrapper.recurring_type]
invoice_period_from_date = get_next_date(ref_wrapper.doc.invoice_period_from_date, mcount) invoice_period_from_date = get_next_date(ref_wrapper.invoice_period_from_date, mcount)
# get last day of the month to maintain period if the from date is first day of its own month # get last day of the month to maintain period if the from date is first day of its own month
# and to date is the last day of its own month # and to date is the last day of its own month
if (cstr(get_first_day(ref_wrapper.doc.invoice_period_from_date)) == \ if (cstr(get_first_day(ref_wrapper.invoice_period_from_date)) == \
cstr(ref_wrapper.doc.invoice_period_from_date)) and \ cstr(ref_wrapper.invoice_period_from_date)) and \
(cstr(get_last_day(ref_wrapper.doc.invoice_period_to_date)) == \ (cstr(get_last_day(ref_wrapper.invoice_period_to_date)) == \
cstr(ref_wrapper.doc.invoice_period_to_date)): cstr(ref_wrapper.invoice_period_to_date)):
invoice_period_to_date = get_last_day(get_next_date(ref_wrapper.doc.invoice_period_to_date, invoice_period_to_date = get_last_day(get_next_date(ref_wrapper.invoice_period_to_date,
mcount)) mcount))
else: else:
invoice_period_to_date = get_next_date(ref_wrapper.doc.invoice_period_to_date, mcount) invoice_period_to_date = get_next_date(ref_wrapper.invoice_period_to_date, mcount)
new_invoice.doc.fields.update({ new_invoice.update({
"posting_date": posting_date, "posting_date": posting_date,
"aging_date": posting_date, "aging_date": posting_date,
"due_date": add_days(posting_date, cint(date_diff(ref_wrapper.doc.due_date, "due_date": add_days(posting_date, cint(date_diff(ref_wrapper.due_date,
ref_wrapper.doc.posting_date))), ref_wrapper.posting_date))),
"invoice_period_from_date": invoice_period_from_date, "invoice_period_from_date": invoice_period_from_date,
"invoice_period_to_date": invoice_period_to_date, "invoice_period_to_date": invoice_period_to_date,
"fiscal_year": get_fiscal_year(posting_date)[0], "fiscal_year": get_fiscal_year(posting_date)[0],
"owner": ref_wrapper.doc.owner, "owner": ref_wrapper.owner,
}) })
new_invoice.submit() new_invoice.submit()
@ -735,8 +735,8 @@ def send_notification(new_rv):
"""Notify concerned persons about recurring invoice generation""" """Notify concerned persons about recurring invoice generation"""
from frappe.core.doctype.print_format.print_format import get_html from frappe.core.doctype.print_format.print_format import get_html
frappe.sendmail(new_rv.doc.notification_email_address, frappe.sendmail(new_rv.notification_email_address,
subject="New Invoice : " + new_rv.doc.name, subject="New Invoice : " + new_rv.name,
message = get_html(new_rv.doc, new_rv.doclist, "SalesInvoice")) message = get_html(new_rv.doc, new_rv.doclist, "SalesInvoice"))
def notify_errors(inv, customer, owner): def notify_errors(inv, customer, owner):

View File

@ -11,14 +11,14 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
class TestSalesInvoice(unittest.TestCase): class TestSalesInvoice(unittest.TestCase):
def make(self): def make(self):
w = frappe.bean(copy=test_records[0]) w = frappe.bean(copy=test_records[0])
w.doc.is_pos = 0 w.is_pos = 0
w.insert() w.insert()
w.submit() w.submit()
return w return w
def test_double_submission(self): def test_double_submission(self):
w = frappe.bean(copy=test_records[0]) w = frappe.bean(copy=test_records[0])
w.doc.docstatus = '0' w.docstatus = '0'
w.insert() w.insert()
w2 = [d for d in w.doclist] w2 = [d for d in w.doclist]
@ -29,7 +29,7 @@ class TestSalesInvoice(unittest.TestCase):
def test_timestamp_change(self): def test_timestamp_change(self):
w = frappe.bean(copy=test_records[0]) w = frappe.bean(copy=test_records[0])
w.doc.docstatus = '0' w.docstatus = '0'
w.insert() w.insert()
w2 = frappe.bean([d.fields.copy() for d in w.doclist]) w2 = frappe.bean([d.fields.copy() for d in w.doclist])
@ -60,11 +60,11 @@ class TestSalesInvoice(unittest.TestCase):
# check if item values are calculated # check if item values are calculated
for d in si.get("entries"): for d in si.get("entries"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.item_code][i]) self.assertEquals(d.get(k), expected_values[d.item_code][i])
# check net total # check net total
self.assertEquals(si.doc.net_total, 1250) self.assertEquals(si.net_total, 1250)
self.assertEquals(si.doc.net_total_export, 1250) self.assertEquals(si.net_total_export, 1250)
# check tax calculation # check tax calculation
expected_values = { expected_values = {
@ -81,15 +81,15 @@ class TestSalesInvoice(unittest.TestCase):
for d in si.get("other_charges"): for d in si.get("other_charges"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.doc.grand_total, 1627.05) self.assertEquals(si.grand_total, 1627.05)
self.assertEquals(si.doc.grand_total_export, 1627.05) self.assertEquals(si.grand_total_export, 1627.05)
def test_sales_invoice_calculation_export_currency(self): def test_sales_invoice_calculation_export_currency(self):
si = frappe.bean(copy=test_records[2]) si = frappe.bean(copy=test_records[2])
si.doc.currency = "USD" si.currency = "USD"
si.doc.conversion_rate = 50 si.conversion_rate = 50
si.doclist[1].rate = 1 si.doclist[1].rate = 1
si.doclist[1].price_list_rate = 1 si.doclist[1].price_list_rate = 1
si.doclist[2].rate = 3 si.doclist[2].rate = 3
@ -110,11 +110,11 @@ class TestSalesInvoice(unittest.TestCase):
# check if item values are calculated # check if item values are calculated
for d in si.get("entries"): for d in si.get("entries"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.item_code][i]) self.assertEquals(d.get(k), expected_values[d.item_code][i])
# check net total # check net total
self.assertEquals(si.doc.net_total, 1250) self.assertEquals(si.net_total, 1250)
self.assertEquals(si.doc.net_total_export, 25) self.assertEquals(si.net_total_export, 25)
# check tax calculation # check tax calculation
expected_values = { expected_values = {
@ -131,14 +131,14 @@ class TestSalesInvoice(unittest.TestCase):
for d in si.get("other_charges"): for d in si.get("other_charges"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.doc.grand_total, 1627.05) self.assertEquals(si.grand_total, 1627.05)
self.assertEquals(si.doc.grand_total_export, 32.54) self.assertEquals(si.grand_total_export, 32.54)
def test_sales_invoice_discount_amount(self): def test_sales_invoice_discount_amount(self):
si = frappe.bean(copy=test_records[3]) si = frappe.bean(copy=test_records[3])
si.doc.discount_amount = 104.95 si.discount_amount = 104.95
si.append("other_charges", { si.append("other_charges", {
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"charge_type": "On Previous Row Amount", "charge_type": "On Previous Row Amount",
@ -164,11 +164,11 @@ class TestSalesInvoice(unittest.TestCase):
# check if item values are calculated # check if item values are calculated
for d in si.get("entries"): for d in si.get("entries"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.item_code][i]) self.assertEquals(d.get(k), expected_values[d.item_code][i])
# check net total # check net total
self.assertEquals(si.doc.net_total, 1163.45) self.assertEquals(si.net_total, 1163.45)
self.assertEquals(si.doc.net_total_export, 1578.3) self.assertEquals(si.net_total_export, 1578.3)
# check tax calculation # check tax calculation
expected_values = { expected_values = {
@ -186,14 +186,14 @@ class TestSalesInvoice(unittest.TestCase):
for d in si.get("other_charges"): for d in si.get("other_charges"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.doc.grand_total, 1500) self.assertEquals(si.grand_total, 1500)
self.assertEquals(si.doc.grand_total_export, 1500) self.assertEquals(si.grand_total_export, 1500)
def test_discount_amount_gl_entry(self): def test_discount_amount_gl_entry(self):
si = frappe.bean(copy=test_records[3]) si = frappe.bean(copy=test_records[3])
si.doc.discount_amount = 104.95 si.discount_amount = 104.95
si.append("other_charges", { si.append("other_charges", {
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"charge_type": "On Previous Row Amount", "charge_type": "On Previous Row Amount",
@ -208,12 +208,12 @@ class TestSalesInvoice(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1) order by account asc""", si.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = sorted([ expected_values = sorted([
[si.doc.debit_to, 1500, 0.0], [si.debit_to, 1500, 0.0],
[test_records[3][1]["income_account"], 0.0, 1163.45], [test_records[3][1]["income_account"], 0.0, 1163.45],
[test_records[3][3]["account_head"], 0.0, 130.31], [test_records[3][3]["account_head"], 0.0, 130.31],
[test_records[3][4]["account_head"], 0.0, 2.61], [test_records[3][4]["account_head"], 0.0, 2.61],
@ -235,7 +235,7 @@ class TestSalesInvoice(unittest.TestCase):
si.cancel() si.cancel()
gle = frappe.db.sql("""select * from `tabGL Entry` gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle) self.assertFalse(gle)
@ -275,11 +275,11 @@ class TestSalesInvoice(unittest.TestCase):
# check if item values are calculated # check if item values are calculated
for d in si.get("entries"): for d in si.get("entries"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.item_code][i]) self.assertEquals(d.get(k), expected_values[d.item_code][i])
# check net total # check net total
self.assertEquals(si.doc.net_total, 1249.98) self.assertEquals(si.net_total, 1249.98)
self.assertEquals(si.doc.net_total_export, 1578.3) self.assertEquals(si.net_total_export, 1578.3)
# check tax calculation # check tax calculation
expected_values = { expected_values = {
@ -296,16 +296,16 @@ class TestSalesInvoice(unittest.TestCase):
for d in si.get("other_charges"): for d in si.get("other_charges"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.doc.grand_total, 1622.98) self.assertEquals(si.grand_total, 1622.98)
self.assertEquals(si.doc.grand_total_export, 1622.98) self.assertEquals(si.grand_total_export, 1622.98)
def test_sales_invoice_calculation_export_currency_with_tax_inclusive_price(self): def test_sales_invoice_calculation_export_currency_with_tax_inclusive_price(self):
# prepare # prepare
si = frappe.bean(copy=test_records[3]) si = frappe.bean(copy=test_records[3])
si.doc.currency = "USD" si.currency = "USD"
si.doc.conversion_rate = 50 si.conversion_rate = 50
si.doclist[1].price_list_rate = 55.56 si.doclist[1].price_list_rate = 55.56
si.doclist[1].discount_percentage = 10 si.doclist[1].discount_percentage = 10
si.doclist[2].price_list_rate = 187.5 si.doclist[2].price_list_rate = 187.5
@ -328,11 +328,11 @@ class TestSalesInvoice(unittest.TestCase):
# check if item values are calculated # check if item values are calculated
for d in si.get("entries"): for d in si.get("entries"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.item_code][i]) self.assertEquals(d.get(k), expected_values[d.item_code][i])
# check net total # check net total
self.assertEquals(si.doc.net_total, 49501.7) self.assertEquals(si.net_total, 49501.7)
self.assertEquals(si.doc.net_total_export, 1250) self.assertEquals(si.net_total_export, 1250)
# check tax calculation # check tax calculation
expected_values = { expected_values = {
@ -349,14 +349,14 @@ class TestSalesInvoice(unittest.TestCase):
for d in si.get("other_charges"): for d in si.get("other_charges"):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.doc.grand_total, 65205.16) self.assertEquals(si.grand_total, 65205.16)
self.assertEquals(si.doc.grand_total_export, 1304.1) self.assertEquals(si.grand_total_export, 1304.1)
def test_outstanding(self): def test_outstanding(self):
w = self.make() w = self.make()
self.assertEquals(w.doc.outstanding_amount, w.doc.grand_total) self.assertEquals(w.outstanding_amount, w.grand_total)
def test_payment(self): def test_payment(self):
frappe.db.sql("""delete from `tabGL Entry`""") frappe.db.sql("""delete from `tabGL Entry`""")
@ -366,15 +366,15 @@ class TestSalesInvoice(unittest.TestCase):
import test_records as jv_test_records import test_records as jv_test_records
jv = frappe.bean(frappe.copy_doc(jv_test_records[0])) jv = frappe.bean(frappe.copy_doc(jv_test_records[0]))
jv.doclist[1].against_invoice = w.doc.name jv.doclist[1].against_invoice = w.name
jv.insert() jv.insert()
jv.submit() jv.submit()
self.assertEquals(frappe.db.get_value("Sales Invoice", w.doc.name, "outstanding_amount"), self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"),
161.8) 161.8)
jv.cancel() jv.cancel()
self.assertEquals(frappe.db.get_value("Sales Invoice", w.doc.name, "outstanding_amount"), self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"),
561.8) 561.8)
def test_time_log_batch(self): def test_time_log_batch(self):
@ -409,12 +409,12 @@ class TestSalesInvoice(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1) order by account asc""", si.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = sorted([ expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0], [si.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0], [test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0], [test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0], [test_records[1][3]["account_head"], 0.0, 50.0],
@ -429,7 +429,7 @@ class TestSalesInvoice(unittest.TestCase):
si.cancel() si.cancel()
gle = frappe.db.sql("""select * from `tabGL Entry` gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle) self.assertFalse(gle)
@ -454,7 +454,7 @@ class TestSalesInvoice(unittest.TestCase):
# check stock ledger entries # check stock ledger entries
sle = frappe.db.sql("""select * from `tabStock Ledger Entry` sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
where voucher_type = 'Sales Invoice' and voucher_no = %s""", where voucher_type = 'Sales Invoice' and voucher_no = %s""",
si.doc.name, as_dict=1)[0] si.name, as_dict=1)[0]
self.assertTrue(sle) self.assertTrue(sle)
self.assertEquals([sle.item_code, sle.warehouse, sle.actual_qty], self.assertEquals([sle.item_code, sle.warehouse, sle.actual_qty],
["_Test Item", "_Test Warehouse - _TC", -1.0]) ["_Test Item", "_Test Warehouse - _TC", -1.0])
@ -462,19 +462,19 @@ class TestSalesInvoice(unittest.TestCase):
# check gl entries # check gl entries
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc, debit asc""", si.doc.name, as_dict=1) order by account asc, debit asc""", si.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
stock_in_hand = frappe.db.get_value("Account", {"master_name": "_Test Warehouse - _TC"}) stock_in_hand = frappe.db.get_value("Account", {"master_name": "_Test Warehouse - _TC"})
expected_gl_entries = sorted([ expected_gl_entries = sorted([
[si.doc.debit_to, 630.0, 0.0], [si.debit_to, 630.0, 0.0],
[pos[1]["income_account"], 0.0, 500.0], [pos[1]["income_account"], 0.0, 500.0],
[pos[2]["account_head"], 0.0, 80.0], [pos[2]["account_head"], 0.0, 80.0],
[pos[3]["account_head"], 0.0, 50.0], [pos[3]["account_head"], 0.0, 50.0],
[stock_in_hand, 0.0, 75.0], [stock_in_hand, 0.0, 75.0],
[pos[1]["expense_account"], 75.0, 0.0], [pos[1]["expense_account"], 75.0, 0.0],
[si.doc.debit_to, 0.0, 600.0], [si.debit_to, 0.0, 600.0],
["_Test Account Bank Account - _TC", 600.0, 0.0] ["_Test Account Bank Account - _TC", 600.0, 0.0]
]) ])
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
@ -484,7 +484,7 @@ class TestSalesInvoice(unittest.TestCase):
si.cancel() si.cancel()
gle = frappe.db.sql("""select * from `tabGL Entry` gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle) self.assertFalse(gle)
@ -501,7 +501,7 @@ class TestSalesInvoice(unittest.TestCase):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import test_records \ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
as pr_test_records as pr_test_records
pr = frappe.bean(copy=pr_test_records[0]) pr = frappe.bean(copy=pr_test_records[0])
pr.doc.naming_series = "_T-Purchase Receipt-" pr.naming_series = "_T-Purchase Receipt-"
pr.doclist[1].warehouse = "_Test Warehouse No Account - _TC" pr.doclist[1].warehouse = "_Test Warehouse No Account - _TC"
pr.insert() pr.insert()
pr.submit() pr.submit()
@ -518,7 +518,7 @@ class TestSalesInvoice(unittest.TestCase):
# check stock ledger entries # check stock ledger entries
sle = frappe.db.sql("""select * from `tabStock Ledger Entry` sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
where voucher_type = 'Sales Invoice' and voucher_no = %s""", where voucher_type = 'Sales Invoice' and voucher_no = %s""",
si.doc.name, as_dict=1)[0] si.name, as_dict=1)[0]
self.assertTrue(sle) self.assertTrue(sle)
self.assertEquals([sle.item_code, sle.warehouse, sle.actual_qty], self.assertEquals([sle.item_code, sle.warehouse, sle.actual_qty],
["_Test Item", "_Test Warehouse No Account - _TC", -1.0]) ["_Test Item", "_Test Warehouse No Account - _TC", -1.0])
@ -526,11 +526,11 @@ class TestSalesInvoice(unittest.TestCase):
# check gl entries # check gl entries
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc, debit asc""", si.doc.name, as_dict=1) order by account asc, debit asc""", si.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_gl_entries = sorted([ expected_gl_entries = sorted([
[si.doc.debit_to, 630.0, 0.0], [si.debit_to, 630.0, 0.0],
[si_doclist[1]["income_account"], 0.0, 500.0], [si_doclist[1]["income_account"], 0.0, 500.0],
[si_doclist[2]["account_head"], 0.0, 80.0], [si_doclist[2]["account_head"], 0.0, 80.0],
[si_doclist[3]["account_head"], 0.0, 50.0], [si_doclist[3]["account_head"], 0.0, 50.0],
@ -542,7 +542,7 @@ class TestSalesInvoice(unittest.TestCase):
si.cancel() si.cancel()
gle = frappe.db.sql("""select * from `tabGL Entry` gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle) self.assertFalse(gle)
set_perpetual_inventory(0) set_perpetual_inventory(0)
@ -559,11 +559,11 @@ class TestSalesInvoice(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1) order by account asc""", si.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = sorted([ expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0], [si.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0], [test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0], [test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0], [test_records[1][3]["account_head"], 0.0, 50.0],
@ -586,11 +586,11 @@ class TestSalesInvoice(unittest.TestCase):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1) order by account asc""", si.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = sorted([ expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0], [si.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0], [test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0], [test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0], [test_records[1][3]["account_head"], 0.0, 50.0],
@ -606,7 +606,7 @@ class TestSalesInvoice(unittest.TestCase):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import test_records \ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
as pr_test_records as pr_test_records
pr = frappe.bean(copy=pr_test_records[0]) pr = frappe.bean(copy=pr_test_records[0])
pr.doc.naming_series = "_T-Purchase Receipt-" pr.naming_series = "_T-Purchase Receipt-"
pr.insert() pr.insert()
pr.submit() pr.submit()
@ -614,7 +614,7 @@ class TestSalesInvoice(unittest.TestCase):
from erpnext.stock.doctype.delivery_note.test_delivery_note import test_records \ from erpnext.stock.doctype.delivery_note.test_delivery_note import test_records \
as dn_test_records as dn_test_records
dn = frappe.bean(copy=dn_test_records[0]) dn = frappe.bean(copy=dn_test_records[0])
dn.doc.naming_series = "_T-Delivery Note-" dn.naming_series = "_T-Delivery Note-"
dn.insert() dn.insert()
dn.submit() dn.submit()
return dn return dn
@ -638,35 +638,35 @@ class TestSalesInvoice(unittest.TestCase):
si = frappe.bean(copy=test_records[0]) si = frappe.bean(copy=test_records[0])
si.append("advance_adjustment_details", { si.append("advance_adjustment_details", {
"doctype": "Sales Invoice Advance", "doctype": "Sales Invoice Advance",
"journal_voucher": jv.doc.name, "journal_voucher": jv.name,
"jv_detail_no": jv.doclist[1].name, "jv_detail_no": jv.doclist[1].name,
"advance_amount": 400, "advance_amount": 400,
"allocated_amount": 300, "allocated_amount": 300,
"remarks": jv.doc.remark "remarks": jv.remark
}) })
si.insert() si.insert()
si.submit() si.submit()
si.load_from_db() si.load_from_db()
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_invoice=%s""", si.doc.name)) where against_invoice=%s""", si.name))
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_invoice=%s and credit=300""", si.doc.name)) where against_invoice=%s and credit=300""", si.name))
self.assertEqual(si.doc.outstanding_amount, 261.8) self.assertEqual(si.outstanding_amount, 261.8)
si.cancel() si.cancel()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail` self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_invoice=%s""", si.doc.name)) where against_invoice=%s""", si.name))
def test_recurring_invoice(self): def test_recurring_invoice(self):
from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year
today = nowdate() today = nowdate()
base_si = frappe.bean(copy=test_records[0]) base_si = frappe.bean(copy=test_records[0])
base_si.doc.fields.update({ base_si.update({
"convert_into_recurring_invoice": 1, "convert_into_recurring_invoice": 1,
"recurring_type": "Monthly", "recurring_type": "Monthly",
"notification_email_address": "test@example.com, test1@example.com, test2@example.com", "notification_email_address": "test@example.com, test1@example.com, test2@example.com",
@ -685,7 +685,7 @@ class TestSalesInvoice(unittest.TestCase):
# monthly without a first and last day period # monthly without a first and last day period
si2 = frappe.bean(copy=base_si.doclist) si2 = frappe.bean(copy=base_si.doclist)
si2.doc.fields.update({ si2.update({
"invoice_period_from_date": today, "invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, days=30) "invoice_period_to_date": add_to_date(today, days=30)
}) })
@ -695,7 +695,7 @@ class TestSalesInvoice(unittest.TestCase):
# quarterly # quarterly
si3 = frappe.bean(copy=base_si.doclist) si3 = frappe.bean(copy=base_si.doclist)
si3.doc.fields.update({ si3.update({
"recurring_type": "Quarterly", "recurring_type": "Quarterly",
"invoice_period_from_date": get_first_day(today), "invoice_period_from_date": get_first_day(today),
"invoice_period_to_date": get_last_day(add_to_date(today, months=3)) "invoice_period_to_date": get_last_day(add_to_date(today, months=3))
@ -706,7 +706,7 @@ class TestSalesInvoice(unittest.TestCase):
# quarterly without a first and last day period # quarterly without a first and last day period
si4 = frappe.bean(copy=base_si.doclist) si4 = frappe.bean(copy=base_si.doclist)
si4.doc.fields.update({ si4.update({
"recurring_type": "Quarterly", "recurring_type": "Quarterly",
"invoice_period_from_date": today, "invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, months=3) "invoice_period_to_date": add_to_date(today, months=3)
@ -717,7 +717,7 @@ class TestSalesInvoice(unittest.TestCase):
# yearly # yearly
si5 = frappe.bean(copy=base_si.doclist) si5 = frappe.bean(copy=base_si.doclist)
si5.doc.fields.update({ si5.update({
"recurring_type": "Yearly", "recurring_type": "Yearly",
"invoice_period_from_date": get_first_day(today), "invoice_period_from_date": get_first_day(today),
"invoice_period_to_date": get_last_day(add_to_date(today, years=1)) "invoice_period_to_date": get_last_day(add_to_date(today, years=1))
@ -728,7 +728,7 @@ class TestSalesInvoice(unittest.TestCase):
# yearly without a first and last day period # yearly without a first and last day period
si6 = frappe.bean(copy=base_si.doclist) si6 = frappe.bean(copy=base_si.doclist)
si6.doc.fields.update({ si6.update({
"recurring_type": "Yearly", "recurring_type": "Yearly",
"invoice_period_from_date": today, "invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, years=1) "invoice_period_to_date": add_to_date(today, years=1)
@ -739,14 +739,14 @@ class TestSalesInvoice(unittest.TestCase):
# change posting date but keep recuring day to be today # change posting date but keep recuring day to be today
si7 = frappe.bean(copy=base_si.doclist) si7 = frappe.bean(copy=base_si.doclist)
si7.doc.fields.update({ si7.update({
"posting_date": add_to_date(today, days=-1) "posting_date": add_to_date(today, days=-1)
}) })
si7.insert() si7.insert()
si7.submit() si7.submit()
# setting so that _test function works # setting so that _test function works
si7.doc.posting_date = today si7.posting_date = today
self._test_recurring_invoice(si7, True) self._test_recurring_invoice(si7, True)
def _test_recurring_invoice(self, base_si, first_and_last_day): def _test_recurring_invoice(self, base_si, first_and_last_day):
@ -754,20 +754,20 @@ class TestSalesInvoice(unittest.TestCase):
from erpnext.accounts.doctype.sales_invoice.sales_invoice \ from erpnext.accounts.doctype.sales_invoice.sales_invoice \
import manage_recurring_invoices, get_next_date import manage_recurring_invoices, get_next_date
no_of_months = ({"Monthly": 1, "Quarterly": 3, "Yearly": 12})[base_si.doc.recurring_type] no_of_months = ({"Monthly": 1, "Quarterly": 3, "Yearly": 12})[base_si.recurring_type]
def _test(i): def _test(i):
self.assertEquals(i+1, frappe.db.sql("""select count(*) from `tabSales Invoice` self.assertEquals(i+1, frappe.db.sql("""select count(*) from `tabSales Invoice`
where recurring_id=%s and docstatus=1""", base_si.doc.recurring_id)[0][0]) where recurring_id=%s and docstatus=1""", base_si.recurring_id)[0][0])
next_date = get_next_date(base_si.doc.posting_date, no_of_months, next_date = get_next_date(base_si.posting_date, no_of_months,
base_si.doc.repeat_on_day_of_month) base_si.repeat_on_day_of_month)
manage_recurring_invoices(next_date=next_date, commit=False) manage_recurring_invoices(next_date=next_date, commit=False)
recurred_invoices = frappe.db.sql("""select name from `tabSales Invoice` recurred_invoices = frappe.db.sql("""select name from `tabSales Invoice`
where recurring_id=%s and docstatus=1 order by name desc""", where recurring_id=%s and docstatus=1 order by name desc""",
base_si.doc.recurring_id) base_si.recurring_id)
self.assertEquals(i+2, len(recurred_invoices)) self.assertEquals(i+2, len(recurred_invoices))
@ -775,21 +775,21 @@ class TestSalesInvoice(unittest.TestCase):
for fieldname in ["convert_into_recurring_invoice", "recurring_type", for fieldname in ["convert_into_recurring_invoice", "recurring_type",
"repeat_on_day_of_month", "notification_email_address"]: "repeat_on_day_of_month", "notification_email_address"]:
self.assertEquals(base_si.doc.fields.get(fieldname), self.assertEquals(base_si.get(fieldname),
new_si.doc.fields.get(fieldname)) new_si.get(fieldname))
self.assertEquals(new_si.doc.posting_date, unicode(next_date)) self.assertEquals(new_si.posting_date, unicode(next_date))
self.assertEquals(new_si.doc.invoice_period_from_date, self.assertEquals(new_si.invoice_period_from_date,
unicode(add_months(base_si.doc.invoice_period_from_date, no_of_months))) unicode(add_months(base_si.invoice_period_from_date, no_of_months)))
if first_and_last_day: if first_and_last_day:
self.assertEquals(new_si.doc.invoice_period_to_date, self.assertEquals(new_si.invoice_period_to_date,
unicode(get_last_day(add_months(base_si.doc.invoice_period_to_date, unicode(get_last_day(add_months(base_si.invoice_period_to_date,
no_of_months)))) no_of_months))))
else: else:
self.assertEquals(new_si.doc.invoice_period_to_date, self.assertEquals(new_si.invoice_period_to_date,
unicode(add_months(base_si.doc.invoice_period_to_date, no_of_months))) unicode(add_months(base_si.invoice_period_to_date, no_of_months)))
return new_si return new_si
@ -812,7 +812,7 @@ class TestSalesInvoice(unittest.TestCase):
serial_nos = get_serial_nos(se.doclist[1].serial_no) serial_nos = get_serial_nos(se.doclist[1].serial_no)
si = frappe.bean(copy=test_records[0]) si = frappe.bean(copy=test_records[0])
si.doc.update_stock = 1 si.update_stock = 1
si.doclist[1].item_code = "_Test Serialized Item With Series" si.doclist[1].item_code = "_Test Serialized Item With Series"
si.doclist[1].qty = 1 si.doclist[1].qty = 1
si.doclist[1].serial_no = serial_nos[0] si.doclist[1].serial_no = serial_nos[0]
@ -822,7 +822,7 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Delivered") self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Delivered")
self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "warehouse")) self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"))
self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0],
"delivery_document_no"), si.doc.name) "delivery_document_no"), si.name)
return si return si
@ -846,11 +846,11 @@ class TestSalesInvoice(unittest.TestCase):
serial_nos = get_serial_nos(se.doclist[1].serial_no) serial_nos = get_serial_nos(se.doclist[1].serial_no)
sr = frappe.bean("Serial No", serial_nos[0]) sr = frappe.bean("Serial No", serial_nos[0])
sr.doc.status = "Not Available" sr.status = "Not Available"
sr.save() sr.save()
si = frappe.bean(copy=test_records[0]) si = frappe.bean(copy=test_records[0])
si.doc.update_stock = 1 si.update_stock = 1
si.doclist[1].item_code = "_Test Serialized Item With Series" si.doclist[1].item_code = "_Test Serialized Item With Series"
si.doclist[1].qty = 1 si.doclist[1].qty = 1
si.doclist[1].serial_no = serial_nos[0] si.doclist[1].serial_no = serial_nos[0]

View File

@ -8,10 +8,10 @@ from frappe.model.controller import DocListController
class SalesTaxesAndChargesMaster(DocListController): class SalesTaxesAndChargesMaster(DocListController):
def validate(self): def validate(self):
if self.doc.is_default == 1: if self.is_default == 1:
frappe.db.sql("""update `tabSales Taxes and Charges Master` set is_default = 0 frappe.db.sql("""update `tabSales Taxes and Charges Master` set is_default = 0
where ifnull(is_default,0) = 1 and name != %s and company = %s""", where ifnull(is_default,0) = 1 and name != %s and company = %s""",
(self.doc.name, self.doc.company)) (self.name, self.company))
# at least one territory # at least one territory
self.validate_table_has_rows("valid_for_territories") self.validate_table_has_rows("valid_for_territories")

View File

@ -74,7 +74,7 @@ class ShippingRule(DocListController):
overlaps.append([d1, d2]) overlaps.append([d1, d2])
if overlaps: if overlaps:
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
msgprint(_("Error") + ": " + _("Overlapping Conditions found between") + ":") msgprint(_("Error") + ": " + _("Overlapping Conditions found between") + ":")
messages = [] messages = []
for d1, d2 in overlaps: for d1, d2 in overlaps:

View File

@ -178,4 +178,4 @@ def create_party_account(party, party_type, company):
"report_type": "Balance Sheet" "report_type": "Balance Sheet"
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True)
frappe.msgprint(_("Account Created") + ": " + account.doc.name) frappe.msgprint(_("Account Created") + ": " + account.name)

View File

@ -104,11 +104,11 @@ def add_ac(args=None):
args.pop("cmd") args.pop("cmd")
ac = frappe.bean(args) ac = frappe.bean(args)
ac.doc.doctype = "Account" ac.doctype = "Account"
ac.doc.old_parent = "" ac.old_parent = ""
ac.doc.freeze_account = "No" ac.freeze_account = "No"
ac.insert() ac.insert()
return ac.doc.name return ac.name
@frappe.whitelist() @frappe.whitelist()
def add_cc(args=None): def add_cc(args=None):
@ -117,10 +117,10 @@ def add_cc(args=None):
args.pop("cmd") args.pop("cmd")
cc = frappe.bean(args) cc = frappe.bean(args)
cc.doc.doctype = "Cost Center" cc.doctype = "Cost Center"
cc.doc.old_parent = "" cc.old_parent = ""
cc.insert() cc.insert()
return cc.doc.name return cc.name
def reconcile_against_document(args): def reconcile_against_document(args):
""" """
@ -185,8 +185,8 @@ def update_against_doc(d, jv_obj):
ch.account = d['account'] ch.account = d['account']
ch.cost_center = cstr(jvd[0][0]) ch.cost_center = cstr(jvd[0][0])
ch.balance = cstr(jvd[0][1]) ch.balance = cstr(jvd[0][1])
ch.fields[d['dr_or_cr']] = flt(d['unadjusted_amt']) - flt(d['allocated_amt']) ch.set(d['dr_or_cr'], flt(d['unadjusted_amt']) - flt(d['allocated_amt']))
ch.fields[d['dr_or_cr']== 'debit' and 'credit' or 'debit'] = 0 ch.set(d['dr_or_cr']== 'debit' and 'credit' or 'debit', 0)
ch.against_account = cstr(jvd[0][2]) ch.against_account = cstr(jvd[0][2])
ch.is_advance = cstr(jvd[0][3]) ch.is_advance = cstr(jvd[0][3])
ch.docstatus = 1 ch.docstatus = 1

View File

@ -12,8 +12,8 @@ class BuyingSettings(Document):
def validate(self): def validate(self):
for key in ["supplier_type", "supp_master_name", "maintain_same_rate", "buying_price_list"]: for key in ["supplier_type", "supp_master_name", "maintain_same_rate", "buying_price_list"]:
frappe.db.set_default(key, self.doc.fields.get(key, "")) frappe.db.set_default(key, self.get(key, ""))
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
set_by_naming_series("Supplier", "supplier_name", set_by_naming_series("Supplier", "supplier_name",
self.doc.get("supp_master_name")=="Naming Series", hide_name_field=False) self.get("supp_master_name")=="Naming Series", hide_name_field=False)

View File

@ -17,11 +17,11 @@ class PurchaseCommon(BuyingController):
"""updates last_purchase_rate in item table for each item""" """updates last_purchase_rate in item table for each item"""
import frappe.utils import frappe.utils
this_purchase_date = frappe.utils.getdate(obj.doc.fields.get('posting_date') or obj.doc.fields.get('transaction_date')) this_purchase_date = frappe.utils.getdate(obj.get('posting_date') or obj.get('transaction_date'))
for d in getlist(obj.doclist,obj.fname): for d in getlist(obj.doclist,obj.fname):
# get last purchase details # get last purchase details
last_purchase_details = get_last_purchase_details(d.item_code, obj.doc.name) last_purchase_details = get_last_purchase_details(d.item_code, obj.name)
# compare last purchase date and this transaction's date # compare last purchase date and this transaction's date
last_purchase_rate = None last_purchase_rate = None
@ -44,8 +44,8 @@ class PurchaseCommon(BuyingController):
def get_last_purchase_rate(self, obj): def get_last_purchase_rate(self, obj):
"""get last purchase rates for all items""" """get last purchase rates for all items"""
doc_name = obj.doc.name doc_name = obj.name
conversion_rate = flt(obj.doc.fields.get('conversion_rate')) or 1.0 conversion_rate = flt(obj.get('conversion_rate')) or 1.0
for d in getlist(obj.doclist, obj.fname): for d in getlist(obj.doclist, obj.fname):
if d.item_code: if d.item_code:
@ -83,7 +83,7 @@ class PurchaseCommon(BuyingController):
f_lst.pop('received_qty') f_lst.pop('received_qty')
for x in f_lst : for x in f_lst :
if d.fields.has_key(x): if d.fields.has_key(x):
d.fields[x] = f_lst[x] d.set(x, f_lst[x])
item = frappe.db.sql("""select is_stock_item, is_purchase_item, item = frappe.db.sql("""select is_stock_item, is_purchase_item,
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""", d.item_code) is_sub_contracted_item, end_of_life from `tabItem` where name=%s""", d.item_code)

View File

@ -29,11 +29,11 @@ class PurchaseOrder(BuyingController):
def validate(self): def validate(self):
super(DocType, self).validate() super(DocType, self).validate()
if not self.doc.status: if not self.status:
self.doc.status = "Draft" self.status = "Draft"
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", validate_status(self.status, ["Draft", "Submitted", "Stopped",
"Cancelled"]) "Cancelled"])
pc_obj = get_obj(dt='Purchase Common') pc_obj = get_obj(dt='Purchase Common')
@ -99,7 +99,7 @@ class PurchaseOrder(BuyingController):
# get qty and pending_qty of prevdoc # get qty and pending_qty of prevdoc
curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname', curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname',
d.prevdoc_detail_docname, 'Material Request Item', d.prevdoc_detail_docname, 'Material Request Item',
'Material Request - Purchase Order', self.doc.name) 'Material Request - Purchase Order', self.name)
max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \ max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \
flt(curr_ref_qty.split('~~~')[0]), 0 flt(curr_ref_qty.split('~~~')[0]), 0
@ -119,17 +119,17 @@ class PurchaseOrder(BuyingController):
"warehouse": d.warehouse, "warehouse": d.warehouse,
"ordered_qty": (is_submit and 1 or -1) * flt(po_qty), "ordered_qty": (is_submit and 1 or -1) * flt(po_qty),
"indented_qty": (is_submit and 1 or -1) * flt(ind_qty), "indented_qty": (is_submit and 1 or -1) * flt(ind_qty),
"posting_date": self.doc.transaction_date "posting_date": self.transaction_date
} }
update_bin(args) update_bin(args)
def check_modified_date(self): def check_modified_date(self):
mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s", mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s",
self.doc.name) self.name)
date_diff = frappe.db.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified))) date_diff = frappe.db.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.modified)))
if date_diff and date_diff[0][0]: if date_diff and date_diff[0][0]:
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ") msgprint(cstr(self.doctype) +" => "+ cstr(self.name) +" has been modified. Please Refresh. ")
raise Exception raise Exception
def update_status(self, status): def update_status(self, status):
@ -141,7 +141,7 @@ class PurchaseOrder(BuyingController):
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1) self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
# step 3:=> Acknowledge user # step 3:=> Acknowledge user
msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status))) msgprint(self.doctype + ": " + self.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
def on_submit(self): def on_submit(self):
purchase_controller = frappe.get_obj("Purchase Common") purchase_controller = frappe.get_obj("Purchase Common")
@ -149,8 +149,8 @@ class PurchaseOrder(BuyingController):
self.update_prevdoc_status() self.update_prevdoc_status()
self.update_bin(is_submit = 1, is_stopped = 0) self.update_bin(is_submit = 1, is_stopped = 0)
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, get_obj('Authorization Control').validate_approving_authority(self.doctype,
self.doc.company, self.doc.grand_total) self.company, self.grand_total)
purchase_controller.update_last_purchase_rate(self, is_submit = 1) purchase_controller.update_last_purchase_rate(self, is_submit = 1)
@ -161,13 +161,13 @@ class PurchaseOrder(BuyingController):
self.check_for_stopped_status(pc_obj) self.check_for_stopped_status(pc_obj)
# Check if Purchase Receipt has been submitted against current Purchase Order # Check if Purchase Receipt has been submitted against current Purchase Order
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.doc.name, detail_doctype = 'Purchase Receipt Item') pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.name, detail_doctype = 'Purchase Receipt Item')
# Check if Purchase Invoice has been submitted against current Purchase Order # Check if Purchase Invoice has been submitted against current Purchase Order
submitted = frappe.db.sql("""select t1.name submitted = frappe.db.sql("""select t1.name
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2
where t1.name = t2.parent and t2.purchase_order = %s and t1.docstatus = 1""", where t1.name = t2.parent and t2.purchase_order = %s and t1.docstatus = 1""",
self.doc.name) self.name)
if submitted: if submitted:
msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !") msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
raise Exception raise Exception

View File

@ -14,12 +14,12 @@ class TestPurchaseOrder(unittest.TestCase):
po = frappe.bean(copy=test_records[0]).insert() po = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_purchase_receipt, self.assertRaises(frappe.ValidationError, make_purchase_receipt,
po.doc.name) po.name)
po = frappe.bean("Purchase Order", po.doc.name) po = frappe.bean("Purchase Order", po.name)
po.submit() po.submit()
pr = make_purchase_receipt(po.doc.name) pr = make_purchase_receipt(po.name)
pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC" pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC"
pr[0]["posting_date"] = "2013-05-12" pr[0]["posting_date"] = "2013-05-12"
self.assertEquals(pr[0]["doctype"], "Purchase Receipt") self.assertEquals(pr[0]["doctype"], "Purchase Receipt")
@ -37,17 +37,17 @@ class TestPurchaseOrder(unittest.TestCase):
po = frappe.bean(copy=test_records[0]).insert() po = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_purchase_receipt, self.assertRaises(frappe.ValidationError, make_purchase_receipt,
po.doc.name) po.name)
po = frappe.bean("Purchase Order", po.doc.name) po = frappe.bean("Purchase Order", po.name)
po.doc.is_subcontracted = "No" po.is_subcontracted = "No"
po.doclist[1].item_code = "_Test Item" po.doclist[1].item_code = "_Test Item"
po.submit() po.submit()
self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item", self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10) "warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10)
pr = make_purchase_receipt(po.doc.name) pr = make_purchase_receipt(po.name)
self.assertEquals(pr[0]["doctype"], "Purchase Receipt") self.assertEquals(pr[0]["doctype"], "Purchase Receipt")
self.assertEquals(len(pr), len(test_records[0])) self.assertEquals(len(pr), len(test_records[0]))
@ -63,7 +63,7 @@ class TestPurchaseOrder(unittest.TestCase):
frappe.db.set_value('Item', '_Test Item', 'tolerance', 50) frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
pr1 = make_purchase_receipt(po.doc.name) pr1 = make_purchase_receipt(po.name)
pr1[0]["naming_series"] = "_T-Purchase Receipt-" pr1[0]["naming_series"] = "_T-Purchase Receipt-"
pr1[0]["posting_date"] = "2013-05-12" pr1[0]["posting_date"] = "2013-05-12"
pr1[1]["qty"] = 8 pr1[1]["qty"] = 8
@ -80,11 +80,11 @@ class TestPurchaseOrder(unittest.TestCase):
po = frappe.bean(copy=test_records[0]).insert() po = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_purchase_invoice, self.assertRaises(frappe.ValidationError, make_purchase_invoice,
po.doc.name) po.name)
po = frappe.bean("Purchase Order", po.doc.name) po = frappe.bean("Purchase Order", po.name)
po.submit() po.submit()
pi = make_purchase_invoice(po.doc.name) pi = make_purchase_invoice(po.name)
self.assertEquals(pi[0]["doctype"], "Purchase Invoice") self.assertEquals(pi[0]["doctype"], "Purchase Invoice")
self.assertEquals(len(pi), len(test_records[0])) self.assertEquals(len(pi), len(test_records[0]))
@ -100,8 +100,8 @@ class TestPurchaseOrder(unittest.TestCase):
def test_warehouse_company_validation(self): def test_warehouse_company_validation(self):
from erpnext.stock.utils import InvalidWarehouseCompany from erpnext.stock.utils import InvalidWarehouseCompany
po = frappe.bean(copy=test_records[0]) po = frappe.bean(copy=test_records[0])
po.doc.company = "_Test Company 1" po.company = "_Test Company 1"
po.doc.conversion_rate = 0.0167 po.conversion_rate = 0.0167
self.assertRaises(InvalidWarehouseCompany, po.insert) self.assertRaises(InvalidWarehouseCompany, po.insert)
def test_uom_integer_validation(self): def test_uom_integer_validation(self):

View File

@ -12,28 +12,28 @@ class QualityInspection(Document):
def get_item_specification_details(self): def get_item_specification_details(self):
self.set('qa_specification_details', []) self.set('qa_specification_details', [])
specification = frappe.db.sql("select specification, value from `tabItem Quality Inspection Parameter` \ specification = frappe.db.sql("select specification, value from `tabItem Quality Inspection Parameter` \
where parent = '%s' order by idx" % (self.doc.item_code)) where parent = '%s' order by idx" % (self.item_code))
for d in specification: for d in specification:
child = self.doc.append('qa_specification_details', {}) child = self.append('qa_specification_details', {})
child.specification = d[0] child.specification = d[0]
child.value = d[1] child.value = d[1]
child.status = 'Accepted' child.status = 'Accepted'
def on_submit(self): def on_submit(self):
if self.doc.purchase_receipt_no: if self.purchase_receipt_no:
frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2 frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2
set t1.qa_no = %s, t2.modified = %s set t1.qa_no = %s, t2.modified = %s
where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""", where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""",
(self.doc.name, self.doc.modified, self.doc.purchase_receipt_no, (self.name, self.modified, self.purchase_receipt_no,
self.doc.item_code)) self.item_code))
def on_cancel(self): def on_cancel(self):
if self.doc.purchase_receipt_no: if self.purchase_receipt_no:
frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2 frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2
set t1.qa_no = '', t2.modified = %s set t1.qa_no = '', t2.modified = %s
where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""", where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""",
(self.doc.modified, self.doc.purchase_receipt_no, self.doc.item_code)) (self.modified, self.purchase_receipt_no, self.item_code))
def item_query(doctype, txt, searchfield, start, page_len, filters): def item_query(doctype, txt, searchfield, start, page_len, filters):

View File

@ -18,44 +18,44 @@ class Supplier(TransactionBase):
supp_master_name = frappe.defaults.get_global_default('supp_master_name') supp_master_name = frappe.defaults.get_global_default('supp_master_name')
if supp_master_name == 'Supplier Name': if supp_master_name == 'Supplier Name':
if frappe.db.exists("Customer", self.doc.supplier_name): if frappe.db.exists("Customer", self.supplier_name):
frappe.msgprint(_("A Customer exists with same name"), raise_exception=1) frappe.msgprint(_("A Customer exists with same name"), raise_exception=1)
self.doc.name = self.doc.supplier_name self.name = self.supplier_name
else: else:
self.doc.name = make_autoname(self.doc.naming_series + '.#####') self.name = make_autoname(self.naming_series + '.#####')
def update_address(self): def update_address(self):
frappe.db.sql("""update `tabAddress` set supplier_name=%s, modified=NOW() frappe.db.sql("""update `tabAddress` set supplier_name=%s, modified=NOW()
where supplier=%s""", (self.doc.supplier_name, self.doc.name)) where supplier=%s""", (self.supplier_name, self.name))
def update_contact(self): def update_contact(self):
frappe.db.sql("""update `tabContact` set supplier_name=%s, modified=NOW() frappe.db.sql("""update `tabContact` set supplier_name=%s, modified=NOW()
where supplier=%s""", (self.doc.supplier_name, self.doc.name)) where supplier=%s""", (self.supplier_name, self.name))
def update_credit_days_limit(self): def update_credit_days_limit(self):
frappe.db.sql("""update tabAccount set credit_days = %s where name = %s""", frappe.db.sql("""update tabAccount set credit_days = %s where name = %s""",
(cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr())) (cint(self.credit_days), self.name + " - " + self.get_company_abbr()))
def on_update(self): def on_update(self):
if not self.doc.naming_series: if not self.naming_series:
self.doc.naming_series = '' self.naming_series = ''
self.update_address() self.update_address()
self.update_contact() self.update_contact()
# create account head # create account head
create_party_account(self.doc.name, "Supplier", self.doc.company) create_party_account(self.name, "Supplier", self.company)
# update credit days and limit in account # update credit days and limit in account
self.update_credit_days_limit() self.update_credit_days_limit()
def get_company_abbr(self): def get_company_abbr(self):
return frappe.db.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
def validate(self): def validate(self):
#validation for Naming Series mandatory field... #validation for Naming Series mandatory field...
if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series': if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series':
if not self.doc.naming_series: if not self.naming_series:
msgprint("Series is Mandatory.", raise_exception=1) msgprint("Series is Mandatory.", raise_exception=1)
def get_contacts(self,nm): def get_contacts(self,nm):
@ -67,18 +67,18 @@ class Supplier(TransactionBase):
return '' return ''
def delete_supplier_address(self): def delete_supplier_address(self):
for rec in frappe.db.sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1): for rec in frappe.db.sql("select * from `tabAddress` where supplier=%s", (self.name,), as_dict=1):
frappe.db.sql("delete from `tabAddress` where name=%s",(rec['name'])) frappe.db.sql("delete from `tabAddress` where name=%s",(rec['name']))
def delete_supplier_contact(self): def delete_supplier_contact(self):
for contact in frappe.db.sql_list("""select name from `tabContact` for contact in frappe.db.sql_list("""select name from `tabContact`
where supplier=%s""", self.doc.name): where supplier=%s""", self.name):
frappe.delete_doc("Contact", contact) frappe.delete_doc("Contact", contact)
def delete_supplier_account(self): def delete_supplier_account(self):
"""delete supplier's ledger if exist and check balance before deletion""" """delete supplier's ledger if exist and check balance before deletion"""
acc = frappe.db.sql("select name from `tabAccount` where master_type = 'Supplier' \ acc = frappe.db.sql("select name from `tabAccount` where master_type = 'Supplier' \
and master_name = %s and docstatus < 2", self.doc.name) and master_name = %s and docstatus < 2", self.name)
if acc: if acc:
frappe.delete_doc('Account', acc[0][0]) frappe.delete_doc('Account', acc[0][0])
@ -89,7 +89,7 @@ class Supplier(TransactionBase):
def before_rename(self, olddn, newdn, merge=False): def before_rename(self, olddn, newdn, merge=False):
from erpnext.accounts.utils import rename_account_for from erpnext.accounts.utils import rename_account_for
rename_account_for("Supplier", olddn, newdn, merge, self.doc.company) rename_account_for("Supplier", olddn, newdn, merge, self.company)
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
set_field = '' set_field = ''

View File

@ -14,11 +14,11 @@ class SupplierQuotation(BuyingController):
def validate(self): def validate(self):
super(DocType, self).validate() super(DocType, self).validate()
if not self.doc.status: if not self.status:
self.doc.status = "Draft" self.status = "Draft"
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", validate_status(self.status, ["Draft", "Submitted", "Stopped",
"Cancelled"]) "Cancelled"])
self.validate_common() self.validate_common()

View File

@ -14,11 +14,11 @@ class TestPurchaseOrder(unittest.TestCase):
sq = frappe.bean(copy=test_records[0]).insert() sq = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_purchase_order, self.assertRaises(frappe.ValidationError, make_purchase_order,
sq.doc.name) sq.name)
sq = frappe.bean("Supplier Quotation", sq.doc.name) sq = frappe.bean("Supplier Quotation", sq.name)
sq.submit() sq.submit()
po = make_purchase_order(sq.doc.name) po = make_purchase_order(sq.name)
self.assertEquals(po[0]["doctype"], "Purchase Order") self.assertEquals(po[0]["doctype"], "Purchase Order")
self.assertEquals(len(po), len(sq.doclist)) self.assertEquals(len(po), len(sq.doclist))

View File

@ -24,10 +24,10 @@ class AccountsController(TransactionBase):
def set_missing_values(self, for_validate=False): def set_missing_values(self, for_validate=False):
for fieldname in ["posting_date", "transaction_date"]: for fieldname in ["posting_date", "transaction_date"]:
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname): if not self.get(fieldname) and self.meta.get_field(fieldname):
self.doc.fields[fieldname] = today() self.set(fieldname, today())
if not self.doc.fiscal_year: if not self.fiscal_year:
self.doc.fiscal_year = get_fiscal_year(self.doc.fields[fieldname])[0] self.fiscal_year = get_fiscal_year(self.fields[fieldname])[0]
def validate_date_with_fiscal_year(self): def validate_date_with_fiscal_year(self):
if self.meta.get_field("fiscal_year") : if self.meta.get_field("fiscal_year") :
@ -37,16 +37,16 @@ class AccountsController(TransactionBase):
elif self.meta.get_field("transaction_date"): elif self.meta.get_field("transaction_date"):
date_field = "transaction_date" date_field = "transaction_date"
if date_field and self.doc.fields[date_field]: if date_field and self.fields[date_field]:
validate_fiscal_year(self.doc.fields[date_field], self.doc.fiscal_year, validate_fiscal_year(self.fields[date_field], self.fiscal_year,
label=self.meta.get_label(date_field)) label=self.meta.get_label(date_field))
def validate_for_freezed_account(self): def validate_for_freezed_account(self):
for fieldname in ["customer", "supplier"]: for fieldname in ["customer", "supplier"]:
if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname): if self.meta.get_field(fieldname) and self.get(fieldname):
accounts = frappe.db.get_values("Account", accounts = frappe.db.get_values("Account",
{"master_type": fieldname.title(), "master_name": self.doc.fields[fieldname], {"master_type": fieldname.title(), "master_name": self.fields[fieldname],
"company": self.doc.company}, "name") "company": self.company}, "name")
if accounts: if accounts:
from erpnext.accounts.doctype.gl_entry.gl_entry import validate_frozen_account from erpnext.accounts.doctype.gl_entry.gl_entry import validate_frozen_account
for account in accounts: for account in accounts:
@ -54,30 +54,30 @@ class AccountsController(TransactionBase):
def set_price_list_currency(self, buying_or_selling): def set_price_list_currency(self, buying_or_selling):
if self.meta.get_field("currency"): if self.meta.get_field("currency"):
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
# price list part # price list part
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \ fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
else "buying_price_list" else "buying_price_list"
if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname): if self.meta.get_field(fieldname) and self.get(fieldname):
self.doc.price_list_currency = frappe.db.get_value("Price List", self.price_list_currency = frappe.db.get_value("Price List",
self.doc.fields.get(fieldname), "currency") self.get(fieldname), "currency")
if self.doc.price_list_currency == company_currency: if self.price_list_currency == company_currency:
self.doc.plc_conversion_rate = 1.0 self.plc_conversion_rate = 1.0
elif not self.doc.plc_conversion_rate: elif not self.plc_conversion_rate:
self.doc.plc_conversion_rate = self.get_exchange_rate( self.plc_conversion_rate = self.get_exchange_rate(
self.doc.price_list_currency, company_currency) self.price_list_currency, company_currency)
# currency # currency
if not self.doc.currency: if not self.currency:
self.doc.currency = self.doc.price_list_currency self.currency = self.price_list_currency
self.doc.conversion_rate = self.doc.plc_conversion_rate self.conversion_rate = self.plc_conversion_rate
elif self.doc.currency == company_currency: elif self.currency == company_currency:
self.doc.conversion_rate = 1.0 self.conversion_rate = 1.0
elif not self.doc.conversion_rate: elif not self.conversion_rate:
self.doc.conversion_rate = self.get_exchange_rate(self.doc.currency, self.conversion_rate = self.get_exchange_rate(self.currency,
company_currency) company_currency)
def get_exchange_rate(self, from_currency, to_currency): def get_exchange_rate(self, from_currency, to_currency):
@ -88,14 +88,14 @@ class AccountsController(TransactionBase):
"""set missing item values""" """set missing item values"""
from erpnext.stock.get_item_details import get_item_details from erpnext.stock.get_item_details import get_item_details
for item in self.get(self.fname): for item in self.get(self.fname):
if item.fields.get("item_code"): if item.get("item_code"):
args = item.fields.copy() args = item.fields.copy()
args.update(self.doc.fields) args.update(self.fields)
ret = get_item_details(args) ret = get_item_details(args)
for fieldname, value in ret.items(): for fieldname, value in ret.items():
if self.meta.get_field(fieldname, parentfield=self.fname) and \ if self.meta.get_field(fieldname, parentfield=self.fname) and \
item.fields.get(fieldname) is None and value is not None: item.get(fieldname) is None and value is not None:
item.fields[fieldname] = value item.set(fieldname, value)
def set_taxes(self, tax_parentfield, tax_master_field): def set_taxes(self, tax_parentfield, tax_master_field):
if not self.meta.get_field(tax_parentfield): if not self.meta.get_field(tax_parentfield):
@ -104,22 +104,21 @@ class AccountsController(TransactionBase):
tax_master_doctype = self.meta.get_field(tax_master_field).options tax_master_doctype = self.meta.get_field(tax_master_field).options
if not self.get(tax_parentfield): if not self.get(tax_parentfield):
if not self.doc.fields.get(tax_master_field): if not self.get(tax_master_field):
# get the default tax master # get the default tax master
self.doc.fields[tax_master_field] = \ self.set(tax_master_field, frappe.db.get_value(tax_master_doctype, {"is_default": 1}))
frappe.db.get_value(tax_master_doctype, {"is_default": 1})
self.append_taxes_from_master(tax_parentfield, tax_master_field, tax_master_doctype) self.append_taxes_from_master(tax_parentfield, tax_master_field, tax_master_doctype)
def append_taxes_from_master(self, tax_parentfield, tax_master_field, tax_master_doctype=None): def append_taxes_from_master(self, tax_parentfield, tax_master_field, tax_master_doctype=None):
if self.doc.fields.get(tax_master_field): if self.get(tax_master_field):
if not tax_master_doctype: if not tax_master_doctype:
tax_master_doctype = self.meta.get_field(tax_master_field).options tax_master_doctype = self.meta.get_field(tax_master_field).options
tax_doctype = self.meta.get_field(tax_parentfield).options tax_doctype = self.meta.get_field(tax_parentfield).options
from frappe.model import default_fields from frappe.model import default_fields
tax_master = frappe.bean(tax_master_doctype, self.doc.fields.get(tax_master_field)) tax_master = frappe.bean(tax_master_doctype, self.get(tax_master_field))
for i, tax in enumerate(tax_master.get(tax_parentfield)): for i, tax in enumerate(tax_master.get(tax_parentfield)):
for fieldname in default_fields: for fieldname in default_fields:
@ -140,16 +139,16 @@ class AccountsController(TransactionBase):
def _calculate_taxes_and_totals(self): def _calculate_taxes_and_totals(self):
# validate conversion rate # validate conversion rate
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
if not self.doc.currency or self.doc.currency == company_currency: if not self.currency or self.currency == company_currency:
self.doc.currency = company_currency self.currency = company_currency
self.doc.conversion_rate = 1.0 self.conversion_rate = 1.0
else: else:
from erpnext.setup.doctype.currency.currency import validate_conversion_rate from erpnext.setup.doctype.currency.currency import validate_conversion_rate
validate_conversion_rate(self.doc.currency, self.doc.conversion_rate, validate_conversion_rate(self.currency, self.conversion_rate,
self.meta.get_label("conversion_rate"), self.doc.company) self.meta.get_label("conversion_rate"), self.company)
self.doc.conversion_rate = flt(self.doc.conversion_rate) self.conversion_rate = flt(self.conversion_rate)
self.item_doclist = self.get(self.fname) self.item_doclist = self.get(self.fname)
self.tax_doclist = self.get(self.other_fname) self.tax_doclist = self.get(self.other_fname)
@ -175,7 +174,7 @@ class AccountsController(TransactionBase):
tax_fields.append("tax_amount") tax_fields.append("tax_amount")
for fieldname in tax_fields: for fieldname in tax_fields:
tax.fields[fieldname] = 0.0 tax.set(fieldname, 0.0)
self.validate_on_previous_row(tax) self.validate_on_previous_row(tax)
self.validate_inclusive_tax(tax) self.validate_inclusive_tax(tax)
@ -297,7 +296,7 @@ class AccountsController(TransactionBase):
self.precision("tax_amount", tax)) self.precision("tax_amount", tax))
def adjust_discount_amount_loss(self, tax): def adjust_discount_amount_loss(self, tax):
discount_amount_loss = self.doc.grand_total - flt(self.doc.discount_amount) - tax.total discount_amount_loss = self.grand_total - flt(self.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, self.precision("tax_amount", tax)) discount_amount_loss, self.precision("tax_amount", tax))
tax.total = flt(tax.total + discount_amount_loss, self.precision("total", tax)) tax.total = flt(tax.total + discount_amount_loss, self.precision("total", tax))
@ -309,8 +308,8 @@ class AccountsController(TransactionBase):
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
actual = flt(tax.rate, self.precision("tax_amount", tax)) actual = flt(tax.rate, self.precision("tax_amount", tax))
current_tax_amount = (self.doc.net_total current_tax_amount = (self.net_total
and ((item.base_amount / self.doc.net_total) * actual) and ((item.base_amount / self.net_total) * actual)
or 0) or 0)
elif tax.charge_type == "On Net Total": elif 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
@ -355,32 +354,32 @@ class AccountsController(TransactionBase):
def _set_in_company_currency(self, item, print_field, base_field): def _set_in_company_currency(self, item, print_field, base_field):
"""set values in base currency""" """set values in base currency"""
item.fields[base_field] = flt((flt(item.fields[print_field], item.set(base_field, flt((flt(item.fields[print_field],)
self.precision(print_field, item)) * self.doc.conversion_rate), self.precision(print_field, item)) * self.conversion_rate),
self.precision(base_field, item)) self.precision(base_field, item))
def calculate_total_advance(self, parenttype, advance_parentfield): def calculate_total_advance(self, parenttype, advance_parentfield):
if self.doc.doctype == parenttype and self.doc.docstatus < 2: if self.doctype == parenttype and self.docstatus < 2:
sum_of_allocated_amount = sum([flt(adv.allocated_amount, self.precision("allocated_amount", adv)) sum_of_allocated_amount = sum([flt(adv.allocated_amount, self.precision("allocated_amount", adv))
for adv in self.get(advance_parentfield)]) for adv in self.get(advance_parentfield)])
self.doc.total_advance = flt(sum_of_allocated_amount, self.precision("total_advance")) self.total_advance = flt(sum_of_allocated_amount, self.precision("total_advance"))
self.calculate_outstanding_amount() self.calculate_outstanding_amount()
def get_gl_dict(self, args): def get_gl_dict(self, args):
"""this method populates the common properties of a gl entry record""" """this method populates the common properties of a gl entry record"""
gl_dict = frappe._dict({ gl_dict = frappe._dict({
'company': self.doc.company, 'company': self.company,
'posting_date': self.doc.posting_date, 'posting_date': self.posting_date,
'voucher_type': self.doc.doctype, 'voucher_type': self.doctype,
'voucher_no': self.doc.name, 'voucher_no': self.name,
'aging_date': self.doc.fields.get("aging_date") or self.doc.posting_date, 'aging_date': self.get("aging_date") or self.posting_date,
'remarks': self.doc.remarks, 'remarks': self.remarks,
'fiscal_year': self.doc.fiscal_year, 'fiscal_year': self.fiscal_year,
'debit': 0, 'debit': 0,
'credit': 0, 'credit': 0,
'is_opening': self.doc.fields.get("is_opening") or "No", 'is_opening': self.get("is_opening") or "No",
}) })
gl_dict.update(args) gl_dict.update(args)
return gl_dict return gl_dict
@ -389,7 +388,7 @@ class AccountsController(TransactionBase):
self.doclist.remove_items({"parentfield": parentfield, "allocated_amount": ["in", [0, None, ""]]}) self.doclist.remove_items({"parentfield": parentfield, "allocated_amount": ["in", [0, None, ""]]})
frappe.db.sql("""delete from `tab%s` where parentfield=%s and parent = %s frappe.db.sql("""delete from `tab%s` where parentfield=%s and parent = %s
and ifnull(allocated_amount, 0) = 0""" % (childtype, '%s', '%s'), (parentfield, self.doc.name)) and ifnull(allocated_amount, 0) = 0""" % (childtype, '%s', '%s'), (parentfield, self.name))
def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr): def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr):
res = frappe.db.sql("""select t1.name as jv_no, t1.remark, res = frappe.db.sql("""select t1.name as jv_no, t1.remark,
@ -419,7 +418,7 @@ class AccountsController(TransactionBase):
global_tolerance = None global_tolerance = None
for item in self.get("entries"): for item in self.get("entries"):
if item.fields.get(item_ref_dn): if item.get(item_ref_dn):
ref_amt = flt(frappe.db.get_value(ref_dt + " Item", ref_amt = flt(frappe.db.get_value(ref_dt + " Item",
item.fields[item_ref_dn], based_on), self.precision(based_on, item)) item.fields[item_ref_dn], based_on), self.precision(based_on, item))
if not ref_amt: if not ref_amt:
@ -429,7 +428,7 @@ class AccountsController(TransactionBase):
already_billed = frappe.db.sql("""select sum(%s) from `tab%s` already_billed = frappe.db.sql("""select sum(%s) from `tab%s`
where %s=%s and docstatus=1 and parent != %s""" % where %s=%s and docstatus=1 and parent != %s""" %
(based_on, self.tname, item_ref_dn, '%s', '%s'), (based_on, self.tname, item_ref_dn, '%s', '%s'),
(item.fields[item_ref_dn], self.doc.name))[0][0] (item.fields[item_ref_dn], self.name))[0][0]
total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]),
self.precision(based_on, item)) self.precision(based_on, item))
@ -455,7 +454,7 @@ class AccountsController(TransactionBase):
def get_company_default(self, fieldname): def get_company_default(self, fieldname):
from erpnext.accounts.utils import get_company_default from erpnext.accounts.utils import get_company_default
return get_company_default(self.doc.company, fieldname) return get_company_default(self.company, fieldname)
def get_stock_items(self): def get_stock_items(self):
stock_items = [] stock_items = []
@ -471,7 +470,7 @@ class AccountsController(TransactionBase):
@property @property
def company_abbr(self): def company_abbr(self):
if not hasattr(self, "_abbr"): if not hasattr(self, "_abbr"):
self._abbr = frappe.db.get_value("Company", self.doc.company, "abbr") self._abbr = frappe.db.get_value("Company", self.company, "abbr")
return self._abbr return self._abbr

View File

@ -17,9 +17,9 @@ class BuyingController(StockController):
def validate(self): def validate(self):
super(BuyingController, self).validate() super(BuyingController, self).validate()
if self.doc.supplier and not self.doc.supplier_name: if self.supplier and not self.supplier_name:
self.doc.supplier_name = frappe.db.get_value("Supplier", self.supplier_name = frappe.db.get_value("Supplier",
self.doc.supplier, "supplier_name") self.supplier, "supplier_name")
self.is_item_table_empty() self.is_item_table_empty()
self.validate_stock_or_nonstock_items() self.validate_stock_or_nonstock_items()
self.validate_warehouse() self.validate_warehouse()
@ -31,19 +31,19 @@ class BuyingController(StockController):
self.set_price_list_currency("Buying") self.set_price_list_currency("Buying")
# set contact and address details for supplier, if they are not mentioned # set contact and address details for supplier, if they are not mentioned
if self.doc.supplier: if self.supplier:
self.doc.update_if_missing(get_party_details(self.doc.supplier, party_type="Supplier")) self.update_if_missing(get_party_details(self.supplier, party_type="Supplier"))
self.set_missing_item_details() self.set_missing_item_details()
if self.doc.fields.get("__islocal"): if self.get("__islocal"):
self.set_taxes("other_charges", "taxes_and_charges") self.set_taxes("other_charges", "taxes_and_charges")
def set_supplier_from_item_default(self): def set_supplier_from_item_default(self):
if self.meta.get_field("supplier") and not self.doc.supplier: if self.meta.get_field("supplier") and not self.supplier:
for d in self.doclist.get({"doctype": self.tname}): for d in self.doclist.get({"doctype": self.tname}):
supplier = frappe.db.get_value("Item", d.item_code, "default_supplier") supplier = frappe.db.get_value("Item", d.item_code, "default_supplier")
if supplier: if supplier:
self.doc.supplier = supplier self.supplier = supplier
break break
def validate_warehouse(self): def validate_warehouse(self):
@ -53,7 +53,7 @@ class BuyingController(StockController):
self.doclist.get({"doctype": self.tname}) if d.warehouse])) self.doclist.get({"doctype": self.tname}) if d.warehouse]))
for w in warehouses: for w in warehouses:
validate_warehouse_company(w, self.doc.company) validate_warehouse_company(w, self.company)
def validate_stock_or_nonstock_items(self): def validate_stock_or_nonstock_items(self):
if not self.get_stock_items(): if not self.get_stock_items():
@ -65,12 +65,12 @@ class BuyingController(StockController):
def set_total_in_words(self): def set_total_in_words(self):
from frappe.utils import money_in_words from frappe.utils import money_in_words
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
if self.meta.get_field("in_words"): if self.meta.get_field("in_words"):
self.doc.in_words = money_in_words(self.doc.grand_total, company_currency) self.in_words = money_in_words(self.grand_total, company_currency)
if self.meta.get_field("in_words_import"): if self.meta.get_field("in_words_import"):
self.doc.in_words_import = money_in_words(self.doc.grand_total_import, self.in_words_import = money_in_words(self.grand_total_import,
self.doc.currency) self.currency)
def calculate_taxes_and_totals(self): def calculate_taxes_and_totals(self):
self.other_fname = "other_charges" self.other_fname = "other_charges"
@ -97,54 +97,54 @@ class BuyingController(StockController):
def calculate_net_total(self): def calculate_net_total(self):
self.doc.net_total = self.doc.net_total_import = 0.0 self.net_total = self.net_total_import = 0.0
for item in self.item_doclist: for item in self.item_doclist:
self.doc.net_total += item.base_amount self.net_total += item.base_amount
self.doc.net_total_import += item.amount self.net_total_import += item.amount
self.round_floats_in(self.doc, ["net_total", "net_total_import"]) self.round_floats_in(self.doc, ["net_total", "net_total_import"])
def calculate_totals(self): def calculate_totals(self):
self.doc.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist self.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist
else self.doc.net_total, self.precision("grand_total")) else self.net_total, self.precision("grand_total"))
self.doc.grand_total_import = flt(self.doc.grand_total / self.doc.conversion_rate, self.grand_total_import = flt(self.grand_total / self.conversion_rate,
self.precision("grand_total_import")) self.precision("grand_total_import"))
self.doc.total_tax = flt(self.doc.grand_total - self.doc.net_total, self.total_tax = flt(self.grand_total - self.net_total,
self.precision("total_tax")) self.precision("total_tax"))
if self.meta.get_field("rounded_total"): if self.meta.get_field("rounded_total"):
self.doc.rounded_total = _round(self.doc.grand_total) self.rounded_total = _round(self.grand_total)
if self.meta.get_field("rounded_total_import"): if self.meta.get_field("rounded_total_import"):
self.doc.rounded_total_import = _round(self.doc.grand_total_import) self.rounded_total_import = _round(self.grand_total_import)
if self.meta.get_field("other_charges_added"): if self.meta.get_field("other_charges_added"):
self.doc.other_charges_added = flt(sum([flt(d.tax_amount) for d in self.tax_doclist self.other_charges_added = flt(sum([flt(d.tax_amount) for d in self.tax_doclist
if d.add_deduct_tax=="Add" and d.category in ["Valuation and Total", "Total"]]), if d.add_deduct_tax=="Add" and d.category in ["Valuation and Total", "Total"]]),
self.precision("other_charges_added")) self.precision("other_charges_added"))
if self.meta.get_field("other_charges_deducted"): if self.meta.get_field("other_charges_deducted"):
self.doc.other_charges_deducted = flt(sum([flt(d.tax_amount) for d in self.tax_doclist self.other_charges_deducted = flt(sum([flt(d.tax_amount) for d in self.tax_doclist
if d.add_deduct_tax=="Deduct" and d.category in ["Valuation and Total", "Total"]]), if d.add_deduct_tax=="Deduct" and d.category in ["Valuation and Total", "Total"]]),
self.precision("other_charges_deducted")) self.precision("other_charges_deducted"))
if self.meta.get_field("other_charges_added_import"): if self.meta.get_field("other_charges_added_import"):
self.doc.other_charges_added_import = flt(self.doc.other_charges_added / self.other_charges_added_import = flt(self.other_charges_added /
self.doc.conversion_rate, self.precision("other_charges_added_import")) self.conversion_rate, self.precision("other_charges_added_import"))
if self.meta.get_field("other_charges_deducted_import"): if self.meta.get_field("other_charges_deducted_import"):
self.doc.other_charges_deducted_import = flt(self.doc.other_charges_deducted / self.other_charges_deducted_import = flt(self.other_charges_deducted /
self.doc.conversion_rate, self.precision("other_charges_deducted_import")) self.conversion_rate, self.precision("other_charges_deducted_import"))
def calculate_outstanding_amount(self): def calculate_outstanding_amount(self):
if self.doc.doctype == "Purchase Invoice" and self.doc.docstatus == 0: if self.doctype == "Purchase Invoice" and self.docstatus == 0:
self.doc.total_advance = flt(self.doc.total_advance, self.total_advance = flt(self.total_advance,
self.precision("total_advance")) self.precision("total_advance"))
self.doc.total_amount_to_pay = flt(self.doc.grand_total - flt(self.doc.write_off_amount, self.total_amount_to_pay = flt(self.grand_total - flt(self.write_off_amount,
self.precision("write_off_amount")), self.precision("total_amount_to_pay")) self.precision("write_off_amount")), self.precision("total_amount_to_pay"))
self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance, self.outstanding_amount = flt(self.total_amount_to_pay - self.total_advance,
self.precision("outstanding_amount")) self.precision("outstanding_amount"))
def _cleanup(self): def _cleanup(self):
@ -208,18 +208,18 @@ class BuyingController(StockController):
item.valuation_rate = 0.0 item.valuation_rate = 0.0
def validate_for_subcontracting(self): def validate_for_subcontracting(self):
if not self.doc.is_subcontracted and self.sub_contracted_items: if not self.is_subcontracted and self.sub_contracted_items:
frappe.msgprint(_("""Please enter whether %s is made for subcontracting or purchasing, frappe.msgprint(_("""Please enter whether %s is made for subcontracting or purchasing,
in 'Is Subcontracted' field""" % self.doc.doctype), raise_exception=1) in 'Is Subcontracted' field""" % self.doctype), raise_exception=1)
if self.doc.doctype == "Purchase Receipt" and self.doc.is_subcontracted=="Yes" \ if self.doctype == "Purchase Receipt" and self.is_subcontracted=="Yes" \
and not self.doc.supplier_warehouse: and not self.supplier_warehouse:
frappe.msgprint(_("Supplier Warehouse mandatory subcontracted purchase receipt"), frappe.msgprint(_("Supplier Warehouse mandatory subcontracted purchase receipt"),
raise_exception=1) raise_exception=1)
def update_raw_materials_supplied(self, raw_material_table): def update_raw_materials_supplied(self, raw_material_table):
self.set(raw_material_table, []) self.set(raw_material_table, [])
if self.doc.is_subcontracted=="Yes": if self.is_subcontracted=="Yes":
for item in self.get(self.fname): for item in self.get(self.fname):
if item.item_code in self.sub_contracted_items: if item.item_code in self.sub_contracted_items:
self.add_bom_items(item, raw_material_table) self.add_bom_items(item, raw_material_table)
@ -230,7 +230,7 @@ class BuyingController(StockController):
for item in bom_items: for item in bom_items:
required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor) required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor)
rm_doclist = { rm_doclist = {
"doctype": self.doc.doctype + " Item Supplied", "doctype": self.doctype + " Item Supplied",
"reference_name": d.name, "reference_name": d.name,
"bom_detail_no": item.name, "bom_detail_no": item.name,
"main_item_code": d.item_code, "main_item_code": d.item_code,
@ -241,7 +241,7 @@ class BuyingController(StockController):
"rate": item.rate, "rate": item.rate,
"amount": required_qty * flt(item.rate) "amount": required_qty * flt(item.rate)
} }
if self.doc.doctype == "Purchase Receipt": if self.doctype == "Purchase Receipt":
rm_doclist.update({ rm_doclist.update({
"consumed_qty": required_qty, "consumed_qty": required_qty,
"description": item.description, "description": item.description,
@ -251,7 +251,7 @@ class BuyingController(StockController):
raw_materials_cost += required_qty * flt(item.rate) raw_materials_cost += required_qty * flt(item.rate)
if self.doc.doctype == "Purchase Receipt": if self.doctype == "Purchase Receipt":
d.rm_supp_cost = raw_materials_cost d.rm_supp_cost = raw_materials_cost
def get_items_from_default_bom(self, item_code): def get_items_from_default_bom(self, item_code):

View File

@ -28,27 +28,27 @@ class SellingController(StockController):
# set contact and address details for customer, if they are not mentioned # set contact and address details for customer, if they are not mentioned
self.set_missing_lead_customer_details() self.set_missing_lead_customer_details()
self.set_price_list_and_item_details() self.set_price_list_and_item_details()
if self.doc.fields.get("__islocal"): if self.get("__islocal"):
self.set_taxes("other_charges", "taxes_and_charges") self.set_taxes("other_charges", "taxes_and_charges")
def set_missing_lead_customer_details(self): def set_missing_lead_customer_details(self):
if self.doc.customer: if self.customer:
from erpnext.accounts.party import _get_party_details from erpnext.accounts.party import _get_party_details
self.doc.update_if_missing(_get_party_details(self.doc.customer, self.update_if_missing(_get_party_details(self.customer,
ignore_permissions=self.bean.ignore_permissions)) ignore_permissions=self.bean.ignore_permissions))
elif self.doc.lead: elif self.lead:
from erpnext.selling.doctype.lead.lead import get_lead_details from erpnext.selling.doctype.lead.lead import get_lead_details
self.doc.update_if_missing(get_lead_details(self.doc.lead)) self.update_if_missing(get_lead_details(self.lead))
def set_price_list_and_item_details(self): def set_price_list_and_item_details(self):
self.set_price_list_currency("Selling") self.set_price_list_currency("Selling")
self.set_missing_item_details() self.set_missing_item_details()
def apply_shipping_rule(self): def apply_shipping_rule(self):
if self.doc.shipping_rule: if self.shipping_rule:
shipping_rule = frappe.bean("Shipping Rule", self.doc.shipping_rule) shipping_rule = frappe.bean("Shipping Rule", self.shipping_rule)
value = self.doc.net_total value = self.net_total
# TODO # TODO
# shipping rule calculation based on item's net weight # shipping rule calculation based on item's net weight
@ -62,25 +62,25 @@ class SellingController(StockController):
self.append("other_charges", { self.append("other_charges", {
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"charge_type": "Actual", "charge_type": "Actual",
"account_head": shipping_rule.doc.account, "account_head": shipping_rule.account,
"cost_center": shipping_rule.doc.cost_center, "cost_center": shipping_rule.cost_center,
"description": shipping_rule.doc.label, "description": shipping_rule.label,
"rate": shipping_amount "rate": shipping_amount
}) })
def set_total_in_words(self): def set_total_in_words(self):
from frappe.utils import money_in_words from frappe.utils import money_in_words
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None,
"disable_rounded_total")) "disable_rounded_total"))
if self.meta.get_field("in_words"): if self.meta.get_field("in_words"):
self.doc.in_words = money_in_words(disable_rounded_total and self.in_words = money_in_words(disable_rounded_total and
self.doc.grand_total or self.doc.rounded_total, company_currency) self.grand_total or self.rounded_total, company_currency)
if self.meta.get_field("in_words_export"): if self.meta.get_field("in_words_export"):
self.doc.in_words_export = money_in_words(disable_rounded_total and self.in_words_export = money_in_words(disable_rounded_total and
self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) self.grand_total_export or self.rounded_total_export, self.currency)
def calculate_taxes_and_totals(self): def calculate_taxes_and_totals(self):
self.other_fname = "other_charges" self.other_fname = "other_charges"
@ -112,7 +112,7 @@ class SellingController(StockController):
cumulated_tax_fraction += tax.tax_fraction_for_current_item cumulated_tax_fraction += tax.tax_fraction_for_current_item
if cumulated_tax_fraction and not self.discount_amount_applied: if cumulated_tax_fraction and not self.discount_amount_applied:
item.base_amount = flt((item.amount * self.doc.conversion_rate) / item.base_amount = flt((item.amount * self.conversion_rate) /
(1 + cumulated_tax_fraction), self.precision("base_amount", item)) (1 + cumulated_tax_fraction), self.precision("base_amount", item))
item.base_rate = flt(item.base_amount / item.qty, self.precision("base_rate", item)) item.base_rate = flt(item.base_amount / item.qty, self.precision("base_rate", item))
@ -166,38 +166,38 @@ class SellingController(StockController):
self._set_in_company_currency(item, "amount", "base_amount") self._set_in_company_currency(item, "amount", "base_amount")
def calculate_net_total(self): def calculate_net_total(self):
self.doc.net_total = self.doc.net_total_export = 0.0 self.net_total = self.net_total_export = 0.0
for item in self.item_doclist: for item in self.item_doclist:
self.doc.net_total += item.base_amount self.net_total += item.base_amount
self.doc.net_total_export += item.amount self.net_total_export += item.amount
self.round_floats_in(self.doc, ["net_total", "net_total_export"]) self.round_floats_in(self.doc, ["net_total", "net_total_export"])
def calculate_totals(self): def calculate_totals(self):
self.doc.grand_total = flt(self.tax_doclist and \ self.grand_total = flt(self.tax_doclist and \
self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total")) self.tax_doclist[-1].total or self.net_total, self.precision("grand_total"))
self.doc.grand_total_export = flt(self.doc.grand_total / self.doc.conversion_rate, self.grand_total_export = flt(self.grand_total / self.conversion_rate,
self.precision("grand_total_export")) self.precision("grand_total_export"))
self.doc.other_charges_total = flt(self.doc.grand_total - self.doc.net_total, self.other_charges_total = flt(self.grand_total - self.net_total,
self.precision("other_charges_total")) self.precision("other_charges_total"))
self.doc.other_charges_total_export = flt(self.doc.grand_total_export - self.other_charges_total_export = flt(self.grand_total_export -
self.doc.net_total_export + flt(self.doc.discount_amount), self.net_total_export + flt(self.discount_amount),
self.precision("other_charges_total_export")) self.precision("other_charges_total_export"))
self.doc.rounded_total = _round(self.doc.grand_total) self.rounded_total = _round(self.grand_total)
self.doc.rounded_total_export = _round(self.doc.grand_total_export) self.rounded_total_export = _round(self.grand_total_export)
def apply_discount_amount(self): def apply_discount_amount(self):
if self.doc.discount_amount: if self.discount_amount:
grand_total_for_discount_amount = self.get_grand_total_for_discount_amount() grand_total_for_discount_amount = self.get_grand_total_for_discount_amount()
if grand_total_for_discount_amount: if grand_total_for_discount_amount:
# calculate item amount after Discount Amount # calculate item amount after Discount Amount
for item in self.item_doclist: for item in self.item_doclist:
distributed_amount = flt(self.doc.discount_amount) * item.base_amount / grand_total_for_discount_amount distributed_amount = flt(self.discount_amount) * item.base_amount / grand_total_for_discount_amount
item.base_amount = flt(item.base_amount - distributed_amount, self.precision("base_amount", item)) item.base_amount = flt(item.base_amount - distributed_amount, self.precision("base_amount", item))
self.discount_amount_applied = True self.discount_amount_applied = True
@ -214,7 +214,7 @@ class SellingController(StockController):
flt(tax.rate) / 100 flt(tax.rate) / 100
actual_taxes_dict.setdefault(tax.idx, actual_tax_amount) actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)
grand_total_for_discount_amount = flt(self.doc.grand_total - sum(actual_taxes_dict.values()), grand_total_for_discount_amount = flt(self.grand_total - sum(actual_taxes_dict.values()),
self.precision("grand_total")) self.precision("grand_total"))
return grand_total_for_discount_amount return grand_total_for_discount_amount
@ -222,21 +222,21 @@ class SellingController(StockController):
# NOTE: # NOTE:
# write_off_amount is only for POS Invoice # write_off_amount is only for POS Invoice
# total_advance is only for non POS Invoice # total_advance is only for non POS Invoice
if self.doc.doctype == "Sales Invoice" and self.doc.docstatus == 0: if self.doctype == "Sales Invoice" and self.docstatus == 0:
self.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount", self.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount",
"paid_amount"]) "paid_amount"])
total_amount_to_pay = self.doc.grand_total - self.doc.write_off_amount total_amount_to_pay = self.grand_total - self.write_off_amount
self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance \ self.outstanding_amount = flt(total_amount_to_pay - self.total_advance \
- self.doc.paid_amount, self.precision("outstanding_amount")) - self.paid_amount, self.precision("outstanding_amount"))
def calculate_commission(self): def calculate_commission(self):
if self.meta.get_field("commission_rate"): if self.meta.get_field("commission_rate"):
self.round_floats_in(self.doc, ["net_total", "commission_rate"]) self.round_floats_in(self.doc, ["net_total", "commission_rate"])
if self.doc.commission_rate > 100.0: if self.commission_rate > 100.0:
msgprint(_(self.meta.get_label("commission_rate")) + " " + msgprint(_(self.meta.get_label("commission_rate")) + " " +
_("cannot be greater than 100"), raise_exception=True) _("cannot be greater than 100"), raise_exception=True)
self.doc.total_commission = flt(self.doc.net_total * self.doc.commission_rate / 100.0, self.total_commission = flt(self.net_total * self.commission_rate / 100.0,
self.precision("total_commission")) self.precision("total_commission"))
def calculate_contribution(self): def calculate_contribution(self):
@ -246,7 +246,7 @@ class SellingController(StockController):
self.round_floats_in(sales_person) self.round_floats_in(sales_person)
sales_person.allocated_amount = flt( sales_person.allocated_amount = flt(
self.doc.net_total * sales_person.allocated_percentage / 100.0, self.net_total * sales_person.allocated_percentage / 100.0,
self.precision("allocated_amount", sales_person)) self.precision("allocated_amount", sales_person))
total += sales_person.allocated_percentage total += sales_person.allocated_percentage
@ -258,15 +258,15 @@ class SellingController(StockController):
def validate_order_type(self): def validate_order_type(self):
valid_types = ["Sales", "Maintenance", "Shopping Cart"] valid_types = ["Sales", "Maintenance", "Shopping Cart"]
if not self.doc.order_type: if not self.order_type:
self.doc.order_type = "Sales" self.order_type = "Sales"
elif self.doc.order_type not in valid_types: elif self.order_type not in valid_types:
msgprint(_(self.meta.get_label("order_type")) + " " + msgprint(_(self.meta.get_label("order_type")) + " " +
_("must be one of") + ": " + comma_or(valid_types), raise_exception=True) _("must be one of") + ": " + comma_or(valid_types), raise_exception=True)
def check_credit(self, grand_total): def check_credit(self, grand_total):
customer_account = frappe.db.get_value("Account", {"company": self.doc.company, customer_account = frappe.db.get_value("Account", {"company": self.company,
"master_name": self.doc.customer}, "name") "master_name": self.customer}, "name")
if customer_account: if customer_account:
total_outstanding = frappe.db.sql("""select total_outstanding = frappe.db.sql("""select
sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
@ -291,7 +291,7 @@ class SellingController(StockController):
reserved_warehouse = "" reserved_warehouse = ""
reserved_qty_for_main_item = 0 reserved_qty_for_main_item = 0
if self.doc.doctype == "Sales Order": if self.doctype == "Sales Order":
if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or
self.has_sales_bom(d.item_code)) and not d.warehouse: self.has_sales_bom(d.item_code)) and not d.warehouse:
frappe.throw(_("Please enter Reserved Warehouse for item ") + frappe.throw(_("Please enter Reserved Warehouse for item ") +
@ -300,11 +300,11 @@ class SellingController(StockController):
if flt(d.qty) > flt(d.delivered_qty): if flt(d.qty) > flt(d.delivered_qty):
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty) reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
if self.doc.doctype == "Delivery Note" and d.against_sales_order: if self.doctype == "Delivery Note" and d.against_sales_order:
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12. # if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
# But in this case reserved qty should only be reduced by 10 and not 12 # But in this case reserved qty should only be reduced by 10 and not 12
already_delivered_qty = self.get_already_delivered_qty(self.doc.name, already_delivered_qty = self.get_already_delivered_qty(self.name,
d.against_sales_order, d.prevdoc_detail_docname) d.against_sales_order, d.prevdoc_detail_docname)
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname) so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
@ -362,10 +362,10 @@ class SellingController(StockController):
def check_stop_sales_order(self, ref_fieldname): def check_stop_sales_order(self, ref_fieldname):
for d in self.get(self.fname): for d in self.get(self.fname):
if d.fields.get(ref_fieldname): if d.get(ref_fieldname):
status = frappe.db.get_value("Sales Order", d.fields[ref_fieldname], "status") status = frappe.db.get_value("Sales Order", d.fields[ref_fieldname], "status")
if status == "Stopped": if status == "Stopped":
frappe.throw(self.doc.doctype + frappe.throw(self.doctype +
_(" can not be created/modified against stopped Sales Order ") + _(" can not be created/modified against stopped Sales Order ") +
d.fields[ref_fieldname]) d.fields[ref_fieldname])

View File

@ -25,27 +25,27 @@ status_map = {
], ],
"Opportunity": [ "Opportunity": [
["Draft", None], ["Draft", None],
["Submitted", "eval:self.doc.docstatus==1"], ["Submitted", "eval:self.docstatus==1"],
["Lost", "eval:self.doc.status=='Lost'"], ["Lost", "eval:self.status=='Lost'"],
["Quotation", "has_quotation"], ["Quotation", "has_quotation"],
["Replied", "communication_sent"], ["Replied", "communication_sent"],
["Cancelled", "eval:self.doc.docstatus==2"], ["Cancelled", "eval:self.docstatus==2"],
["Open", "communication_received"], ["Open", "communication_received"],
], ],
"Quotation": [ "Quotation": [
["Draft", None], ["Draft", None],
["Submitted", "eval:self.doc.docstatus==1"], ["Submitted", "eval:self.docstatus==1"],
["Lost", "eval:self.doc.status=='Lost'"], ["Lost", "eval:self.status=='Lost'"],
["Ordered", "has_sales_order"], ["Ordered", "has_sales_order"],
["Replied", "communication_sent"], ["Replied", "communication_sent"],
["Cancelled", "eval:self.doc.docstatus==2"], ["Cancelled", "eval:self.docstatus==2"],
["Open", "communication_received"], ["Open", "communication_received"],
], ],
"Sales Order": [ "Sales Order": [
["Draft", None], ["Draft", None],
["Submitted", "eval:self.doc.docstatus==1"], ["Submitted", "eval:self.docstatus==1"],
["Stopped", "eval:self.doc.status=='Stopped'"], ["Stopped", "eval:self.status=='Stopped'"],
["Cancelled", "eval:self.doc.docstatus==2"], ["Cancelled", "eval:self.docstatus==2"],
], ],
"Support Ticket": [ "Support Ticket": [
["Replied", "communication_sent"], ["Replied", "communication_sent"],
@ -66,26 +66,26 @@ class StatusUpdater(DocListController):
self.validate_qty() self.validate_qty()
def set_status(self, update=False): def set_status(self, update=False):
if self.doc.get("__islocal"): if self.get("__islocal"):
return return
if self.doc.doctype in status_map: if self.doctype in status_map:
sl = status_map[self.doc.doctype][:] sl = status_map[self.doctype][:]
sl.reverse() sl.reverse()
for s in sl: for s in sl:
if not s[1]: if not s[1]:
self.doc.status = s[0] self.status = s[0]
break break
elif s[1].startswith("eval:"): elif s[1].startswith("eval:"):
if eval(s[1][5:]): if eval(s[1][5:]):
self.doc.status = s[0] self.status = s[0]
break break
elif getattr(self, s[1])(): elif getattr(self, s[1])():
self.doc.status = s[0] self.status = s[0]
break break
if update: if update:
frappe.db.set_value(self.doc.doctype, self.doc.name, "status", self.doc.status) frappe.db.set_value(self.doctype, self.name, "status", self.status)
def on_communication(self): def on_communication(self):
self.communication_set = True self.communication_set = True
@ -114,7 +114,7 @@ class StatusUpdater(DocListController):
for args in self.status_updater: for args in self.status_updater:
# get unique transactions to update # get unique transactions to update
for d in self.doclist: for d in self.doclist:
if d.doctype == args['source_dt'] and d.fields.get(args["join_field"]): if d.doctype == args['source_dt'] and d.get(args["join_field"]):
args['name'] = d.fields[args['join_field']] args['name'] = d.fields[args['join_field']]
# get all qty where qty > target_field # get all qty where qty > target_field
@ -181,10 +181,10 @@ class StatusUpdater(DocListController):
""" """
for args in self.status_updater: for args in self.status_updater:
# condition to include current record (if submit or no if cancel) # condition to include current record (if submit or no if cancel)
if self.doc.docstatus == 1: if self.docstatus == 1:
args['cond'] = ' or parent="%s"' % self.doc.name.replace('"', '\"') args['cond'] = ' or parent="%s"' % self.name.replace('"', '\"')
else: else:
args['cond'] = ' and parent!="%s"' % self.doc.name.replace('"', '\"') args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')
args['modified_cond'] = '' args['modified_cond'] = ''
if change_modified: if change_modified:
@ -194,7 +194,7 @@ class StatusUpdater(DocListController):
for d in self.doclist: for d in self.doclist:
if d.doctype == args['source_dt']: if d.doctype == args['source_dt']:
# updates qty in the child table # updates qty in the child table
args['detail_id'] = d.fields.get(args['join_field']) args['detail_id'] = d.get(args['join_field'])
args['second_source_condition'] = "" args['second_source_condition'] = ""
if args.get('second_source_dt') and args.get('second_source_field') \ if args.get('second_source_dt') and args.get('second_source_field') \
@ -212,7 +212,7 @@ class StatusUpdater(DocListController):
where name='%(detail_id)s'""" % args) where name='%(detail_id)s'""" % args)
# get unique transactions to update # get unique transactions to update
for name in set([d.fields.get(args['percent_join_field']) for d in self.doclist for name in set([d.get(args['percent_join_field']) for d in self.doclist
if d.doctype == args['source_dt']]): if d.doctype == args['source_dt']]):
if name: if name:
args['name'] = name args['name'] = name
@ -241,9 +241,9 @@ class StatusUpdater(DocListController):
where docstatus=1 and net_total = 0""" % ref_dt) where docstatus=1 and net_total = 0""" % ref_dt)
for item in self.get("entries"): for item in self.get("entries"):
if item.fields.get(ref_fieldname) \ if item.get(ref_fieldname) \
and item.fields.get(ref_fieldname) in all_zero_amount_refdoc \ and item.get(ref_fieldname) in all_zero_amount_refdoc \
and item.fields.get(ref_fieldname) not in zero_amount_refdoc: and item.get(ref_fieldname) not in zero_amount_refdoc:
zero_amount_refdoc.append(item.fields[ref_fieldname]) zero_amount_refdoc.append(item.fields[ref_fieldname])
if zero_amount_refdoc: if zero_amount_refdoc:
@ -256,7 +256,7 @@ class StatusUpdater(DocListController):
billed_qty = flt(frappe.db.sql("""select sum(ifnull(qty, 0)) billed_qty = flt(frappe.db.sql("""select sum(ifnull(qty, 0))
from `tab%s Item` where %s=%s and docstatus=1""" % from `tab%s Item` where %s=%s and docstatus=1""" %
(self.doc.doctype, ref_fieldname, '%s'), (ref_dn))[0][0]) (self.doctype, ref_fieldname, '%s'), (ref_dn))[0][0])
per_billed = ((ref_doc_qty if billed_qty > ref_doc_qty else billed_qty)\ per_billed = ((ref_doc_qty if billed_qty > ref_doc_qty else billed_qty)\
/ ref_doc_qty)*100 / ref_doc_qty)*100

View File

@ -12,19 +12,19 @@ from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries
class StockController(AccountsController): class StockController(AccountsController):
def make_gl_entries(self, repost_future_gle=True): def make_gl_entries(self, repost_future_gle=True):
if self.doc.docstatus == 2: if self.docstatus == 2:
delete_gl_entries(voucher_type=self.doc.doctype, voucher_no=self.doc.name) delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
warehouse_account = self.get_warehouse_account() warehouse_account = self.get_warehouse_account()
if self.doc.docstatus==1: if self.docstatus==1:
gl_entries = self.get_gl_entries(warehouse_account) gl_entries = self.get_gl_entries(warehouse_account)
make_gl_entries(gl_entries) make_gl_entries(gl_entries)
if repost_future_gle: if repost_future_gle:
items, warehouse_account = self.get_items_and_warehouse_accounts(warehouse_account) items, warehouse_account = self.get_items_and_warehouse_accounts(warehouse_account)
update_gl_entries_after(self.doc.posting_date, self.doc.posting_time, update_gl_entries_after(self.posting_date, self.posting_time,
warehouse_account, items) warehouse_account, items)
def get_gl_entries(self, warehouse_account=None, default_expense_account=None, def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
@ -49,7 +49,7 @@ class StockController(AccountsController):
"account": warehouse_account[sle.warehouse], "account": warehouse_account[sle.warehouse],
"against": detail.expense_account, "against": detail.expense_account,
"cost_center": detail.cost_center, "cost_center": detail.cost_center,
"remarks": self.doc.remarks or "Accounting Entry for Stock", "remarks": self.remarks or "Accounting Entry for Stock",
"debit": flt(sle.stock_value_difference, 2) "debit": flt(sle.stock_value_difference, 2)
})) }))
@ -58,7 +58,7 @@ class StockController(AccountsController):
"account": detail.expense_account, "account": detail.expense_account,
"against": warehouse_account[sle.warehouse], "against": warehouse_account[sle.warehouse],
"cost_center": detail.cost_center, "cost_center": detail.cost_center,
"remarks": self.doc.remarks or "Accounting Entry for Stock", "remarks": self.remarks or "Accounting Entry for Stock",
"credit": flt(sle.stock_value_difference, 2) "credit": flt(sle.stock_value_difference, 2)
})) }))
elif sle.warehouse not in warehouse_with_no_account: elif sle.warehouse not in warehouse_with_no_account:
@ -91,10 +91,10 @@ class StockController(AccountsController):
if hasattr(self, "fname"): if hasattr(self, "fname"):
item_doclist = self.doclist.get({"parentfield": self.fname}) item_doclist = self.doclist.get({"parentfield": self.fname})
elif self.doc.doctype == "Stock Reconciliation": elif self.doctype == "Stock Reconciliation":
import json import json
item_doclist = [] item_doclist = []
data = json.loads(self.doc.reconciliation_json) data = json.loads(self.reconciliation_json)
for row in data[data.index(self.head_row)+1:]: for row in data[data.index(self.head_row)+1:]:
d = frappe._dict(zip(["item_code", "warehouse", "qty", "valuation_rate"], row)) d = frappe._dict(zip(["item_code", "warehouse", "qty", "valuation_rate"], row))
item_doclist.append(d) item_doclist.append(d)
@ -115,7 +115,7 @@ class StockController(AccountsController):
stock_ledger = {} stock_ledger = {}
for sle in frappe.db.sql("""select warehouse, stock_value_difference, voucher_detail_no for sle in frappe.db.sql("""select warehouse, stock_value_difference, voucher_detail_no
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.doc.doctype, self.doc.name), as_dict=True): (self.doctype, self.name), as_dict=True):
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle) stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
return stock_ledger return stock_ledger
@ -167,7 +167,7 @@ class StockController(AccountsController):
from `tabStock Ledger Entry` sle from `tabStock Ledger Entry` sle
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) %s where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) %s
order by timestamp(sle.posting_date, sle.posting_time) asc, name asc""" % order by timestamp(sle.posting_date, sle.posting_time) asc, name asc""" %
('%s', '%s', condition), (self.doc.posting_date, self.doc.posting_time), ('%s', '%s', condition), (self.posting_date, self.posting_time),
as_dict=True): as_dict=True):
future_stock_vouchers.append([d.voucher_type, d.voucher_no]) future_stock_vouchers.append([d.voucher_type, d.voucher_no])
@ -179,7 +179,7 @@ class StockController(AccountsController):
for d in frappe.db.sql("""select * from `tabGL Entry` for d in frappe.db.sql("""select * from `tabGL Entry`
where posting_date >= %s and voucher_no in (%s)""" % where posting_date >= %s and voucher_no in (%s)""" %
('%s', ', '.join(['%s']*len(future_stock_vouchers))), ('%s', ', '.join(['%s']*len(future_stock_vouchers))),
tuple([self.doc.posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1): tuple([self.posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d) gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
return gl_entries return gl_entries
@ -235,20 +235,20 @@ class StockController(AccountsController):
sl_dict = { sl_dict = {
"item_code": d.item_code, "item_code": d.item_code,
"warehouse": d.warehouse, "warehouse": d.warehouse,
"posting_date": self.doc.posting_date, "posting_date": self.posting_date,
"posting_time": self.doc.posting_time, "posting_time": self.posting_time,
"voucher_type": self.doc.doctype, "voucher_type": self.doctype,
"voucher_no": self.doc.name, "voucher_no": self.name,
"voucher_detail_no": d.name, "voucher_detail_no": d.name,
"actual_qty": (self.doc.docstatus==1 and 1 or -1)*flt(d.stock_qty), "actual_qty": (self.docstatus==1 and 1 or -1)*flt(d.stock_qty),
"stock_uom": d.stock_uom, "stock_uom": d.stock_uom,
"incoming_rate": 0, "incoming_rate": 0,
"company": self.doc.company, "company": self.company,
"fiscal_year": self.doc.fiscal_year, "fiscal_year": self.fiscal_year,
"batch_no": cstr(d.batch_no).strip(), "batch_no": cstr(d.batch_no).strip(),
"serial_no": d.serial_no, "serial_no": d.serial_no,
"project": d.project_name, "project": d.project_name,
"is_cancelled": self.doc.docstatus==2 and "Yes" or "No" "is_cancelled": self.docstatus==2 and "Yes" or "No"
} }
sl_dict.update(args) sl_dict.update(args)
@ -260,7 +260,7 @@ class StockController(AccountsController):
def make_cancel_gl_entries(self): def make_cancel_gl_entries(self):
if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s
and voucher_no=%s""", (self.doc.doctype, self.doc.name)): and voucher_no=%s""", (self.doctype, self.name)):
self.make_gl_entries() self.make_gl_entries()
def update_gl_entries_after(posting_date, posting_time, warehouse_account=None, for_items=None): def update_gl_entries_after(posting_date, posting_time, warehouse_account=None, for_items=None):

View File

@ -13,21 +13,21 @@ from frappe.model.document import Document
class Appraisal(Document): class Appraisal(Document):
def validate(self): def validate(self):
if not self.doc.status: if not self.status:
self.doc.status = "Draft" self.status = "Draft"
self.validate_dates() self.validate_dates()
self.validate_existing_appraisal() self.validate_existing_appraisal()
self.calculate_total() self.calculate_total()
def get_employee_name(self): def get_employee_name(self):
emp_nm = frappe.db.sql("select employee_name from `tabEmployee` where name=%s", self.doc.employee) emp_nm = frappe.db.sql("select employee_name from `tabEmployee` where name=%s", self.employee)
emp_nm= emp_nm and emp_nm[0][0] or '' emp_nm= emp_nm and emp_nm[0][0] or ''
self.doc.employee_name = emp_nm self.employee_name = emp_nm
return emp_nm return emp_nm
def validate_dates(self): def validate_dates(self):
if getdate(self.doc.start_date) > getdate(self.doc.end_date): if getdate(self.start_date) > getdate(self.end_date):
msgprint("End Date can not be less than Start Date") msgprint("End Date can not be less than Start Date")
raise Exception raise Exception
@ -35,11 +35,11 @@ class Appraisal(Document):
chk = frappe.db.sql("""select name from `tabAppraisal` where employee=%s chk = frappe.db.sql("""select name from `tabAppraisal` where employee=%s
and (status='Submitted' or status='Completed') and (status='Submitted' or status='Completed')
and ((start_date>=%s and start_date<=%s) and ((start_date>=%s and start_date<=%s)
or (end_date>=%s and end_date<=%s))""",(self.doc.employee,self.doc.start_date,self.doc.end_date,self.doc.start_date,self.doc.end_date)) or (end_date>=%s and end_date<=%s))""",(self.employee,self.start_date,self.end_date,self.start_date,self.end_date))
if chk: if chk:
msgprint("You have already created Appraisal "\ msgprint("You have already created Appraisal "\
+cstr(chk[0][0])+" in the current date range for employee "\ +cstr(chk[0][0])+" in the current date range for employee "\
+cstr(self.doc.employee_name)) +cstr(self.employee_name))
raise Exception raise Exception
def calculate_total(self): def calculate_total(self):
@ -54,11 +54,11 @@ class Appraisal(Document):
msgprint("Total weightage assigned should be 100%. It is :" + str(total_w) + "%", msgprint("Total weightage assigned should be 100%. It is :" + str(total_w) + "%",
raise_exception=1) raise_exception=1)
if frappe.db.get_value("Employee", self.doc.employee, "user_id") != \ if frappe.db.get_value("Employee", self.employee, "user_id") != \
frappe.session.user and total == 0: frappe.session.user and total == 0:
msgprint("Total can't be zero. You must atleast give some points!", raise_exception=1) msgprint("Total can't be zero. You must atleast give some points!", raise_exception=1)
self.doc.total_score = total self.total_score = total
def on_submit(self): def on_submit(self):
frappe.db.set(self.doc, 'status', 'Submitted') frappe.db.set(self.doc, 'status', 'Submitted')

View File

@ -10,11 +10,11 @@ from frappe.model.document import Document
class AppraisalTemplate(Document): class AppraisalTemplate(Document):
def validate(self): def validate(self):
self.doc.total_points = 0 self.total_points = 0
for d in self.doclist.get({"doctype":"Appraisal Template Goal"}): for d in self.doclist.get({"doctype":"Appraisal Template Goal"}):
self.doc.total_points += int(d.per_weightage or 0) self.total_points += int(d.per_weightage or 0)
if int(self.doc.total_points) != 100: if int(self.total_points) != 100:
frappe.msgprint(_("Total (sum of) points distribution for all goals should be 100.") \ frappe.msgprint(_("Total (sum of) points distribution for all goals should be 100.") \
+ " " + _("Not") + " " + str(self.doc.total_points), + " " + _("Not") + " " + str(self.total_points),
raise_exception=True) raise_exception=True)

View File

@ -15,40 +15,40 @@ class Attendance(Document):
def validate_duplicate_record(self): def validate_duplicate_record(self):
res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and att_date = %s res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and att_date = %s
and name != %s and docstatus = 1""", and name != %s and docstatus = 1""",
(self.doc.employee, self.doc.att_date, self.doc.name)) (self.employee, self.att_date, self.name))
if res: if res:
msgprint(_("Attendance for the employee: ") + self.doc.employee + msgprint(_("Attendance for the employee: ") + self.employee +
_(" already marked"), raise_exception=1) _(" already marked"), raise_exception=1)
def check_leave_record(self): def check_leave_record(self):
if self.doc.status == 'Present': if self.status == 'Present':
leave = frappe.db.sql("""select name from `tabLeave Application` leave = frappe.db.sql("""select name from `tabLeave Application`
where employee = %s and %s between from_date and to_date and status = 'Approved' where employee = %s and %s between from_date and to_date and status = 'Approved'
and docstatus = 1""", (self.doc.employee, self.doc.att_date)) and docstatus = 1""", (self.employee, self.att_date))
if leave: if leave:
frappe.msgprint(_("Employee: ") + self.doc.employee + _(" was on leave on ") frappe.msgprint(_("Employee: ") + self.employee + _(" was on leave on ")
+ self.doc.att_date + _(". You can not mark his attendance as 'Present'"), + self.att_date + _(". You can not mark his attendance as 'Present'"),
raise_exception=1) raise_exception=1)
def validate_fiscal_year(self): def validate_fiscal_year(self):
from erpnext.accounts.utils import validate_fiscal_year from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.att_date, self.doc.fiscal_year) validate_fiscal_year(self.att_date, self.fiscal_year)
def validate_att_date(self): def validate_att_date(self):
if getdate(self.doc.att_date) > getdate(nowdate()): if getdate(self.att_date) > getdate(nowdate()):
msgprint(_("Attendance can not be marked for future dates"), raise_exception=1) msgprint(_("Attendance can not be marked for future dates"), raise_exception=1)
def validate_employee(self): def validate_employee(self):
emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'", emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
self.doc.employee) self.employee)
if not emp: if not emp:
msgprint(_("Employee: ") + self.doc.employee + msgprint(_("Employee: ") + self.employee +
_(" not active or does not exists in the system"), raise_exception=1) _(" not active or does not exists in the system"), raise_exception=1)
def validate(self): def validate(self):
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.doc.status, ["Present", "Absent", "Half Day"]) validate_status(self.status, ["Present", "Absent", "Half Day"])
self.validate_fiscal_year() self.validate_fiscal_year()
self.validate_att_date() self.validate_att_date()
self.validate_duplicate_record() self.validate_duplicate_record()
@ -57,5 +57,5 @@ class Attendance(Document):
def on_update(self): def on_update(self):
# this is done because sometimes user entered wrong employee name # this is done because sometimes user entered wrong employee name
# while uploading employee attendance # while uploading employee attendance
employee_name = frappe.db.get_value("Employee", self.doc.employee, "employee_name") employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
frappe.db.set(self.doc, 'employee_name', employee_name) frappe.db.set(self.doc, 'employee_name', employee_name)

View File

@ -18,28 +18,28 @@ class Employee(DocListController):
throw(_("Please setup Employee Naming System in Human Resource > HR Settings")) throw(_("Please setup Employee Naming System in Human Resource > HR Settings"))
else: else:
if naming_method=='Naming Series': if naming_method=='Naming Series':
self.doc.name = make_autoname(self.doc.naming_series + '.####') self.name = make_autoname(self.naming_series + '.####')
elif naming_method=='Employee Number': elif naming_method=='Employee Number':
self.doc.name = self.doc.employee_number self.name = self.employee_number
self.doc.employee = self.doc.name self.employee = self.name
def validate(self): def validate(self):
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.doc.status, ["Active", "Left"]) validate_status(self.status, ["Active", "Left"])
self.doc.employee = self.doc.name self.employee = self.name
self.validate_date() self.validate_date()
self.validate_email() self.validate_email()
self.validate_status() self.validate_status()
self.validate_employee_leave_approver() self.validate_employee_leave_approver()
if self.doc.user_id: if self.user_id:
self.validate_for_enabled_user_id() self.validate_for_enabled_user_id()
self.validate_duplicate_user_id() self.validate_duplicate_user_id()
def on_update(self): def on_update(self):
if self.doc.user_id and frappe.db.get_value("User", self.doc.user_id, 'docstatus') == 0: if self.user_id and frappe.db.get_value("User", self.user_id, 'docstatus') == 0:
self.restrict_user() self.restrict_user()
self.update_user_default() self.update_user_default()
self.update_user() self.update_user()
@ -49,17 +49,17 @@ class Employee(DocListController):
def restrict_user(self): def restrict_user(self):
"""restrict to this employee for user""" """restrict to this employee for user"""
self.add_restriction_if_required("Employee", self.doc.user_id) self.add_restriction_if_required("Employee", self.user_id)
def update_user_default(self): def update_user_default(self):
frappe.db.set_default("employee_name", self.doc.employee_name, self.doc.user_id) frappe.db.set_default("employee_name", self.employee_name, self.user_id)
frappe.db.set_default("company", self.doc.company, self.doc.user_id) frappe.db.set_default("company", self.company, self.user_id)
def restrict_leave_approver(self): def restrict_leave_approver(self):
"""restrict to this employee for leave approver""" """restrict to this employee for leave approver"""
employee_leave_approvers = [d.leave_approver for d in self.get("employee_leave_approvers")] employee_leave_approvers = [d.leave_approver for d in self.get("employee_leave_approvers")]
if self.doc.reports_to and self.doc.reports_to not in employee_leave_approvers: if self.reports_to and self.reports_to not in employee_leave_approvers:
employee_leave_approvers.append(frappe.db.get_value("Employee", self.doc.reports_to, "user_id")) employee_leave_approvers.append(frappe.db.get_value("Employee", self.reports_to, "user_id"))
for user in employee_leave_approvers: for user in employee_leave_approvers:
self.add_restriction_if_required("Employee", user) self.add_restriction_if_required("Employee", user)
@ -67,45 +67,45 @@ class Employee(DocListController):
def add_restriction_if_required(self, doctype, user): def add_restriction_if_required(self, doctype, user):
if frappe.permissions.has_only_non_restrict_role(doctype, user) \ if frappe.permissions.has_only_non_restrict_role(doctype, user) \
and self.doc.name not in get_restrictions(user).get("Employee", []): and self.name not in get_restrictions(user).get("Employee", []):
frappe.defaults.add_default("Employee", self.doc.name, user, "Restriction") frappe.defaults.add_default("Employee", self.name, user, "Restriction")
def update_user(self): def update_user(self):
# add employee role if missing # add employee role if missing
if not "Employee" in frappe.db.sql_list("""select role from tabUserRole if not "Employee" in frappe.db.sql_list("""select role from tabUserRole
where parent=%s""", self.doc.user_id): where parent=%s""", self.user_id):
from frappe.utils.user import add_role from frappe.utils.user import add_role
add_role(self.doc.user_id, "Employee") add_role(self.user_id, "Employee")
user_wrapper = frappe.bean("User", self.doc.user_id) user_wrapper = frappe.bean("User", self.user_id)
# copy details like Fullname, DOB and Image to User # copy details like Fullname, DOB and Image to User
if self.doc.employee_name: if self.employee_name:
employee_name = self.doc.employee_name.split(" ") employee_name = self.employee_name.split(" ")
if len(employee_name) >= 3: if len(employee_name) >= 3:
user_wrapper.doc.last_name = " ".join(employee_name[2:]) user_wrapper.last_name = " ".join(employee_name[2:])
user_wrapper.doc.middle_name = employee_name[1] user_wrapper.middle_name = employee_name[1]
elif len(employee_name) == 2: elif len(employee_name) == 2:
user_wrapper.doc.last_name = employee_name[1] user_wrapper.last_name = employee_name[1]
user_wrapper.doc.first_name = employee_name[0] user_wrapper.first_name = employee_name[0]
if self.doc.date_of_birth: if self.date_of_birth:
user_wrapper.doc.birth_date = self.doc.date_of_birth user_wrapper.birth_date = self.date_of_birth
if self.doc.gender: if self.gender:
user_wrapper.doc.gender = self.doc.gender user_wrapper.gender = self.gender
if self.doc.image: if self.image:
if not user_wrapper.doc.user_image == self.doc.image: if not user_wrapper.user_image == self.image:
user_wrapper.doc.user_image = self.doc.image user_wrapper.user_image = self.image
try: try:
frappe.doc({ frappe.doc({
"doctype": "File Data", "doctype": "File Data",
"file_name": self.doc.image, "file_name": self.image,
"attached_to_doctype": "User", "attached_to_doctype": "User",
"attached_to_name": self.doc.user_id "attached_to_name": self.user_id
}).insert() }).insert()
except frappe.DuplicateEntryError, e: except frappe.DuplicateEntryError, e:
# already exists # already exists
@ -114,51 +114,51 @@ class Employee(DocListController):
user_wrapper.save() user_wrapper.save()
def validate_date(self): def validate_date(self):
if self.doc.date_of_birth and self.doc.date_of_joining and getdate(self.doc.date_of_birth) >= getdate(self.doc.date_of_joining): if self.date_of_birth and self.date_of_joining and getdate(self.date_of_birth) >= getdate(self.date_of_joining):
throw(_("Date of Joining must be greater than Date of Birth")) throw(_("Date of Joining must be greater than Date of Birth"))
elif self.doc.scheduled_confirmation_date and self.doc.date_of_joining and (getdate(self.doc.scheduled_confirmation_date) < getdate(self.doc.date_of_joining)): elif self.scheduled_confirmation_date and self.date_of_joining and (getdate(self.scheduled_confirmation_date) < getdate(self.date_of_joining)):
throw(_("Scheduled Confirmation Date must be greater than Date of Joining")) throw(_("Scheduled Confirmation Date must be greater than Date of Joining"))
elif self.doc.final_confirmation_date and self.doc.date_of_joining and (getdate(self.doc.final_confirmation_date) < getdate(self.doc.date_of_joining)): elif self.final_confirmation_date and self.date_of_joining and (getdate(self.final_confirmation_date) < getdate(self.date_of_joining)):
throw(_("Final Confirmation Date must be greater than Date of Joining")) throw(_("Final Confirmation Date must be greater than Date of Joining"))
elif self.doc.date_of_retirement and self.doc.date_of_joining and (getdate(self.doc.date_of_retirement) <= getdate(self.doc.date_of_joining)): elif self.date_of_retirement and self.date_of_joining and (getdate(self.date_of_retirement) <= getdate(self.date_of_joining)):
throw(_("Date Of Retirement must be greater than Date of Joining")) throw(_("Date Of Retirement must be greater than Date of Joining"))
elif self.doc.relieving_date and self.doc.date_of_joining and (getdate(self.doc.relieving_date) <= getdate(self.doc.date_of_joining)): elif self.relieving_date and self.date_of_joining and (getdate(self.relieving_date) <= getdate(self.date_of_joining)):
throw(_("Relieving Date must be greater than Date of Joining")) throw(_("Relieving Date must be greater than Date of Joining"))
elif self.doc.contract_end_date and self.doc.date_of_joining and (getdate(self.doc.contract_end_date)<=getdate(self.doc.date_of_joining)): elif self.contract_end_date and self.date_of_joining and (getdate(self.contract_end_date)<=getdate(self.date_of_joining)):
throw(_("Contract End Date must be greater than Date of Joining")) throw(_("Contract End Date must be greater than Date of Joining"))
def validate_email(self): def validate_email(self):
if self.doc.company_email and not validate_email_add(self.doc.company_email): if self.company_email and not validate_email_add(self.company_email):
throw(_("Please enter valid Company Email")) throw(_("Please enter valid Company Email"))
if self.doc.personal_email and not validate_email_add(self.doc.personal_email): if self.personal_email and not validate_email_add(self.personal_email):
throw(_("Please enter valid Personal Email")) throw(_("Please enter valid Personal Email"))
def validate_status(self): def validate_status(self):
if self.doc.status == 'Left' and not self.doc.relieving_date: if self.status == 'Left' and not self.relieving_date:
throw(_("Please enter relieving date.")) throw(_("Please enter relieving date."))
def validate_for_enabled_user_id(self): def validate_for_enabled_user_id(self):
enabled = frappe.db.sql("""select name from `tabUser` where enabled = frappe.db.sql("""select name from `tabUser` where
name=%s and enabled=1""", self.doc.user_id) name=%s and enabled=1""", self.user_id)
if not enabled: if not enabled:
throw("{id}: {user_id} {msg}".format(**{ throw("{id}: {user_id} {msg}".format(**{
"id": _("User ID"), "id": _("User ID"),
"user_id": self.doc.user_id, "user_id": self.user_id,
"msg": _("is disabled.") "msg": _("is disabled.")
})) }))
def validate_duplicate_user_id(self): def validate_duplicate_user_id(self):
employee = frappe.db.sql_list("""select name from `tabEmployee` where employee = frappe.db.sql_list("""select name from `tabEmployee` where
user_id=%s and status='Active' and name!=%s""", (self.doc.user_id, self.doc.name)) user_id=%s and status='Active' and name!=%s""", (self.user_id, self.name))
if employee: if employee:
throw("{id}: {user_id} {msg}: {employee}".format(**{ throw("{id}: {user_id} {msg}: {employee}".format(**{
"id": _("User ID"), "id": _("User ID"),
"user_id": self.doc.user_id, "user_id": self.user_id,
"msg": _("is already assigned to Employee"), "msg": _("is already assigned to Employee"),
"employee": employee[0] "employee": employee[0]
})) }))
@ -173,24 +173,24 @@ class Employee(DocListController):
exc=InvalidLeaveApproverError) exc=InvalidLeaveApproverError)
def update_dob_event(self): def update_dob_event(self):
if self.doc.status == "Active" and self.doc.date_of_birth \ if self.status == "Active" and self.date_of_birth \
and not cint(frappe.db.get_value("HR Settings", None, "stop_birthday_reminders")): and not cint(frappe.db.get_value("HR Settings", None, "stop_birthday_reminders")):
birthday_event = frappe.db.sql("""select name from `tabEvent` where repeat_on='Every Year' birthday_event = frappe.db.sql("""select name from `tabEvent` where repeat_on='Every Year'
and ref_type='Employee' and ref_name=%s""", self.doc.name) and ref_type='Employee' and ref_name=%s""", self.name)
starts_on = self.doc.date_of_birth + " 00:00:00" starts_on = self.date_of_birth + " 00:00:00"
ends_on = self.doc.date_of_birth + " 00:15:00" ends_on = self.date_of_birth + " 00:15:00"
if birthday_event: if birthday_event:
event = frappe.bean("Event", birthday_event[0][0]) event = frappe.bean("Event", birthday_event[0][0])
event.doc.starts_on = starts_on event.starts_on = starts_on
event.doc.ends_on = ends_on event.ends_on = ends_on
event.save() event.save()
else: else:
frappe.bean({ frappe.bean({
"doctype": "Event", "doctype": "Event",
"subject": _("Birthday") + ": " + self.doc.employee_name, "subject": _("Birthday") + ": " + self.employee_name,
"description": _("Happy Birthday!") + " " + self.doc.employee_name, "description": _("Happy Birthday!") + " " + self.employee_name,
"starts_on": starts_on, "starts_on": starts_on,
"ends_on": ends_on, "ends_on": ends_on,
"event_type": "Public", "event_type": "Public",
@ -199,11 +199,11 @@ class Employee(DocListController):
"repeat_this_event": 1, "repeat_this_event": 1,
"repeat_on": "Every Year", "repeat_on": "Every Year",
"ref_type": "Employee", "ref_type": "Employee",
"ref_name": self.doc.name "ref_name": self.name
}).insert() }).insert()
else: else:
frappe.db.sql("""delete from `tabEvent` where repeat_on='Every Year' and frappe.db.sql("""delete from `tabEvent` where repeat_on='Every Year' and
ref_type='Employee' and ref_name=%s""", self.doc.name) ref_type='Employee' and ref_name=%s""", self.name)
@frappe.whitelist() @frappe.whitelist()
def get_retirement_date(date_of_birth=None): def get_retirement_date(date_of_birth=None):

View File

@ -16,13 +16,13 @@ class ExpenseClaim(Document):
self.validate_exp_details() self.validate_exp_details()
def on_submit(self): def on_submit(self):
if self.doc.approval_status=="Draft": if self.approval_status=="Draft":
frappe.msgprint("""Please set Approval Status to 'Approved' or \ frappe.msgprint("""Please set Approval Status to 'Approved' or \
'Rejected' before submitting""", raise_exception=1) 'Rejected' before submitting""", raise_exception=1)
def validate_fiscal_year(self): def validate_fiscal_year(self):
from erpnext.accounts.utils import validate_fiscal_year from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.posting_date, self.doc.fiscal_year, "Posting Date") validate_fiscal_year(self.posting_date, self.fiscal_year, "Posting Date")
def validate_exp_details(self): def validate_exp_details(self):
if not self.get('expense_voucher_details'): if not self.get('expense_voucher_details'):

View File

@ -13,7 +13,7 @@ from frappe.model.document import Document
class HolidayList(Document): class HolidayList(Document):
def autoname(self): def autoname(self):
self.doc.name = make_autoname(self.doc.fiscal_year + "/" + self.doc.holiday_list_name + "/.###") self.name = make_autoname(self.fiscal_year + "/" + self.holiday_list_name + "/.###")
def validate(self): def validate(self):
self.update_default_holiday_list() self.update_default_holiday_list()
@ -25,20 +25,20 @@ class HolidayList(Document):
last_idx = max([cint(d.idx) for d in self.doclist.get( last_idx = max([cint(d.idx) for d in self.doclist.get(
{"parentfield": "holiday_list_details"})] or [0,]) {"parentfield": "holiday_list_details"})] or [0,])
for i, d in enumerate(date_list): for i, d in enumerate(date_list):
ch = self.doc.append('holiday_list_details', {}) ch = self.append('holiday_list_details', {})
ch.description = self.doc.weekly_off ch.description = self.weekly_off
ch.holiday_date = d ch.holiday_date = d
ch.idx = last_idx + i + 1 ch.idx = last_idx + i + 1
def validate_values(self): def validate_values(self):
if not self.doc.fiscal_year: if not self.fiscal_year:
throw(_("Please select Fiscal Year")) throw(_("Please select Fiscal Year"))
if not self.doc.weekly_off: if not self.weekly_off:
throw(_("Please select weekly off day")) throw(_("Please select weekly off day"))
def get_fy_start_end_dates(self): def get_fy_start_end_dates(self):
return frappe.db.sql("""select year_start_date, year_end_date return frappe.db.sql("""select year_start_date, year_end_date
from `tabFiscal Year` where name=%s""", (self.doc.fiscal_year,))[0] from `tabFiscal Year` where name=%s""", (self.fiscal_year,))[0]
def get_weekly_off_date_list(self, year_start_date, year_end_date): def get_weekly_off_date_list(self, year_start_date, year_end_date):
from frappe.utils import getdate from frappe.utils import getdate
@ -49,7 +49,7 @@ class HolidayList(Document):
import calendar import calendar
date_list = [] date_list = []
weekday = getattr(calendar, (self.doc.weekly_off).upper()) weekday = getattr(calendar, (self.weekly_off).upper())
reference_date = year_start_date + relativedelta.relativedelta(weekday=weekday) reference_date = year_start_date + relativedelta.relativedelta(weekday=weekday)
while reference_date <= year_end_date: while reference_date <= year_end_date:
@ -63,4 +63,4 @@ class HolidayList(Document):
def update_default_holiday_list(self): def update_default_holiday_list(self):
frappe.db.sql("""update `tabHoliday List` set is_default = 0 frappe.db.sql("""update `tabHoliday List` set is_default = 0
where ifnull(is_default, 0) = 1 and fiscal_year = %s""", (self.doc.fiscal_year,)) where ifnull(is_default, 0) = 1 and fiscal_year = %s""", (self.fiscal_year,))

View File

@ -17,17 +17,17 @@ class HrSettings(Document):
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
set_by_naming_series("Employee", "employee_number", set_by_naming_series("Employee", "employee_number",
self.doc.get("emp_created_by")=="Naming Series", hide_name_field=True) self.get("emp_created_by")=="Naming Series", hide_name_field=True)
def update_birthday_reminders(self): def update_birthday_reminders(self):
original_stop_birthday_reminders = cint(frappe.db.get_value("HR Settings", original_stop_birthday_reminders = cint(frappe.db.get_value("HR Settings",
None, "stop_birthday_reminders")) None, "stop_birthday_reminders"))
# reset birthday reminders # reset birthday reminders
if cint(self.doc.stop_birthday_reminders) != original_stop_birthday_reminders: if cint(self.stop_birthday_reminders) != original_stop_birthday_reminders:
frappe.db.sql("""delete from `tabEvent` where repeat_on='Every Year' and ref_type='Employee'""") frappe.db.sql("""delete from `tabEvent` where repeat_on='Every Year' and ref_type='Employee'""")
if not self.doc.stop_birthday_reminders: if not self.stop_birthday_reminders:
for employee in frappe.db.sql_list("""select name from `tabEmployee` where status='Active' and for employee in frappe.db.sql_list("""select name from `tabEmployee` where status='Active' and
ifnull(date_of_birth, '')!=''"""): ifnull(date_of_birth, '')!=''"""):
frappe.get_obj("Employee", employee).update_dob_event() frappe.get_obj("Employee", employee).update_dob_event()

View File

@ -19,10 +19,10 @@ class JobsMailbox(POP3Mailbox):
"name") "name")
if name: if name:
applicant = frappe.bean("Job Applicant", name) applicant = frappe.bean("Job Applicant", name)
if applicant.doc.status!="Rejected": if applicant.status!="Rejected":
applicant.doc.status = "Open" applicant.status = "Open"
applicant.ignore_permissions = True applicant.ignore_permissions = True
applicant.doc.save() applicant.save()
else: else:
name = (mail.from_real_name and (mail.from_real_name + " - ") or "") \ name = (mail.from_real_name and (mail.from_real_name + " - ") or "") \
+ mail.from_email + mail.from_email
@ -40,7 +40,7 @@ class JobsMailbox(POP3Mailbox):
mail.save_attachments_in_doc(applicant.doc) mail.save_attachments_in_doc(applicant.doc)
_make(content=mail.content, sender=mail.from_email, subject=mail.subject or "No Subject", _make(content=mail.content, sender=mail.from_email, subject=mail.subject or "No Subject",
doctype="Job Applicant", name=applicant.doc.name, sent_or_received="Received") doctype="Job Applicant", name=applicant.name, sent_or_received="Received")
def get_job_applications(): def get_job_applications():
if cint(frappe.db.get_value('Jobs Email Settings', None, 'extract_emails')): if cint(frappe.db.get_value('Jobs Email Settings', None, 'extract_emails')):

View File

@ -29,8 +29,8 @@ class LeaveAllocation(Document):
def validate_new_leaves_allocated_value(self): def validate_new_leaves_allocated_value(self):
"""validate that leave allocation is in multiples of 0.5""" """validate that leave allocation is in multiples of 0.5"""
if flt(self.doc.new_leaves_allocated) % 0.5: if flt(self.new_leaves_allocated) % 0.5:
guess = round(flt(self.doc.new_leaves_allocated) * 2.0) / 2.0 guess = round(flt(self.new_leaves_allocated) * 2.0) / 2.0
msgprint("""New Leaves Allocated should be a multiple of 0.5. msgprint("""New Leaves Allocated should be a multiple of 0.5.
Perhaps you should enter %s or %s""" % (guess, guess + 0.5), Perhaps you should enter %s or %s""" % (guess, guess + 0.5),
@ -40,25 +40,25 @@ class LeaveAllocation(Document):
"""check whether leave for same type is already allocated or not""" """check whether leave for same type is already allocated or not"""
leave_allocation = frappe.db.sql("""select name from `tabLeave Allocation` leave_allocation = frappe.db.sql("""select name from `tabLeave Allocation`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""", where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, self.doc.fiscal_year)) (self.employee, self.leave_type, self.fiscal_year))
if leave_allocation: if leave_allocation:
msgprint("""%s is already allocated to Employee: %s for Fiscal Year: %s. msgprint("""%s is already allocated to Employee: %s for Fiscal Year: %s.
Please refere Leave Allocation: \ Please refere Leave Allocation: \
<a href="#Form/Leave Allocation/%s">%s</a>""" % \ <a href="#Form/Leave Allocation/%s">%s</a>""" % \
(self.doc.leave_type, self.doc.employee, self.doc.fiscal_year, (self.leave_type, self.employee, self.fiscal_year,
leave_allocation[0][0], leave_allocation[0][0]), raise_exception=1) leave_allocation[0][0], leave_allocation[0][0]), raise_exception=1)
def validate_new_leaves_allocated(self): def validate_new_leaves_allocated(self):
"""check if Total Leaves Allocated >= Leave Applications""" """check if Total Leaves Allocated >= Leave Applications"""
self.doc.total_leaves_allocated = flt(self.doc.carry_forwarded_leaves) + \ self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + \
flt(self.doc.new_leaves_allocated) flt(self.new_leaves_allocated)
leaves_applied = self.get_leaves_applied(self.doc.fiscal_year) leaves_applied = self.get_leaves_applied(self.fiscal_year)
if leaves_applied > self.doc.total_leaves_allocated: if leaves_applied > self.total_leaves_allocated:
expected_new_leaves = flt(self.doc.new_leaves_allocated) + \ expected_new_leaves = flt(self.new_leaves_allocated) + \
(leaves_applied - self.doc.total_leaves_allocated) (leaves_applied - self.total_leaves_allocated)
msgprint("""Employee: %s has already applied for %s leaves. msgprint("""Employee: %s has already applied for %s leaves.
Hence, New Leaves Allocated should be atleast %s""" % \ Hence, New Leaves Allocated should be atleast %s""" % \
(self.doc.employee, leaves_applied, expected_new_leaves), (self.employee, leaves_applied, expected_new_leaves),
raise_exception=1) raise_exception=1)
def get_leave_bal(self, prev_fyear): def get_leave_bal(self, prev_fyear):
@ -68,40 +68,40 @@ class LeaveAllocation(Document):
leaves_applied = frappe.db.sql("""select SUM(ifnull(total_leave_days, 0)) leaves_applied = frappe.db.sql("""select SUM(ifnull(total_leave_days, 0))
from `tabLeave Application` where employee=%s and leave_type=%s from `tabLeave Application` where employee=%s and leave_type=%s
and fiscal_year=%s and docstatus=1""", and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, fiscal_year)) (self.employee, self.leave_type, fiscal_year))
return leaves_applied and flt(leaves_applied[0][0]) or 0 return leaves_applied and flt(leaves_applied[0][0]) or 0
def get_leaves_allocated(self, fiscal_year): def get_leaves_allocated(self, fiscal_year):
leaves_allocated = frappe.db.sql("""select SUM(ifnull(total_leaves_allocated, 0)) leaves_allocated = frappe.db.sql("""select SUM(ifnull(total_leaves_allocated, 0))
from `tabLeave Allocation` where employee=%s and leave_type=%s from `tabLeave Allocation` where employee=%s and leave_type=%s
and fiscal_year=%s and docstatus=1 and name!=%s""", and fiscal_year=%s and docstatus=1 and name!=%s""",
(self.doc.employee, self.doc.leave_type, fiscal_year, self.doc.name)) (self.employee, self.leave_type, fiscal_year, self.name))
return leaves_allocated and flt(leaves_allocated[0][0]) or 0 return leaves_allocated and flt(leaves_allocated[0][0]) or 0
def allow_carry_forward(self): def allow_carry_forward(self):
"""check whether carry forward is allowed or not for this leave type""" """check whether carry forward is allowed or not for this leave type"""
cf = frappe.db.sql("""select is_carry_forward from `tabLeave Type` where name = %s""", cf = frappe.db.sql("""select is_carry_forward from `tabLeave Type` where name = %s""",
self.doc.leave_type) self.leave_type)
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.doc,'carry_forward',0) frappe.db.set(self.doc,'carry_forward',0)
msgprint("Sorry! You cannot carry forward %s" % (self.doc.leave_type), msgprint("Sorry! You cannot carry forward %s" % (self.leave_type),
raise_exception=1) raise_exception=1)
def get_carry_forwarded_leaves(self): def get_carry_forwarded_leaves(self):
if self.doc.carry_forward: if self.carry_forward:
self.allow_carry_forward() self.allow_carry_forward()
prev_fiscal_year = frappe.db.sql("""select name from `tabFiscal Year` prev_fiscal_year = frappe.db.sql("""select name from `tabFiscal Year`
where year_start_date = (select date_add(year_start_date, interval -1 year) where year_start_date = (select date_add(year_start_date, interval -1 year)
from `tabFiscal Year` where name=%s) from `tabFiscal Year` where name=%s)
order by name desc limit 1""", self.doc.fiscal_year) order by name desc limit 1""", self.fiscal_year)
prev_fiscal_year = prev_fiscal_year and prev_fiscal_year[0][0] or '' prev_fiscal_year = prev_fiscal_year and prev_fiscal_year[0][0] or ''
prev_bal = 0 prev_bal = 0
if prev_fiscal_year and cint(self.doc.carry_forward) == 1: if prev_fiscal_year and cint(self.carry_forward) == 1:
prev_bal = self.get_leave_bal(prev_fiscal_year) prev_bal = self.get_leave_bal(prev_fiscal_year)
ret = { ret = {
'carry_forwarded_leaves': prev_bal, 'carry_forwarded_leaves': prev_bal,
'total_leaves_allocated': flt(prev_bal) + flt(self.doc.new_leaves_allocated) 'total_leaves_allocated': flt(prev_bal) + flt(self.new_leaves_allocated)
} }
return ret return ret
@ -113,12 +113,12 @@ class LeaveAllocation(Document):
def check_for_leave_application(self): def check_for_leave_application(self):
exists = frappe.db.sql("""select name from `tabLeave Application` exists = frappe.db.sql("""select name from `tabLeave Application`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""", where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, self.doc.fiscal_year)) (self.employee, self.leave_type, self.fiscal_year))
if exists: if exists:
msgprint("""Cannot cancel this Leave Allocation as \ msgprint("""Cannot cancel this Leave Allocation as \
Employee : %s has already applied for %s. Employee : %s has already applied for %s.
Please check Leave Application: \ Please check Leave Application: \
<a href="#Form/Leave Application/%s">%s</a>""" % \ <a href="#Form/Leave Application/%s">%s</a>""" % \
(self.doc.employee, self.doc.leave_type, exists[0][0], exists[0][0])) (self.employee, self.leave_type, exists[0][0], exists[0][0]))
raise Exception raise Exception

View File

@ -17,8 +17,8 @@ class LeaveApproverIdentityError(frappe.ValidationError): pass
from frappe.model.controller import DocListController from frappe.model.controller import DocListController
class LeaveApplication(DocListController): class LeaveApplication(DocListController):
def setup(self): def setup(self):
if frappe.db.exists(self.doc.doctype, self.doc.name): if frappe.db.exists(self.doctype, self.name):
self.previous_doc = frappe.doc(self.doc.doctype, self.doc.name) self.previous_doc = frappe.doc(self.doctype, self.name)
else: else:
self.previous_doc = None self.previous_doc = None
@ -32,22 +32,22 @@ class LeaveApplication(DocListController):
self.validate_leave_approver() self.validate_leave_approver()
def on_update(self): def on_update(self):
if (not self.previous_doc and self.doc.leave_approver) or (self.previous_doc and \ if (not self.previous_doc and self.leave_approver) or (self.previous_doc and \
self.doc.status == "Open" and self.previous_doc.leave_approver != self.doc.leave_approver): self.status == "Open" and self.previous_doc.leave_approver != self.leave_approver):
# notify leave approver about creation # notify leave approver about creation
self.notify_leave_approver() self.notify_leave_approver()
elif self.previous_doc and \ elif self.previous_doc and \
self.previous_doc.status == "Open" and self.doc.status == "Rejected": self.previous_doc.status == "Open" and self.status == "Rejected":
# notify employee about rejection # notify employee about rejection
self.notify_employee(self.doc.status) self.notify_employee(self.status)
def on_submit(self): def on_submit(self):
if self.doc.status != "Approved": if self.status != "Approved":
frappe.msgprint("""Only Leave Applications with status 'Approved' can be Submitted.""", frappe.msgprint("""Only Leave Applications with status 'Approved' can be Submitted.""",
raise_exception=True) raise_exception=True)
# notify leave applier about approval # notify leave applier about approval
self.notify_employee(self.doc.status) self.notify_employee(self.status)
def on_cancel(self): def on_cancel(self):
# notify leave applier about cancellation # notify leave applier about cancellation
@ -56,8 +56,8 @@ class LeaveApplication(DocListController):
def show_block_day_warning(self): def show_block_day_warning(self):
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
block_dates = get_applicable_block_dates(self.doc.from_date, self.doc.to_date, block_dates = get_applicable_block_dates(self.from_date, self.to_date,
self.doc.employee, self.doc.company, all_lists=True) self.employee, self.company, all_lists=True)
if block_dates: if block_dates:
frappe.msgprint(_("Warning: Leave application contains following block dates") + ":") frappe.msgprint(_("Warning: Leave application contains following block dates") + ":")
@ -67,30 +67,30 @@ class LeaveApplication(DocListController):
def validate_block_days(self): def validate_block_days(self):
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
block_dates = get_applicable_block_dates(self.doc.from_date, self.doc.to_date, block_dates = get_applicable_block_dates(self.from_date, self.to_date,
self.doc.employee, self.doc.company) self.employee, self.company)
if block_dates: if block_dates:
if self.doc.status == "Approved": if self.status == "Approved":
frappe.msgprint(_("Cannot approve leave as you are not authorized to approve leaves on Block Dates.")) frappe.msgprint(_("Cannot approve leave as you are not authorized to approve leaves on Block Dates."))
raise LeaveDayBlockedError raise LeaveDayBlockedError
def get_holidays(self): def get_holidays(self):
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2, `tabEmployee` e1 tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2, `tabEmployee` e1
where e1.name = %s and h1.parent = h2.name and e1.holiday_list = h2.name where e1.name = %s and h1.parent = h2.name and e1.holiday_list = h2.name
and h1.holiday_date between %s and %s""", (self.doc.employee, self.doc.from_date, self.doc.to_date)) and h1.holiday_date between %s and %s""", (self.employee, self.from_date, self.to_date))
if not tot_hol: if not tot_hol:
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2 tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2
where h1.parent = h2.name and h1.holiday_date between %s and %s where h1.parent = h2.name and h1.holiday_date between %s and %s
and ifnull(h2.is_default,0) = 1 and h2.fiscal_year = %s""", and ifnull(h2.is_default,0) = 1 and h2.fiscal_year = %s""",
(self.doc.from_date, self.doc.to_date, self.doc.fiscal_year)) (self.from_date, self.to_date, self.fiscal_year))
return tot_hol and flt(tot_hol[0][0]) or 0 return tot_hol and flt(tot_hol[0][0]) or 0
def get_total_leave_days(self): def get_total_leave_days(self):
"""Calculates total leave days based on input and holidays""" """Calculates total leave days based on input and holidays"""
ret = {'total_leave_days' : 0.5} ret = {'total_leave_days' : 0.5}
if not self.doc.half_day: if not self.half_day:
tot_days = date_diff(self.doc.to_date, self.doc.from_date) + 1 tot_days = date_diff(self.to_date, self.from_date) + 1
holidays = self.get_holidays() holidays = self.get_holidays()
ret = { ret = {
'total_leave_days' : flt(tot_days)-flt(holidays) 'total_leave_days' : flt(tot_days)-flt(holidays)
@ -98,33 +98,33 @@ class LeaveApplication(DocListController):
return ret return ret
def validate_to_date(self): def validate_to_date(self):
if self.doc.from_date and self.doc.to_date and \ if self.from_date and self.to_date and \
(getdate(self.doc.to_date) < getdate(self.doc.from_date)): (getdate(self.to_date) < getdate(self.from_date)):
msgprint("To date cannot be before from date") msgprint("To date cannot be before from date")
raise Exception raise Exception
def validate_balance_leaves(self): def validate_balance_leaves(self):
if self.doc.from_date and self.doc.to_date: if self.from_date and self.to_date:
self.doc.total_leave_days = self.get_total_leave_days()["total_leave_days"] self.total_leave_days = self.get_total_leave_days()["total_leave_days"]
if self.doc.total_leave_days == 0: if self.total_leave_days == 0:
msgprint(_("The day(s) on which you are applying for leave coincide with holiday(s). You need not apply for leave."), msgprint(_("The day(s) on which you are applying for leave coincide with holiday(s). You need not apply for leave."),
raise_exception=1) raise_exception=1)
if not is_lwp(self.doc.leave_type): if not is_lwp(self.leave_type):
self.doc.leave_balance = get_leave_balance(self.doc.employee, self.leave_balance = get_leave_balance(self.employee,
self.doc.leave_type, self.doc.fiscal_year)["leave_balance"] self.leave_type, self.fiscal_year)["leave_balance"]
if self.doc.status != "Rejected" \ if self.status != "Rejected" \
and self.doc.leave_balance - self.doc.total_leave_days < 0: and self.leave_balance - self.total_leave_days < 0:
#check if this leave type allow the remaining balance to be in negative. If yes then warn the user and continue to save else warn the user and don't save. #check if this leave type allow the remaining balance to be in negative. If yes then warn the user and continue to save else warn the user and don't save.
msgprint("There is not enough leave balance for Leave Type: %s" % \ msgprint("There is not enough leave balance for Leave Type: %s" % \
(self.doc.leave_type,), (self.leave_type,),
raise_exception=not(frappe.db.get_value("Leave Type", self.doc.leave_type,"allow_negative") or None)) raise_exception=not(frappe.db.get_value("Leave Type", self.leave_type,"allow_negative") or None))
def validate_leave_overlap(self): def validate_leave_overlap(self):
if not self.doc.name: if not self.name:
self.doc.name = "New Leave Application" self.name = "New Leave Application"
for d in frappe.db.sql("""select name, leave_type, posting_date, for d in frappe.db.sql("""select name, leave_type, posting_date,
from_date, to_date from_date, to_date
@ -136,45 +136,45 @@ class LeaveApplication(DocListController):
and (from_date between %(from_date)s and %(to_date)s and (from_date between %(from_date)s and %(to_date)s
or to_date between %(from_date)s and %(to_date)s or to_date between %(from_date)s and %(to_date)s
or %(from_date)s between from_date and to_date) or %(from_date)s between from_date and to_date)
and name != %(name)s""", self.doc.fields, as_dict = 1): and name != %(name)s""", self.fields, as_dict = 1):
msgprint("Employee : %s has already applied for %s between %s and %s on %s. Please refer Leave Application : <a href=\"#Form/Leave Application/%s\">%s</a>" % (self.doc.employee, cstr(d['leave_type']), formatdate(d['from_date']), formatdate(d['to_date']), formatdate(d['posting_date']), d['name'], d['name']), raise_exception = OverlapError) msgprint("Employee : %s has already applied for %s between %s and %s on %s. Please refer Leave Application : <a href=\"#Form/Leave Application/%s\">%s</a>" % (self.employee, cstr(d['leave_type']), formatdate(d['from_date']), formatdate(d['to_date']), formatdate(d['posting_date']), d['name'], d['name']), raise_exception = OverlapError)
def validate_max_days(self): def validate_max_days(self):
max_days = frappe.db.get_value("Leave Type", self.doc.leave_type, "max_days_allowed") max_days = frappe.db.get_value("Leave Type", self.leave_type, "max_days_allowed")
if max_days and self.doc.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("Sorry ! You cannot apply for %s for more than %s days" %
(self.doc.leave_type, max_days)) (self.leave_type, max_days))
def validate_leave_approver(self): def validate_leave_approver(self):
employee = frappe.bean("Employee", self.doc.employee) employee = frappe.bean("Employee", self.employee)
leave_approvers = [l.leave_approver for l in leave_approvers = [l.leave_approver for l in
employee.get("employee_leave_approvers")] employee.get("employee_leave_approvers")]
if len(leave_approvers) and self.doc.leave_approver not in leave_approvers: if len(leave_approvers) and self.leave_approver not in leave_approvers:
msgprint(("[" + _("For Employee") + ' "' + self.doc.employee + '"] ' msgprint(("[" + _("For Employee") + ' "' + self.employee + '"] '
+ _("Leave Approver can be one of") + ": " + _("Leave Approver can be one of") + ": "
+ comma_or(leave_approvers)), raise_exception=InvalidLeaveApproverError) + comma_or(leave_approvers)), raise_exception=InvalidLeaveApproverError)
elif self.doc.leave_approver and not frappe.db.sql("""select name from `tabUserRole` elif self.leave_approver and not frappe.db.sql("""select name from `tabUserRole`
where parent=%s and role='Leave Approver'""", self.doc.leave_approver): where parent=%s and role='Leave Approver'""", self.leave_approver):
msgprint(get_fullname(self.doc.leave_approver) + ": " \ msgprint(get_fullname(self.leave_approver) + ": " \
+ _("does not have role 'Leave Approver'"), raise_exception=InvalidLeaveApproverError) + _("does not have role 'Leave Approver'"), raise_exception=InvalidLeaveApproverError)
elif self.doc.docstatus==1 and len(leave_approvers) and self.doc.leave_approver != frappe.session.user: elif self.docstatus==1 and len(leave_approvers) and self.leave_approver != frappe.session.user:
msgprint(_("Only the selected Leave Approver can submit this Leave Application"), msgprint(_("Only the selected Leave Approver can submit this Leave Application"),
raise_exception=LeaveApproverIdentityError) raise_exception=LeaveApproverIdentityError)
def notify_employee(self, status): def notify_employee(self, status):
employee = frappe.doc("Employee", self.doc.employee) employee = frappe.doc("Employee", self.employee)
if not employee.user_id: if not employee.user_id:
return return
def _get_message(url=False): def _get_message(url=False):
if url: if url:
name = get_url_to_form(self.doc.doctype, self.doc.name) name = get_url_to_form(self.doctype, self.name)
else: else:
name = self.doc.name name = self.name
return (_("Leave Application") + ": %s - %s") % (name, _(status)) return (_("Leave Application") + ": %s - %s") % (name, _(status))
@ -186,21 +186,21 @@ class LeaveApplication(DocListController):
}) })
def notify_leave_approver(self): def notify_leave_approver(self):
employee = frappe.doc("Employee", self.doc.employee) employee = frappe.doc("Employee", self.employee)
def _get_message(url=False): def _get_message(url=False):
name = self.doc.name name = self.name
employee_name = cstr(employee.employee_name) employee_name = cstr(employee.employee_name)
if url: if url:
name = get_url_to_form(self.doc.doctype, self.doc.name) name = get_url_to_form(self.doctype, self.name)
employee_name = get_url_to_form("Employee", self.doc.employee, label=employee_name) employee_name = get_url_to_form("Employee", self.employee, label=employee_name)
return (_("New Leave Application") + ": %s - " + _("Employee") + ": %s") % (name, employee_name) return (_("New Leave Application") + ": %s - " + _("Employee") + ": %s") % (name, employee_name)
self.notify({ self.notify({
# for post in messages # for post in messages
"message": _get_message(url=True), "message": _get_message(url=True),
"message_to": self.doc.leave_approver, "message_to": self.leave_approver,
# for email # for email
"subject": _get_message() "subject": _get_message()
@ -210,7 +210,7 @@ class LeaveApplication(DocListController):
args = frappe._dict(args) args = frappe._dict(args)
from frappe.core.page.messages.messages import post from frappe.core.page.messages.messages import post
post({"txt": args.message, "contact": args.message_to, "subject": args.subject, post({"txt": args.message, "contact": args.message_to, "subject": args.subject,
"notify": cint(self.doc.follow_via_email)}) "notify": cint(self.follow_via_email)})
@frappe.whitelist() @frappe.whitelist()
def get_leave_balance(employee, leave_type, fiscal_year): def get_leave_balance(employee, leave_type, fiscal_year):

View File

@ -33,8 +33,8 @@ class TestLeaveApplication(unittest.TestCase):
def get_application(self, doclist): def get_application(self, doclist):
application = frappe.bean(copy=doclist) application = frappe.bean(copy=doclist)
application.doc.from_date = "2013-01-01" application.from_date = "2013-01-01"
application.doc.to_date = "2013-01-05" application.to_date = "2013-01-05"
return application return application
def test_block_list(self): def test_block_list(self):
@ -48,7 +48,7 @@ class TestLeaveApplication(unittest.TestCase):
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.insert() application.insert()
application.doc.status = "Approved" application.status = "Approved"
self.assertRaises(LeaveDayBlockedError, application.submit) self.assertRaises(LeaveDayBlockedError, application.submit)
frappe.set_user("test1@example.com") frappe.set_user("test1@example.com")
@ -69,11 +69,11 @@ class TestLeaveApplication(unittest.TestCase):
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com" application.leave_approver = "test2@example.com"
application.insert() application.insert()
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com" application.leave_approver = "test2@example.com"
self.assertRaises(OverlapError, application.insert) self.assertRaises(OverlapError, application.insert)
def test_global_block_list(self): def test_global_block_list(self):
@ -84,7 +84,7 @@ class TestLeaveApplication(unittest.TestCase):
add_role("test@example.com", "Leave Approver") add_role("test@example.com", "Leave Approver")
application = self.get_application(test_records[3]) application = self.get_application(test_records[3])
application.doc.leave_approver = "test@example.com" application.leave_approver = "test@example.com"
frappe.db.set_value("Leave Block List", "_Test Leave Block List", frappe.db.set_value("Leave Block List", "_Test Leave Block List",
"applies_to_all_departments", 1) "applies_to_all_departments", 1)
@ -95,7 +95,7 @@ class TestLeaveApplication(unittest.TestCase):
application.insert() application.insert()
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
application.doc.status = "Approved" application.status = "Approved"
self.assertRaises(LeaveDayBlockedError, application.submit) self.assertRaises(LeaveDayBlockedError, application.submit)
frappe.db.set_value("Leave Block List", "_Test Leave Block List", frappe.db.set_value("Leave Block List", "_Test Leave Block List",
@ -120,14 +120,14 @@ class TestLeaveApplication(unittest.TestCase):
# create leave application as Employee # create leave application as Employee
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.doc.leave_approver = "test1@example.com" application.leave_approver = "test1@example.com"
application.insert() application.insert()
# submit leave application by Leave Approver # submit leave application by Leave Approver
frappe.set_user("test1@example.com") frappe.set_user("test1@example.com")
application.doc.status = "Approved" application.status = "Approved"
application.submit() application.submit()
self.assertEqual(frappe.db.get_value("Leave Application", application.doc.name, self.assertEqual(frappe.db.get_value("Leave Application", application.name,
"docstatus"), 1) "docstatus"), 1)
def _test_leave_approval_invalid_leave_approver_insert(self): def _test_leave_approval_invalid_leave_approver_insert(self):
@ -143,7 +143,7 @@ class TestLeaveApplication(unittest.TestCase):
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
application.doc.leave_approver = "test1@example.com" application.leave_approver = "test1@example.com"
self.assertRaises(InvalidLeaveApproverError, application.insert) self.assertRaises(InvalidLeaveApproverError, application.insert)
frappe.db.sql("""delete from `tabEmployee Leave Approver` where parent=%s""", frappe.db.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
@ -157,10 +157,10 @@ class TestLeaveApplication(unittest.TestCase):
# but submit as invalid leave approver - should raise exception # but submit as invalid leave approver - should raise exception
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com" application.leave_approver = "test2@example.com"
application.insert() application.insert()
frappe.set_user("test1@example.com") frappe.set_user("test1@example.com")
application.doc.status = "Approved" application.status = "Approved"
from erpnext.hr.doctype.leave_application.leave_application import LeaveApproverIdentityError from erpnext.hr.doctype.leave_application.leave_application import LeaveApproverIdentityError
self.assertRaises(LeaveApproverIdentityError, application.submit) self.assertRaises(LeaveApproverIdentityError, application.submit)
@ -177,14 +177,14 @@ class TestLeaveApplication(unittest.TestCase):
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com" application.leave_approver = "test2@example.com"
application.insert() application.insert()
# change to valid leave approver and try to submit leave application # change to valid leave approver and try to submit leave application
frappe.set_user("test2@example.com") frappe.set_user("test2@example.com")
application.doc.status = "Approved" application.status = "Approved"
application.submit() application.submit()
self.assertEqual(frappe.db.get_value("Leave Application", application.doc.name, self.assertEqual(frappe.db.get_value("Leave Application", application.name,
"docstatus"), 1) "docstatus"), 1)
frappe.db.sql("""delete from `tabEmployee Leave Approver` where parent=%s""", frappe.db.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",

View File

@ -16,7 +16,7 @@ class LeaveBlockList(Document):
dates = [] dates = []
for d in self.doclist.get({"doctype":"Leave Block List Date"}): for d in self.doclist.get({"doctype":"Leave Block List Date"}):
# validate fiscal year # validate fiscal year
validate_fiscal_year(d.block_date, self.doc.year, _("Block Date")) validate_fiscal_year(d.block_date, self.year, _("Block Date"))
# date is not repeated # date is not repeated
if d.block_date in dates: if d.block_date in dates:

View File

@ -20,7 +20,7 @@ class LeaveControlPanel(Document):
def get_employees(self): def get_employees(self):
lst1 = [[self.doc.employee_type,"employment_type"],[self.doc.branch,"branch"],[self.doc.designation,"designation"],[self.doc.department, "department"],[self.doc.grade,"grade"]] lst1 = [[self.employee_type,"employment_type"],[self.branch,"branch"],[self.designation,"designation"],[self.department, "department"],[self.grade,"grade"]]
condition = "where " condition = "where "
flag = 0 flag = 0
for l in lst1: for l in lst1:
@ -54,11 +54,11 @@ class LeaveControlPanel(Document):
la.set("__islocal", 1) la.set("__islocal", 1)
la.employee = cstr(d[0]) la.employee = cstr(d[0])
la.employee_name = frappe.db.get_value('Employee',cstr(d[0]),'employee_name') la.employee_name = frappe.db.get_value('Employee',cstr(d[0]),'employee_name')
la.leave_type = self.doc.leave_type la.leave_type = self.leave_type
la.fiscal_year = self.doc.fiscal_year la.fiscal_year = self.fiscal_year
la.posting_date = nowdate() la.posting_date = nowdate()
la.carry_forward = cint(self.doc.carry_forward) la.carry_forward = cint(self.carry_forward)
la.new_leaves_allocated = flt(self.doc.no_of_days) la.new_leaves_allocated = flt(self.no_of_days)
la.docstatus = 1 la.docstatus = 1
la.save() la.save()
leave_allocated_for.append(d[0]) leave_allocated_for.append(d[0])

View File

@ -35,14 +35,14 @@ class SalaryManager(Document):
cond = '' cond = ''
for f in ['company', 'branch', 'department', 'designation', 'grade']: for f in ['company', 'branch', 'department', 'designation', 'grade']:
if self.doc.fields.get(f): if self.get(f):
cond += " and t1." + f + " = '" + self.doc.fields.get(f).replace("'", "\'") + "'" cond += " and t1." + f + " = '" + self.get(f).replace("'", "\'") + "'"
return cond return cond
def get_joining_releiving_condition(self): def get_joining_releiving_condition(self):
m = self.get_month_details(self.doc.fiscal_year, self.doc.month) m = self.get_month_details(self.fiscal_year, self.month)
cond = """ cond = """
and ifnull(t1.date_of_joining, '0000-00-00') <= '%(month_end_date)s' and ifnull(t1.date_of_joining, '0000-00-00') <= '%(month_end_date)s'
and ifnull(t1.relieving_date, '2199-12-31') >= '%(month_start_date)s' and ifnull(t1.relieving_date, '2199-12-31') >= '%(month_start_date)s'
@ -52,7 +52,7 @@ class SalaryManager(Document):
def check_mandatory(self): def check_mandatory(self):
for f in ['company', 'month', 'fiscal_year']: for f in ['company', 'month', 'fiscal_year']:
if not self.doc.fields[f]: if not self.fields[f]:
msgprint("Please select %s to proceed" % f, raise_exception=1) msgprint("Please select %s to proceed" % f, raise_exception=1)
@ -85,17 +85,17 @@ class SalaryManager(Document):
for emp in emp_list: for emp in emp_list:
if not frappe.db.sql("""select name from `tabSalary Slip` if not frappe.db.sql("""select name from `tabSalary Slip`
where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s
""", (emp[0], self.doc.month, self.doc.fiscal_year, self.doc.company)): """, (emp[0], self.month, self.fiscal_year, self.company)):
ss = frappe.bean({ ss = frappe.bean({
"doctype": "Salary Slip", "doctype": "Salary Slip",
"fiscal_year": self.doc.fiscal_year, "fiscal_year": self.fiscal_year,
"employee": emp[0], "employee": emp[0],
"month": self.doc.month, "month": self.month,
"email_check": self.doc.send_email, "email_check": self.send_email,
"company": self.doc.company, "company": self.company,
}) })
ss.insert() ss.insert()
ss_list.append(ss.doc.name) ss_list.append(ss.name)
return self.create_log(ss_list) return self.create_log(ss_list)
@ -117,7 +117,7 @@ class SalaryManager(Document):
ss_list = frappe.db.sql(""" ss_list = frappe.db.sql("""
select t1.name from `tabSalary Slip` t1 select t1.name from `tabSalary Slip` t1
where t1.docstatus = 0 and month = %s and fiscal_year = %s %s where t1.docstatus = 0 and month = %s and fiscal_year = %s %s
""" % ('%s', '%s', cond), (self.doc.month, self.doc.fiscal_year)) """ % ('%s', '%s', cond), (self.month, self.fiscal_year))
return ss_list return ss_list
@ -130,8 +130,8 @@ class SalaryManager(Document):
for ss in ss_list: for ss in ss_list:
ss_obj = get_obj("Salary Slip",ss[0],with_children=1) ss_obj = get_obj("Salary Slip",ss[0],with_children=1)
try: try:
frappe.db.set(ss_obj.doc, 'email_check', cint(self.doc.send_mail)) frappe.db.set(ss_obj.doc, 'email_check', cint(self.send_mail))
if cint(self.doc.send_email) == 1: if cint(self.send_email) == 1:
ss_obj.send_mail_funct() ss_obj.send_mail_funct()
frappe.db.set(ss_obj.doc, 'docstatus', 1) frappe.db.set(ss_obj.doc, 'docstatus', 1)
@ -152,7 +152,7 @@ class SalaryManager(Document):
submitted_ss = list(set(all_ss) - set(not_submitted_ss)) submitted_ss = list(set(all_ss) - set(not_submitted_ss))
if submitted_ss: if submitted_ss:
mail_sent_msg = self.doc.send_email and " (Mail has been sent to the employee)" or "" mail_sent_msg = self.send_email and " (Mail has been sent to the employee)" or ""
log = """ log = """
<b>Submitted Salary Slips%s:</b>\ <b>Submitted Salary Slips%s:</b>\
<br><br> %s <br><br> <br><br> %s <br><br>
@ -179,7 +179,7 @@ class SalaryManager(Document):
tot = frappe.db.sql(""" tot = frappe.db.sql("""
select sum(rounded_total) from `tabSalary Slip` t1 select sum(rounded_total) from `tabSalary Slip` t1
where t1.docstatus = 1 and month = %s and fiscal_year = %s %s where t1.docstatus = 1 and month = %s and fiscal_year = %s %s
""" % ('%s', '%s', cond), (self.doc.month, self.doc.fiscal_year)) """ % ('%s', '%s', cond), (self.month, self.fiscal_year))
return flt(tot[0][0]) return flt(tot[0][0])
@ -189,7 +189,7 @@ class SalaryManager(Document):
get default bank account,default salary acount from company get default bank account,default salary acount from company
""" """
amt = self.get_total_salary() amt = self.get_total_salary()
default_bank_account = frappe.db.get_value("Company", self.doc.company, default_bank_account = frappe.db.get_value("Company", self.company,
"default_bank_account") "default_bank_account")
if not default_bank_account: if not default_bank_account:
msgprint("You can set Default Bank Account in Company master.") msgprint("You can set Default Bank Account in Company master.")

View File

@ -16,10 +16,10 @@ from erpnext.utilities.transaction_base import TransactionBase
class SalarySlip(TransactionBase): class SalarySlip(TransactionBase):
def autoname(self): def autoname(self):
self.doc.name = make_autoname('Sal Slip/' +self.doc.employee + '/.#####') self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
def get_emp_and_leave_details(self): def get_emp_and_leave_details(self):
if self.doc.employee: if self.employee:
self.get_leave_details() self.get_leave_details()
struct = self.check_sal_struct() struct = self.check_sal_struct()
if struct: if struct:
@ -27,10 +27,10 @@ class SalarySlip(TransactionBase):
def check_sal_struct(self): def check_sal_struct(self):
struct = frappe.db.sql("""select name from `tabSalary Structure` struct = frappe.db.sql("""select name from `tabSalary Structure`
where employee=%s and is_active = 'Yes'""", self.doc.employee) where employee=%s and is_active = 'Yes'""", self.employee)
if not struct: if not struct:
msgprint("Please create Salary Structure for employee '%s'" % self.doc.employee) msgprint("Please create Salary Structure for employee '%s'" % self.employee)
self.doc.employee = None self.employee = None
return struct and struct[0][0] or '' return struct and struct[0][0] or ''
def pull_sal_struct(self, struct): def pull_sal_struct(self, struct):
@ -38,21 +38,21 @@ class SalarySlip(TransactionBase):
self.doclist = get_mapped_doclist(struct, self.doclist) self.doclist = get_mapped_doclist(struct, self.doclist)
def pull_emp_details(self): def pull_emp_details(self):
emp = frappe.db.get_value("Employee", self.doc.employee, emp = frappe.db.get_value("Employee", self.employee,
["bank_name", "bank_ac_no", "esic_card_no", "pf_number"], as_dict=1) ["bank_name", "bank_ac_no", "esic_card_no", "pf_number"], as_dict=1)
if emp: if emp:
self.doc.bank_name = emp.bank_name self.bank_name = emp.bank_name
self.doc.bank_account_no = emp.bank_ac_no self.bank_account_no = emp.bank_ac_no
self.doc.esic_no = emp.esic_card_no self.esic_no = emp.esic_card_no
self.doc.pf_no = emp.pf_number self.pf_no = emp.pf_number
def get_leave_details(self, lwp=None): def get_leave_details(self, lwp=None):
if not self.doc.fiscal_year: if not self.fiscal_year:
self.doc.fiscal_year = frappe.get_default("fiscal_year") self.fiscal_year = frappe.get_default("fiscal_year")
if not self.doc.month: if not self.month:
self.doc.month = "%02d" % getdate(nowdate()).month self.month = "%02d" % getdate(nowdate()).month
m = get_obj('Salary Manager').get_month_details(self.doc.fiscal_year, self.doc.month) m = get_obj('Salary Manager').get_month_details(self.fiscal_year, self.month)
holidays = self.get_holidays_for_employee(m) holidays = self.get_holidays_for_employee(m)
if not cint(frappe.db.get_value("HR Settings", "HR Settings", if not cint(frappe.db.get_value("HR Settings", "HR Settings",
@ -64,16 +64,16 @@ class SalarySlip(TransactionBase):
if not lwp: if not lwp:
lwp = self.calculate_lwp(holidays, m) lwp = self.calculate_lwp(holidays, m)
self.doc.total_days_in_month = m['month_days'] self.total_days_in_month = m['month_days']
self.doc.leave_without_pay = lwp self.leave_without_pay = lwp
payment_days = flt(self.get_payment_days(m)) - flt(lwp) payment_days = flt(self.get_payment_days(m)) - flt(lwp)
self.doc.payment_days = payment_days > 0 and payment_days or 0 self.payment_days = payment_days > 0 and payment_days or 0
def get_payment_days(self, m): def get_payment_days(self, m):
payment_days = m['month_days'] payment_days = m['month_days']
emp = frappe.db.sql("select date_of_joining, relieving_date from `tabEmployee` \ emp = frappe.db.sql("select date_of_joining, relieving_date from `tabEmployee` \
where name = %s", self.doc.employee, as_dict=1)[0] where name = %s", self.employee, as_dict=1)[0]
if emp['relieving_date']: if emp['relieving_date']:
if getdate(emp['relieving_date']) > m['month_start_date'] and \ if getdate(emp['relieving_date']) > m['month_start_date'] and \
@ -98,13 +98,13 @@ class SalarySlip(TransactionBase):
from `tabHoliday` t1, tabEmployee t2 from `tabHoliday` t1, tabEmployee t2
where t1.parent = t2.holiday_list and t2.name = %s where t1.parent = t2.holiday_list and t2.name = %s
and t1.holiday_date between %s and %s""", and t1.holiday_date between %s and %s""",
(self.doc.employee, m['month_start_date'], m['month_end_date'])) (self.employee, m['month_start_date'], m['month_end_date']))
if not holidays: if not holidays:
holidays = frappe.db.sql("""select t1.holiday_date holidays = frappe.db.sql("""select t1.holiday_date
from `tabHoliday` t1, `tabHoliday List` t2 from `tabHoliday` t1, `tabHoliday List` t2
where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1 where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1
and t2.fiscal_year = %s and t2.fiscal_year = %s
and t1.holiday_date between %s and %s""", (self.doc.fiscal_year, and t1.holiday_date between %s and %s""", (self.fiscal_year,
m['month_start_date'], m['month_end_date'])) m['month_start_date'], m['month_end_date']))
holidays = [cstr(i[0]) for i in holidays] holidays = [cstr(i[0]) for i in holidays]
return holidays return holidays
@ -122,7 +122,7 @@ class SalarySlip(TransactionBase):
and t1.docstatus = 1 and t1.docstatus = 1
and t1.employee = %s and t1.employee = %s
and %s between from_date and to_date and %s between from_date and to_date
""", (self.doc.employee, dt)) """, (self.employee, dt))
if leave: if leave:
lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1) lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1)
return lwp return lwp
@ -131,11 +131,11 @@ class SalarySlip(TransactionBase):
ret_exist = frappe.db.sql("""select name from `tabSalary Slip` ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
where month = %s and fiscal_year = %s and docstatus != 2 where month = %s and fiscal_year = %s and docstatus != 2
and employee = %s and name != %s""", and employee = %s and name != %s""",
(self.doc.month, self.doc.fiscal_year, self.doc.employee, self.doc.name)) (self.month, self.fiscal_year, self.employee, self.name))
if ret_exist: if ret_exist:
self.doc.employee = '' self.employee = ''
msgprint("Salary Slip of employee '%s' already created for this month" msgprint("Salary Slip of employee '%s' already created for this month"
% self.doc.employee, raise_exception=1) % self.employee, raise_exception=1)
def validate(self): def validate(self):
@ -146,59 +146,59 @@ class SalarySlip(TransactionBase):
len(self.get("deduction_details"))): len(self.get("deduction_details"))):
self.get_emp_and_leave_details() self.get_emp_and_leave_details()
else: else:
self.get_leave_details(self.doc.leave_without_pay) self.get_leave_details(self.leave_without_pay)
if not self.doc.net_pay: if not self.net_pay:
self.calculate_net_pay() self.calculate_net_pay()
company_currency = get_company_currency(self.doc.company) company_currency = get_company_currency(self.company)
self.doc.total_in_words = money_in_words(self.doc.rounded_total, company_currency) self.total_in_words = money_in_words(self.rounded_total, company_currency)
def calculate_earning_total(self): def calculate_earning_total(self):
self.doc.gross_pay = flt(self.doc.arrear_amount) + flt(self.doc.leave_encashment_amount) self.gross_pay = flt(self.arrear_amount) + flt(self.leave_encashment_amount)
for d in self.get("earning_details"): for d in self.get("earning_details"):
if cint(d.e_depends_on_lwp) == 1: if cint(d.e_depends_on_lwp) == 1:
d.e_modified_amount = _round(flt(d.e_amount) * flt(self.doc.payment_days) d.e_modified_amount = _round(flt(d.e_amount) * flt(self.payment_days)
/ cint(self.doc.total_days_in_month), 2) / cint(self.total_days_in_month), 2)
elif not self.doc.payment_days: elif not self.payment_days:
d.e_modified_amount = 0 d.e_modified_amount = 0
else: else:
d.e_modified_amount = d.e_amount d.e_modified_amount = d.e_amount
self.doc.gross_pay += flt(d.e_modified_amount) self.gross_pay += flt(d.e_modified_amount)
def calculate_ded_total(self): def calculate_ded_total(self):
self.doc.total_deduction = 0 self.total_deduction = 0
for d in self.get('deduction_details'): for d in self.get('deduction_details'):
if cint(d.d_depends_on_lwp) == 1: if cint(d.d_depends_on_lwp) == 1:
d.d_modified_amount = _round(flt(d.d_amount) * flt(self.doc.payment_days) d.d_modified_amount = _round(flt(d.d_amount) * flt(self.payment_days)
/ cint(self.doc.total_days_in_month), 2) / cint(self.total_days_in_month), 2)
elif not self.doc.payment_days: elif not self.payment_days:
d.d_modified_amount = 0 d.d_modified_amount = 0
else: else:
d.d_modified_amount = d.d_amount d.d_modified_amount = d.d_amount
self.doc.total_deduction += flt(d.d_modified_amount) self.total_deduction += flt(d.d_modified_amount)
def calculate_net_pay(self): def calculate_net_pay(self):
self.calculate_earning_total() self.calculate_earning_total()
self.calculate_ded_total() self.calculate_ded_total()
self.doc.net_pay = flt(self.doc.gross_pay) - flt(self.doc.total_deduction) self.net_pay = flt(self.gross_pay) - flt(self.total_deduction)
self.doc.rounded_total = _round(self.doc.net_pay) self.rounded_total = _round(self.net_pay)
def on_submit(self): def on_submit(self):
if(self.doc.email_check == 1): if(self.email_check == 1):
self.send_mail_funct() self.send_mail_funct()
def send_mail_funct(self): def send_mail_funct(self):
from frappe.utils.email_lib import sendmail from frappe.utils.email_lib import sendmail
receiver = frappe.db.get_value("Employee", self.doc.employee, "company_email") receiver = frappe.db.get_value("Employee", self.employee, "company_email")
if receiver: if receiver:
subj = 'Salary Slip - ' + cstr(self.doc.month) +'/'+cstr(self.doc.fiscal_year) subj = 'Salary Slip - ' + cstr(self.month) +'/'+cstr(self.fiscal_year)
earn_ret=frappe.db.sql("""select e_type, e_modified_amount from `tabSalary Slip Earning` earn_ret=frappe.db.sql("""select e_type, e_modified_amount from `tabSalary Slip Earning`
where parent = %s""", self.doc.name) where parent = %s""", self.name)
ded_ret=frappe.db.sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction` ded_ret=frappe.db.sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction`
where parent = %s""", self.doc.name) where parent = %s""", self.name)
earn_table = '' earn_table = ''
ded_table = '' ded_table = ''
@ -288,13 +288,13 @@ class SalarySlip(TransactionBase):
<td width='25%%'><b>Net Pay(in words) : </td> <td width='25%%'><b>Net Pay(in words) : </td>
<td colspan = '3' width = '50%%'>%s</b></td> <td colspan = '3' width = '50%%'>%s</b></td>
</tr> </tr>
</table></div>''' % (cstr(letter_head), cstr(self.doc.employee), </table></div>''' % (cstr(letter_head), cstr(self.employee),
cstr(self.doc.employee_name), cstr(self.doc.month), cstr(self.doc.fiscal_year), cstr(self.employee_name), cstr(self.month), cstr(self.fiscal_year),
cstr(self.doc.department), cstr(self.doc.branch), cstr(self.doc.designation), cstr(self.department), cstr(self.branch), cstr(self.designation),
cstr(self.doc.grade), cstr(self.doc.bank_account_no), cstr(self.doc.bank_name), cstr(self.grade), cstr(self.bank_account_no), cstr(self.bank_name),
cstr(self.doc.arrear_amount), cstr(self.doc.payment_days), earn_table, ded_table, cstr(self.arrear_amount), cstr(self.payment_days), earn_table, ded_table,
cstr(flt(self.doc.gross_pay)), cstr(flt(self.doc.total_deduction)), cstr(flt(self.gross_pay)), cstr(flt(self.total_deduction)),
cstr(flt(self.doc.net_pay)), cstr(self.doc.total_in_words)) cstr(flt(self.net_pay)), cstr(self.total_in_words))
sendmail([receiver], subject=subj, msg = msg) sendmail([receiver], subject=subj, msg = msg)
else: else:

View File

@ -11,7 +11,7 @@ class TestSalarySlip(unittest.TestCase):
from erpnext.hr.doctype.leave_application.test_leave_application import test_records as leave_applications from erpnext.hr.doctype.leave_application.test_leave_application import test_records as leave_applications
la = frappe.bean(copy=leave_applications[4]) la = frappe.bean(copy=leave_applications[4])
la.insert() la.insert()
la.doc.status = "Approved" la.status = "Approved"
la.submit() la.submit()
def tearDown(self): def tearDown(self):
@ -21,26 +21,26 @@ class TestSalarySlip(unittest.TestCase):
frappe.db.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 1) frappe.db.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 1)
ss = frappe.bean(copy=test_records[0]) ss = frappe.bean(copy=test_records[0])
ss.insert() ss.insert()
self.assertEquals(ss.doc.total_days_in_month, 31) self.assertEquals(ss.total_days_in_month, 31)
self.assertEquals(ss.doc.payment_days, 30) self.assertEquals(ss.payment_days, 30)
self.assertEquals(ss.doclist[1].e_modified_amount, 14516.13) self.assertEquals(ss.doclist[1].e_modified_amount, 14516.13)
self.assertEquals(ss.doclist[2].e_modified_amount, 500) self.assertEquals(ss.doclist[2].e_modified_amount, 500)
self.assertEquals(ss.doclist[3].d_modified_amount, 100) self.assertEquals(ss.doclist[3].d_modified_amount, 100)
self.assertEquals(ss.doclist[4].d_modified_amount, 48.39) self.assertEquals(ss.doclist[4].d_modified_amount, 48.39)
self.assertEquals(ss.doc.gross_pay, 15016.13) self.assertEquals(ss.gross_pay, 15016.13)
self.assertEquals(ss.doc.net_pay, 14867.74) self.assertEquals(ss.net_pay, 14867.74)
def test_salary_slip_with_holidays_excluded(self): def test_salary_slip_with_holidays_excluded(self):
ss = frappe.bean(copy=test_records[0]) ss = frappe.bean(copy=test_records[0])
ss.insert() ss.insert()
self.assertEquals(ss.doc.total_days_in_month, 30) self.assertEquals(ss.total_days_in_month, 30)
self.assertEquals(ss.doc.payment_days, 29) self.assertEquals(ss.payment_days, 29)
self.assertEquals(ss.doclist[1].e_modified_amount, 14500) self.assertEquals(ss.doclist[1].e_modified_amount, 14500)
self.assertEquals(ss.doclist[2].e_modified_amount, 500) self.assertEquals(ss.doclist[2].e_modified_amount, 500)
self.assertEquals(ss.doclist[3].d_modified_amount, 100) self.assertEquals(ss.doclist[3].d_modified_amount, 100)
self.assertEquals(ss.doclist[4].d_modified_amount, 48.33) self.assertEquals(ss.doclist[4].d_modified_amount, 48.33)
self.assertEquals(ss.doc.gross_pay, 15000) self.assertEquals(ss.gross_pay, 15000)
self.assertEquals(ss.doc.net_pay, 14851.67) self.assertEquals(ss.net_pay, 14851.67)
test_dependencies = ["Leave Application"] test_dependencies = ["Leave Application"]

View File

@ -13,12 +13,12 @@ from frappe.model.document import Document
class SalaryStructure(Document): class SalaryStructure(Document):
def autoname(self): def autoname(self):
self.doc.name = make_autoname(self.doc.employee + '/.SST' + '/.#####') self.name = make_autoname(self.employee + '/.SST' + '/.#####')
def get_employee_details(self): def get_employee_details(self):
ret = {} ret = {}
det = frappe.db.sql("""select employee_name, branch, designation, department, grade det = frappe.db.sql("""select employee_name, branch, designation, department, grade
from `tabEmployee` where name = %s""", self.doc.employee) from `tabEmployee` where name = %s""", self.employee)
if det: if det:
ret = { ret = {
'employee_name': cstr(det[0][0]), 'employee_name': cstr(det[0][0]),
@ -26,7 +26,7 @@ class SalaryStructure(Document):
'designation': cstr(det[0][2]), 'designation': cstr(det[0][2]),
'department': cstr(det[0][3]), 'department': cstr(det[0][3]),
'grade': cstr(det[0][4]), 'grade': cstr(det[0][4]),
'backup_employee': cstr(self.doc.employee) 'backup_employee': cstr(self.employee)
} }
return ret return ret
@ -42,7 +42,7 @@ class SalaryStructure(Document):
def make_table(self, doct_name, tab_fname, tab_name): def make_table(self, doct_name, tab_fname, tab_name):
list1 = frappe.db.sql("select name from `tab%s` where docstatus != 2" % doct_name) list1 = frappe.db.sql("select name from `tab%s` where docstatus != 2" % doct_name)
for li in list1: for li in list1:
child = self.doc.append(tab_fname, {}) child = self.append(tab_fname, {})
if(tab_fname == 'earning_details'): if(tab_fname == 'earning_details'):
child.e_type = cstr(li[0]) child.e_type = cstr(li[0])
child.modified_value = 0 child.modified_value = 0
@ -56,13 +56,13 @@ class SalaryStructure(Document):
def check_existing(self): def check_existing(self):
ret = frappe.db.sql("""select name from `tabSalary Structure` where is_active = 'Yes' ret = frappe.db.sql("""select name from `tabSalary Structure` where is_active = 'Yes'
and employee = %s and name!=%s""", (self.doc.employee,self.doc.name)) and employee = %s and name!=%s""", (self.employee,self.name))
if ret and self.doc.is_active=='Yes': if ret and self.is_active=='Yes':
msgprint(_("""Another Salary Structure '%s' is active for employee '%s'. Please make its status 'Inactive' to proceed.""") % msgprint(_("""Another Salary Structure '%s' is active for employee '%s'. Please make its status 'Inactive' to proceed.""") %
(cstr(ret), self.doc.employee), raise_exception=1) (cstr(ret), self.employee), raise_exception=1)
def validate_amount(self): def validate_amount(self):
if flt(self.doc.net_pay) < 0: if flt(self.net_pay) < 0:
msgprint(_("Net pay can not be negative"), raise_exception=1) msgprint(_("Net pay can not be negative"), raise_exception=1)
def validate(self): def validate(self):

View File

@ -16,13 +16,13 @@ class Bom(Document):
def autoname(self): def autoname(self):
last_name = frappe.db.sql("""select max(name) from `tabBOM` last_name = frappe.db.sql("""select max(name) from `tabBOM`
where name like "BOM/%s/%%" """ % cstr(self.doc.item).replace('"', '\\"')) where name like "BOM/%s/%%" """ % cstr(self.item).replace('"', '\\"'))
if last_name: if last_name:
idx = cint(cstr(last_name[0][0]).split('/')[-1].split('-')[0]) + 1 idx = cint(cstr(last_name[0][0]).split('/')[-1].split('-')[0]) + 1
else: else:
idx = 1 idx = 1
self.doc.name = 'BOM/' + self.doc.item + ('/%.3i' % idx) self.name = 'BOM/' + self.item + ('/%.3i' % idx)
def validate(self): def validate(self):
self.clear_operations() self.clear_operations()
@ -39,7 +39,7 @@ class Bom(Document):
def on_update(self): def on_update(self):
self.check_recursion() self.check_recursion()
self.update_exploded_items() self.update_exploded_items()
self.doc.save() self.save()
def on_submit(self): def on_submit(self):
self.manage_default_bom() self.manage_default_bom()
@ -65,7 +65,7 @@ class Bom(Document):
return item return item
def validate_rm_item(self, item): def validate_rm_item(self, item):
if item[0]['name'] == self.doc.item: if item[0]['name'] == self.item:
msgprint("Item_code: %s in materials tab cannot be same as FG Item", msgprint("Item_code: %s in materials tab cannot be same as FG Item",
item[0]['name'], raise_exception=1) item[0]['name'], raise_exception=1)
@ -78,8 +78,8 @@ class Bom(Document):
"qty": item.qty}) "qty": item.qty})
for r in ret: for r in ret:
if not item.fields.get(r): if not item.get(r):
item.fields[r] = ret[r] item.set(r, ret[r])
def get_bom_material_detail(self, args=None): def get_bom_material_detail(self, args=None):
""" Get raw material details like uom, desc and rate""" """ Get raw material details like uom, desc and rate"""
@ -111,16 +111,16 @@ class Bom(Document):
if arg['bom_no']: if arg['bom_no']:
rate = self.get_bom_unitcost(arg['bom_no']) rate = self.get_bom_unitcost(arg['bom_no'])
elif arg and (arg['is_purchase_item'] == 'Yes' or arg['is_sub_contracted_item'] == 'Yes'): elif arg and (arg['is_purchase_item'] == 'Yes' or arg['is_sub_contracted_item'] == 'Yes'):
if self.doc.rm_cost_as_per == 'Valuation Rate': if self.rm_cost_as_per == 'Valuation Rate':
rate = self.get_valuation_rate(arg) rate = self.get_valuation_rate(arg)
elif self.doc.rm_cost_as_per == 'Last Purchase Rate': elif self.rm_cost_as_per == 'Last Purchase Rate':
rate = arg['last_purchase_rate'] rate = arg['last_purchase_rate']
elif self.doc.rm_cost_as_per == "Price List": elif self.rm_cost_as_per == "Price List":
if not self.doc.buying_price_list: if not self.buying_price_list:
frappe.throw(_("Please select Price List")) frappe.throw(_("Please select Price List"))
rate = frappe.db.get_value("Item Price", {"price_list": self.doc.buying_price_list, rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list,
"item_code": arg["item_code"]}, "price_list_rate") or 0 "item_code": arg["item_code"]}, "price_list_rate") or 0
elif self.doc.rm_cost_as_per == 'Standard Rate': elif self.rm_cost_as_per == 'Standard Rate':
rate = arg['standard_rate'] rate = arg['standard_rate']
return rate return rate
@ -133,9 +133,9 @@ class Bom(Document):
'qty': d.qty 'qty': d.qty
})["rate"] })["rate"]
if self.doc.docstatus == 0: if self.docstatus == 0:
frappe.bean(self.doclist).save() frappe.bean(self.doclist).save()
elif self.doc.docstatus == 1: elif self.docstatus == 1:
self.calculate_cost() self.calculate_cost()
self.update_exploded_items() self.update_exploded_items()
frappe.bean(self.doclist).update_after_submit() frappe.bean(self.doclist).update_after_submit()
@ -151,8 +151,8 @@ class Bom(Document):
as on costing date as on costing date
""" """
from erpnext.stock.utils import get_incoming_rate from erpnext.stock.utils import get_incoming_rate
dt = self.doc.costing_date or nowdate() dt = self.costing_date or nowdate()
time = self.doc.costing_date == nowdate() and now().split()[1] or '23:59' time = self.costing_date == nowdate() and now().split()[1] or '23:59'
warehouse = frappe.db.sql("select warehouse from `tabBin` where item_code = %s", args['item_code']) warehouse = frappe.db.sql("select warehouse from `tabBin` where item_code = %s", args['item_code'])
rate = [] rate = []
for wh in warehouse: for wh in warehouse:
@ -172,38 +172,38 @@ class Bom(Document):
""" Uncheck others if current one is selected as default, """ Uncheck others if current one is selected as default,
update default bom in item master update default bom in item master
""" """
if self.doc.is_default and self.doc.is_active: if self.is_default and self.is_active:
from frappe.model.utils import set_default from frappe.model.utils import set_default
set_default(self.doc, "item") set_default(self.doc, "item")
frappe.db.set_value("Item", self.doc.item, "default_bom", self.doc.name) frappe.db.set_value("Item", self.item, "default_bom", self.name)
else: else:
if not self.doc.is_active: if not self.is_active:
frappe.db.set(self.doc, "is_default", 0) frappe.db.set(self.doc, "is_default", 0)
frappe.db.sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s", frappe.db.sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
(self.doc.item, self.doc.name)) (self.item, self.name))
def clear_operations(self): def clear_operations(self):
if not self.doc.with_operations: if not self.with_operations:
self.set('bom_operations', []) self.set('bom_operations', [])
for d in self.get("bom_materials"): for d in self.get("bom_materials"):
d.operation_no = None d.operation_no = None
def validate_main_item(self): def validate_main_item(self):
""" Validate main FG item""" """ Validate main FG item"""
item = self.get_item_det(self.doc.item) item = self.get_item_det(self.item)
if not item: if not item:
msgprint("Item %s does not exists in the system or expired." % msgprint("Item %s does not exists in the system or expired." %
self.doc.item, raise_exception = 1) self.item, raise_exception = 1)
elif item[0]['is_manufactured_item'] != 'Yes' \ elif item[0]['is_manufactured_item'] != 'Yes' \
and item[0]['is_sub_contracted_item'] != 'Yes': and item[0]['is_sub_contracted_item'] != 'Yes':
msgprint("""As Item: %s is not a manufactured / sub-contracted item, \ msgprint("""As Item: %s is not a manufactured / sub-contracted item, \
you can not make BOM for it""" % self.doc.item, raise_exception = 1) you can not make BOM for it""" % self.item, raise_exception = 1)
else: else:
ret = frappe.db.get_value("Item", self.doc.item, ["description", "stock_uom"]) ret = frappe.db.get_value("Item", self.item, ["description", "stock_uom"])
self.doc.description = ret[0] self.description = ret[0]
self.doc.uom = ret[1] self.uom = ret[1]
def validate_operations(self): def validate_operations(self):
""" Check duplicate operation no""" """ Check duplicate operation no"""
@ -221,7 +221,7 @@ class Bom(Document):
check_list = [] check_list = []
for m in self.get('bom_materials'): for m in self.get('bom_materials'):
# check if operation no not in op table # check if operation no not in op table
if self.doc.with_operations and cstr(m.operation_no) not in self.op: if self.with_operations and cstr(m.operation_no) not in self.op:
msgprint("""Operation no: %s against item: %s at row no: %s \ msgprint("""Operation no: %s against item: %s at row no: %s \
is not present at Operations table""" % is not present at Operations table""" %
(m.operation_no, m.item_code, m.idx), raise_exception = 1) (m.operation_no, m.item_code, m.idx), raise_exception = 1)
@ -267,15 +267,15 @@ class Bom(Document):
check_list = [['parent', 'bom_no', 'parent'], ['bom_no', 'parent', 'child']] check_list = [['parent', 'bom_no', 'parent'], ['bom_no', 'parent', 'child']]
for d in check_list: for d in check_list:
bom_list, count = [self.doc.name], 0 bom_list, count = [self.name], 0
while (len(bom_list) > count ): while (len(bom_list) > count ):
boms = frappe.db.sql(" select %s from `tabBOM Item` where %s = %s " % boms = frappe.db.sql(" select %s from `tabBOM Item` where %s = %s " %
(d[0], d[1], '%s'), cstr(bom_list[count])) (d[0], d[1], '%s'), cstr(bom_list[count]))
count = count + 1 count = count + 1
for b in boms: for b in boms:
if b[0] == self.doc.name: if b[0] == self.name:
msgprint("""Recursion Occured => '%s' cannot be '%s' of '%s'. msgprint("""Recursion Occured => '%s' cannot be '%s' of '%s'.
""" % (cstr(b[0]), cstr(d[2]), self.doc.name), raise_exception = 1) """ % (cstr(b[0]), cstr(d[2]), self.name), raise_exception = 1)
if b[0]: if b[0]:
bom_list.append(b[0]) bom_list.append(b[0])
@ -293,8 +293,8 @@ class Bom(Document):
where parent = %s and ifnull(bom_no, '') != ''""", bom_no)] where parent = %s and ifnull(bom_no, '') != ''""", bom_no)]
count = 0 count = 0
if self.doc.name not in bom_list: if self.name not in bom_list:
bom_list.append(self.doc.name) bom_list.append(self.name)
while(count < len(bom_list)): while(count < len(bom_list)):
for child_bom in _get_children(bom_list[count]): for child_bom in _get_children(bom_list[count]):
@ -308,7 +308,7 @@ class Bom(Document):
"""Calculate bom totals""" """Calculate bom totals"""
self.calculate_op_cost() self.calculate_op_cost()
self.calculate_rm_cost() self.calculate_rm_cost()
self.doc.total_cost = self.doc.raw_material_cost + self.doc.operating_cost self.total_cost = self.raw_material_cost + self.operating_cost
def calculate_op_cost(self): def calculate_op_cost(self):
"""Update workstation rate and calculates totals""" """Update workstation rate and calculates totals"""
@ -319,7 +319,7 @@ class Bom(Document):
if d.hour_rate and d.time_in_mins: if d.hour_rate and d.time_in_mins:
d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60.0 d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60.0
total_op_cost += flt(d.operating_cost) total_op_cost += flt(d.operating_cost)
self.doc.operating_cost = total_op_cost self.operating_cost = total_op_cost
def calculate_rm_cost(self): def calculate_rm_cost(self):
"""Fetch RM rate as per today's valuation rate and calculate totals""" """Fetch RM rate as per today's valuation rate and calculate totals"""
@ -328,10 +328,10 @@ class Bom(Document):
if d.bom_no: if d.bom_no:
d.rate = self.get_bom_unitcost(d.bom_no) d.rate = self.get_bom_unitcost(d.bom_no)
d.amount = flt(d.rate) * flt(d.qty) d.amount = flt(d.rate) * flt(d.qty)
d.qty_consumed_per_unit = flt(d.qty) / flt(self.doc.quantity) d.qty_consumed_per_unit = flt(d.qty) / flt(self.quantity)
total_rm_cost += d.amount total_rm_cost += d.amount
self.doc.raw_material_cost = total_rm_cost self.raw_material_cost = total_rm_cost
def update_exploded_items(self): def update_exploded_items(self):
""" Update Flat BOM, following will be correct data""" """ Update Flat BOM, following will be correct data"""
@ -379,23 +379,23 @@ class Bom(Document):
"Add items to Flat BOM table" "Add items to Flat BOM table"
self.set('flat_bom_details', []) self.set('flat_bom_details', [])
for d in self.cur_exploded_items: for d in self.cur_exploded_items:
ch = self.doc.append('flat_bom_details', {}) ch = self.append('flat_bom_details', {})
for i in self.cur_exploded_items[d].keys(): for i in self.cur_exploded_items[d].keys():
ch.fields[i] = self.cur_exploded_items[d][i] ch.set(i, self.cur_exploded_items[d][i])
ch.amount = flt(ch.qty) * flt(ch.rate) ch.amount = flt(ch.qty) * flt(ch.rate)
ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.doc.quantity) ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.quantity)
ch.docstatus = self.doc.docstatus ch.docstatus = self.docstatus
ch.save(1) ch.save(1)
def validate_bom_links(self): def validate_bom_links(self):
if not self.doc.is_active: if not self.is_active:
act_pbom = frappe.db.sql("""select distinct bom_item.parent from `tabBOM Item` bom_item act_pbom = frappe.db.sql("""select distinct bom_item.parent from `tabBOM Item` bom_item
where bom_item.bom_no = %s and bom_item.docstatus = 1 where bom_item.bom_no = %s and bom_item.docstatus = 1
and exists (select * from `tabBOM` where name = bom_item.parent and exists (select * from `tabBOM` where name = bom_item.parent
and docstatus = 1 and is_active = 1)""", self.doc.name) and docstatus = 1 and is_active = 1)""", self.name)
if act_pbom and act_pbom[0][0]: if act_pbom and act_pbom[0][0]:
action = self.doc.docstatus < 2 and _("deactivate") or _("cancel") action = self.docstatus < 2 and _("deactivate") or _("cancel")
msgprint(_("Cannot ") + action + _(": It is linked to other active BOM(s)"), msgprint(_("Cannot ") + action + _(": It is linked to other active BOM(s)"),
raise_exception=1) raise_exception=1)

View File

@ -26,18 +26,18 @@ class BomReplaceTool(Document):
frappe.msgprint(_("BOM replaced")) frappe.msgprint(_("BOM replaced"))
def validate_bom(self): def validate_bom(self):
if cstr(self.doc.current_bom) == cstr(self.doc.new_bom): if cstr(self.current_bom) == cstr(self.new_bom):
msgprint("Current BOM and New BOM can not be same", raise_exception=1) msgprint("Current BOM and New BOM can not be same", raise_exception=1)
def update_new_bom(self): def update_new_bom(self):
current_bom_unitcost = frappe.db.sql("""select total_cost/quantity current_bom_unitcost = frappe.db.sql("""select total_cost/quantity
from `tabBOM` where name = %s""", self.doc.current_bom) from `tabBOM` where name = %s""", self.current_bom)
current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0 current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0
frappe.db.sql("""update `tabBOM Item` set bom_no=%s, frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""", rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""",
(self.doc.new_bom, current_bom_unitcost, current_bom_unitcost, self.doc.current_bom)) (self.new_bom, current_bom_unitcost, current_bom_unitcost, self.current_bom))
def get_parent_boms(self): def get_parent_boms(self):
return [d[0] for d in frappe.db.sql("""select distinct parent return [d[0] for d in frappe.db.sql("""select distinct parent
from `tabBOM Item` where ifnull(bom_no, '') = %s and docstatus < 2""", from `tabBOM Item` where ifnull(bom_no, '') = %s and docstatus < 2""",
self.doc.new_bom)] self.new_bom)]

View File

@ -15,11 +15,11 @@ from frappe.model.document import Document
class ProductionOrder(Document): class ProductionOrder(Document):
def validate(self): def validate(self):
if self.doc.docstatus == 0: if self.docstatus == 0:
self.doc.status = "Draft" self.status = "Draft"
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", validate_status(self.status, ["Draft", "Submitted", "Stopped",
"In Process", "Completed", "Cancelled"]) "In Process", "Completed", "Cancelled"])
self.validate_bom_no() self.validate_bom_no()
@ -30,64 +30,64 @@ class ProductionOrder(Document):
validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"])
def validate_bom_no(self): def validate_bom_no(self):
if self.doc.bom_no: if self.bom_no:
bom = frappe.db.sql("""select name from `tabBOM` where name=%s and docstatus=1 bom = frappe.db.sql("""select name from `tabBOM` where name=%s and docstatus=1
and is_active=1 and item=%s""" and is_active=1 and item=%s"""
, (self.doc.bom_no, self.doc.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("""Incorrect BOM: %s entered.
May be BOM not exists or inactive or not submitted May be BOM not exists or inactive or not submitted
or for some other item.""" % cstr(self.doc.bom_no)) or for some other item.""" % cstr(self.bom_no))
def validate_sales_order(self): def validate_sales_order(self):
if self.doc.sales_order: if self.sales_order:
so = frappe.db.sql("""select name, delivery_date from `tabSales Order` so = frappe.db.sql("""select name, delivery_date from `tabSales Order`
where name=%s and docstatus = 1""", self.doc.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.doc.sales_order) frappe.throw("Sales Order: %s is not valid" % self.sales_order)
if not self.doc.expected_delivery_date: if not self.expected_delivery_date:
self.doc.expected_delivery_date = so.delivery_date self.expected_delivery_date = so.delivery_date
self.validate_production_order_against_so() self.validate_production_order_against_so()
def validate_warehouse(self): def validate_warehouse(self):
from erpnext.stock.utils import validate_warehouse_company from erpnext.stock.utils import validate_warehouse_company
for w in [self.doc.fg_warehouse, self.doc.wip_warehouse]: for w in [self.fg_warehouse, self.wip_warehouse]:
validate_warehouse_company(w, self.doc.company) validate_warehouse_company(w, self.company)
def validate_production_order_against_so(self): def validate_production_order_against_so(self):
# already ordered qty # already ordered qty
ordered_qty_against_so = frappe.db.sql("""select sum(qty) from `tabProduction Order` ordered_qty_against_so = frappe.db.sql("""select sum(qty) from `tabProduction Order`
where production_item = %s and sales_order = %s and docstatus < 2 and name != %s""", where production_item = %s and sales_order = %s and docstatus < 2 and name != %s""",
(self.doc.production_item, self.doc.sales_order, self.doc.name))[0][0] (self.production_item, self.sales_order, self.name))[0][0]
total_qty = flt(ordered_qty_against_so) + flt(self.doc.qty) total_qty = flt(ordered_qty_against_so) + flt(self.qty)
# get qty from Sales Order Item table # get qty from Sales Order Item table
so_item_qty = frappe.db.sql("""select sum(qty) from `tabSales Order Item` so_item_qty = frappe.db.sql("""select sum(qty) from `tabSales Order Item`
where parent = %s and item_code = %s""", where parent = %s and item_code = %s""",
(self.doc.sales_order, self.doc.production_item))[0][0] (self.sales_order, self.production_item))[0][0]
# get qty from Packing Item table # get qty from Packing Item table
dnpi_qty = frappe.db.sql("""select sum(qty) from `tabPacked Item` dnpi_qty = frappe.db.sql("""select sum(qty) from `tabPacked Item`
where parent = %s and parenttype = 'Sales Order' and item_code = %s""", where parent = %s and parenttype = 'Sales Order' and item_code = %s""",
(self.doc.sales_order, self.doc.production_item))[0][0] (self.sales_order, self.production_item))[0][0]
# total qty in SO # total qty in SO
so_qty = flt(so_item_qty) + flt(dnpi_qty) so_qty = flt(so_item_qty) + flt(dnpi_qty)
if total_qty > so_qty: if total_qty > so_qty:
frappe.throw(_("Total production order qty for item") + ": " + frappe.throw(_("Total production order qty for item") + ": " +
cstr(self.doc.production_item) + _(" against sales order") + ": " + cstr(self.production_item) + _(" against sales order") + ": " +
cstr(self.doc.sales_order) + _(" will be ") + cstr(total_qty) + ", " + cstr(self.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
_("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" + _("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" +
_("Please reduce qty."), exc=OverProductionError) _("Please reduce qty."), exc=OverProductionError)
def stop_unstop(self, status): def stop_unstop(self, status):
""" Called from client side on Stop/Unstop event""" """ Called from client side on Stop/Unstop event"""
self.update_status(status) self.update_status(status)
qty = (flt(self.doc.qty)-flt(self.doc.produced_qty)) * ((status == 'Stopped') and -1 or 1) qty = (flt(self.qty)-flt(self.produced_qty)) * ((status == 'Stopped') and -1 or 1)
self.update_planned_qty(qty) self.update_planned_qty(qty)
msgprint("Production Order has been %s" % status) msgprint("Production Order has been %s" % status)
@ -96,37 +96,37 @@ class ProductionOrder(Document):
if status == 'Stopped': if status == 'Stopped':
frappe.db.set(self.doc, 'status', cstr(status)) frappe.db.set(self.doc, 'status', cstr(status))
else: else:
if flt(self.doc.qty) == flt(self.doc.produced_qty): if flt(self.qty) == flt(self.produced_qty):
frappe.db.set(self.doc, 'status', 'Completed') frappe.db.set(self.doc, 'status', 'Completed')
if flt(self.doc.qty) > flt(self.doc.produced_qty): if flt(self.qty) > flt(self.produced_qty):
frappe.db.set(self.doc, 'status', 'In Process') frappe.db.set(self.doc, 'status', 'In Process')
if flt(self.doc.produced_qty) == 0: if flt(self.produced_qty) == 0:
frappe.db.set(self.doc, 'status', 'Submitted') frappe.db.set(self.doc, 'status', 'Submitted')
def on_submit(self): def on_submit(self):
if not self.doc.wip_warehouse: if not self.wip_warehouse:
frappe.throw(_("WIP Warehouse required before Submit")) frappe.throw(_("WIP Warehouse required before Submit"))
frappe.db.set(self.doc,'status', 'Submitted') frappe.db.set(self.doc,'status', 'Submitted')
self.update_planned_qty(self.doc.qty) self.update_planned_qty(self.qty)
def on_cancel(self): def on_cancel(self):
# Check whether any stock entry exists against this Production Order # Check whether any stock entry exists against this Production Order
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.doc.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("""Submitted Stock Entry %s exists against this production order.
Hence can not be cancelled.""" % stock_entry[0][0]) Hence can not be cancelled.""" % stock_entry[0][0])
frappe.db.set(self.doc,'status', 'Cancelled') frappe.db.set(self.doc,'status', 'Cancelled')
self.update_planned_qty(-self.doc.qty) self.update_planned_qty(-self.qty)
def update_planned_qty(self, qty): def update_planned_qty(self, qty):
"""update planned qty in bin""" """update planned qty in bin"""
args = { args = {
"item_code": self.doc.production_item, "item_code": self.production_item,
"warehouse": self.doc.fg_warehouse, "warehouse": self.fg_warehouse,
"posting_date": nowdate(), "posting_date": nowdate(),
"planned_qty": flt(qty) "planned_qty": flt(qty)
} }
@ -155,18 +155,18 @@ def make_stock_entry(production_order_id, purpose):
production_order = frappe.bean("Production Order", production_order_id) production_order = frappe.bean("Production Order", production_order_id)
stock_entry = frappe.new_bean("Stock Entry") stock_entry = frappe.new_bean("Stock Entry")
stock_entry.doc.purpose = purpose stock_entry.purpose = purpose
stock_entry.doc.production_order = production_order_id stock_entry.production_order = production_order_id
stock_entry.doc.company = production_order.doc.company stock_entry.company = production_order.company
stock_entry.doc.bom_no = production_order.doc.bom_no stock_entry.bom_no = production_order.bom_no
stock_entry.doc.use_multi_level_bom = production_order.doc.use_multi_level_bom stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
stock_entry.doc.fg_completed_qty = flt(production_order.doc.qty) - flt(production_order.doc.produced_qty) stock_entry.fg_completed_qty = flt(production_order.qty) - flt(production_order.produced_qty)
if purpose=="Material Transfer": if purpose=="Material Transfer":
stock_entry.doc.to_warehouse = production_order.doc.wip_warehouse stock_entry.to_warehouse = production_order.wip_warehouse
else: else:
stock_entry.doc.from_warehouse = production_order.doc.wip_warehouse stock_entry.from_warehouse = production_order.wip_warehouse
stock_entry.doc.to_warehouse = production_order.doc.fg_warehouse stock_entry.to_warehouse = production_order.fg_warehouse
stock_entry.run_method("get_items") stock_entry.run_method("get_items")
return [d.fields for d in stock_entry.doclist] return [d.fields for d in stock_entry.doclist]

View File

@ -31,21 +31,21 @@ class TestProductionOrder(unittest.TestCase):
mr2.insert() mr2.insert()
mr2.submit() mr2.submit()
stock_entry = make_stock_entry(pro_bean.doc.name, "Manufacture/Repack") stock_entry = make_stock_entry(pro_bean.name, "Manufacture/Repack")
stock_entry = frappe.bean(stock_entry) stock_entry = frappe.bean(stock_entry)
stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.fiscal_year = "_Test Fiscal Year 2013"
stock_entry.doc.fg_completed_qty = 4 stock_entry.fg_completed_qty = 4
stock_entry.doc.posting_date = "2013-05-12" stock_entry.posting_date = "2013-05-12"
stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.fiscal_year = "_Test Fiscal Year 2013"
stock_entry.run_method("get_items") stock_entry.run_method("get_items")
stock_entry.submit() stock_entry.submit()
self.assertEqual(frappe.db.get_value("Production Order", pro_bean.doc.name, self.assertEqual(frappe.db.get_value("Production Order", pro_bean.name,
"produced_qty"), 4) "produced_qty"), 4)
self.assertEqual(frappe.db.get_value("Bin", {"item_code": "_Test FG Item", self.assertEqual(frappe.db.get_value("Bin", {"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty"), 6) "warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty"), 6)
return pro_bean.doc.name return pro_bean.name
def test_over_production(self): def test_over_production(self):
from erpnext.stock.doctype.stock_entry.stock_entry import StockOverProductionError from erpnext.stock.doctype.stock_entry.stock_entry import StockOverProductionError
@ -53,9 +53,9 @@ class TestProductionOrder(unittest.TestCase):
stock_entry = make_stock_entry(pro_order, "Manufacture/Repack") stock_entry = make_stock_entry(pro_order, "Manufacture/Repack")
stock_entry = frappe.bean(stock_entry) stock_entry = frappe.bean(stock_entry)
stock_entry.doc.posting_date = "2013-05-12" stock_entry.posting_date = "2013-05-12"
stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.fiscal_year = "_Test Fiscal Year 2013"
stock_entry.doc.fg_completed_qty = 15 stock_entry.fg_completed_qty = 15
stock_entry.run_method("get_items") stock_entry.run_method("get_items")
stock_entry.insert() stock_entry.insert()

View File

@ -43,21 +43,21 @@ class ProductionPlanningTool(Document):
self.set('pp_details', []) self.set('pp_details', [])
def validate_company(self): def validate_company(self):
if not self.doc.company: if not self.company:
frappe.throw(_("Please enter Company")) frappe.throw(_("Please enter Company"))
def get_open_sales_orders(self): def get_open_sales_orders(self):
""" Pull sales orders which are pending to deliver based on criteria selected""" """ Pull sales orders which are pending to deliver based on criteria selected"""
so_filter = item_filter = "" so_filter = item_filter = ""
if self.doc.from_date: if self.from_date:
so_filter += ' and so.transaction_date >= "' + self.doc.from_date + '"' so_filter += ' and so.transaction_date >= "' + self.from_date + '"'
if self.doc.to_date: if self.to_date:
so_filter += ' and so.transaction_date <= "' + self.doc.to_date + '"' so_filter += ' and so.transaction_date <= "' + self.to_date + '"'
if self.doc.customer: if self.customer:
so_filter += ' and so.customer = "' + self.doc.customer + '"' so_filter += ' and so.customer = "' + self.customer + '"'
if self.doc.fg_item: if self.fg_item:
item_filter += ' and item.name = "' + self.doc.fg_item + '"' item_filter += ' and item.name = "' + self.fg_item + '"'
open_so = frappe.db.sql(""" open_so = frappe.db.sql("""
select distinct so.name, so.transaction_date, so.customer, so.grand_total select distinct so.name, so.transaction_date, so.customer, so.grand_total
@ -74,7 +74,7 @@ class ProductionPlanningTool(Document):
and exists (select name from `tabItem` item where item.name=pi.item_code and exists (select name from `tabItem` item where item.name=pi.item_code
and (ifnull(item.is_pro_applicable, 'No') = 'Yes' and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s))) or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s)))
""" % ('%s', so_filter, item_filter, item_filter), self.doc.company, as_dict=1) """ % ('%s', so_filter, item_filter, item_filter), self.company, as_dict=1)
self.add_so_in_table(open_so) self.add_so_in_table(open_so)
@ -85,7 +85,7 @@ class ProductionPlanningTool(Document):
so_list = [d.sales_order for d in self.get('pp_so_details')] so_list = [d.sales_order for d in self.get('pp_so_details')]
for r in open_so: for r in open_so:
if cstr(r['name']) not in so_list: if cstr(r['name']) not in so_list:
pp_so = self.doc.append('pp_so_details', {}) pp_so = self.append('pp_so_details', {})
pp_so.sales_order = r['name'] pp_so.sales_order = r['name']
pp_so.sales_order_date = cstr(r['transaction_date']) pp_so.sales_order_date = cstr(r['transaction_date'])
pp_so.customer = cstr(r['customer']) pp_so.customer = cstr(r['customer'])
@ -135,7 +135,7 @@ class ProductionPlanningTool(Document):
for p in items: for p in items:
item_details = frappe.db.sql("""select description, stock_uom, default_bom item_details = frappe.db.sql("""select description, stock_uom, default_bom
from tabItem where name=%s""", p['item_code']) from tabItem where name=%s""", p['item_code'])
pi = self.doc.append('pp_details', {}) pi = self.append('pp_details', {})
pi.sales_order = p['parent'] pi.sales_order = p['parent']
pi.warehouse = p['warehouse'] pi.warehouse = p['warehouse']
pi.item_code = p['item_code'] pi.item_code = p['item_code']
@ -200,7 +200,7 @@ class ProductionPlanningTool(Document):
"bom_no" : d.bom_no, "bom_no" : d.bom_no,
"description" : d.description, "description" : d.description,
"stock_uom" : d.stock_uom, "stock_uom" : d.stock_uom,
"company" : self.doc.company, "company" : self.company,
"wip_warehouse" : "", "wip_warehouse" : "",
"fg_warehouse" : d.warehouse, "fg_warehouse" : d.warehouse,
"status" : "Draft", "status" : "Draft",
@ -214,12 +214,12 @@ class ProductionPlanningTool(Document):
pro_list = [] pro_list = []
for key in items: for key in items:
pro = frappe.new_bean("Production Order") pro = frappe.new_bean("Production Order")
pro.doc.fields.update(items[key]) pro.update(items[key])
frappe.flags.mute_messages = True frappe.flags.mute_messages = True
try: try:
pro.insert() pro.insert()
pro_list.append(pro.doc.name) pro_list.append(pro.name)
except OverProductionError, e: except OverProductionError, e:
pass pass
@ -244,7 +244,7 @@ class ProductionPlanningTool(Document):
for bom, so_wise_qty in bom_dict.items(): for bom, so_wise_qty in bom_dict.items():
bom_wise_item_details = {} bom_wise_item_details = {}
if self.doc.use_multi_level_bom: if self.use_multi_level_bom:
# get all raw materials with sub assembly childs # get all raw materials with sub assembly childs
for d in frappe.db.sql("""select fb.item_code, for d in frappe.db.sql("""select fb.item_code,
ifnull(sum(fb.qty_consumed_per_unit), 0) as qty, ifnull(sum(fb.qty_consumed_per_unit), 0) as qty,
@ -303,7 +303,7 @@ class ProductionPlanningTool(Document):
Requested qty should be shortage qty considering minimum order qty Requested qty should be shortage qty considering minimum order qty
""" """
self.validate_data() self.validate_data()
if not self.doc.purchase_request_for_warehouse: if not self.purchase_request_for_warehouse:
frappe.throw(_("Please enter Warehouse for which Material Request will be raised")) frappe.throw(_("Please enter Warehouse for which Material Request will be raised"))
bom_dict = self.get_distinct_items_and_boms()[0] bom_dict = self.get_distinct_items_and_boms()[0]
@ -372,7 +372,7 @@ class ProductionPlanningTool(Document):
"naming_series": "IDT", "naming_series": "IDT",
"transaction_date": nowdate(), "transaction_date": nowdate(),
"status": "Draft", "status": "Draft",
"company": self.doc.company, "company": self.company,
"fiscal_year": fiscal_year, "fiscal_year": fiscal_year,
"requested_by": frappe.session.user, "requested_by": frappe.session.user,
"material_request_type": "Purchase" "material_request_type": "Purchase"
@ -382,14 +382,14 @@ class ProductionPlanningTool(Document):
"doctype": "Material Request Item", "doctype": "Material Request Item",
"__islocal": 1, "__islocal": 1,
"item_code": item, "item_code": item,
"item_name": item_wrapper.doc.item_name, "item_name": item_wrapper.item_name,
"description": item_wrapper.doc.description, "description": item_wrapper.description,
"uom": item_wrapper.doc.stock_uom, "uom": item_wrapper.stock_uom,
"item_group": item_wrapper.doc.item_group, "item_group": item_wrapper.item_group,
"brand": item_wrapper.doc.brand, "brand": item_wrapper.brand,
"qty": requested_qty, "qty": requested_qty,
"schedule_date": add_days(nowdate(), cint(item_wrapper.doc.lead_time_days)), "schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)),
"warehouse": self.doc.purchase_request_for_warehouse, "warehouse": self.purchase_request_for_warehouse,
"sales_order_no": sales_order if sales_order!="No Sales Order" else None "sales_order_no": sales_order if sales_order!="No Sales Order" else None
}) })

View File

@ -14,14 +14,14 @@ class Workstation(Document):
def update_bom_operation(self): def update_bom_operation(self):
bom_list = frappe.db.sql("""select DISTINCT parent from `tabBOM Operation` bom_list = frappe.db.sql("""select DISTINCT parent from `tabBOM Operation`
where workstation = %s""", self.doc.name) where workstation = %s""", self.name)
for bom_no in bom_list: for bom_no in bom_list:
frappe.db.sql("""update `tabBOM Operation` set hour_rate = %s frappe.db.sql("""update `tabBOM Operation` set hour_rate = %s
where parent = %s and workstation = %s""", where parent = %s and workstation = %s""",
(self.doc.hour_rate, bom_no[0], self.doc.name)) (self.hour_rate, bom_no[0], self.name))
def on_update(self): def on_update(self):
frappe.db.set(self.doc, 'overhead', flt(self.doc.hour_rate_electricity) + frappe.db.set(self.doc, 'overhead', flt(self.hour_rate_electricity) +
flt(self.doc.hour_rate_consumable) + flt(self.doc.hour_rate_rent)) flt(self.hour_rate_consumable) + flt(self.hour_rate_rent))
frappe.db.set(self.doc, 'hour_rate', flt(self.doc.hour_rate_labour) + flt(self.doc.overhead)) frappe.db.set(self.doc, 'hour_rate', flt(self.hour_rate_labour) + flt(self.overhead))
self.update_bom_operation() self.update_bom_operation()

View File

@ -7,6 +7,6 @@ def execute():
address = frappe.doc("Address", address) address = frappe.doc("Address", address)
contact = frappe.bean("Contact Us Settings", "Contact Us Settings") contact = frappe.bean("Contact Us Settings", "Contact Us Settings")
for f in ("address_title", "address_line1", "address_line2", "city", "state", "country", "pincode"): for f in ("address_title", "address_line1", "address_line2", "city", "state", "country", "pincode"):
contact.doc.fields[f] = address.get(f) contact.set(f, address.get(f))
contact.save() contact.save()

View File

@ -25,7 +25,7 @@ def map_outgoing_email_settings(email_settings):
else: else:
from_fieldname = to_fieldname = fieldname from_fieldname = to_fieldname = fieldname
outgoing_email_settings.doc.fields[to_fieldname] = email_settings.doc.fields.get(from_fieldname) outgoing_email_settings.set(to_fieldname, email_settings.get(from_fieldname))
outgoing_email_settings.save() outgoing_email_settings.save()
@ -44,7 +44,7 @@ def map_support_email_settings(email_settings):
else: else:
from_fieldname = to_fieldname = fieldname from_fieldname = to_fieldname = fieldname
support_email_settings.doc.fields[to_fieldname] = email_settings.doc.fields.get(from_fieldname) support_email_settings.set(to_fieldname, email_settings.get(from_fieldname))
support_email_settings.save() support_email_settings.save()

View File

@ -14,16 +14,16 @@ class Project(Document):
def get_gross_profit(self): def get_gross_profit(self):
pft, per_pft =0, 0 pft, per_pft =0, 0
pft = flt(self.doc.project_value) - flt(self.doc.est_material_cost) pft = flt(self.project_value) - flt(self.est_material_cost)
#if pft > 0: #if pft > 0:
per_pft = (flt(pft) / flt(self.doc.project_value)) * 100 per_pft = (flt(pft) / flt(self.project_value)) * 100
ret = {'gross_margin_value': pft, 'per_gross_margin': per_pft} ret = {'gross_margin_value': pft, 'per_gross_margin': per_pft}
return ret return ret
def validate(self): def validate(self):
"""validate start date before end date""" """validate start date before end date"""
if self.doc.project_start_date and self.doc.completion_date: if self.project_start_date and self.completion_date:
if getdate(self.doc.completion_date) < getdate(self.doc.project_start_date): if getdate(self.completion_date) < getdate(self.project_start_date):
msgprint("Expected Completion Date can not be less than Project Start Date") msgprint("Expected Completion Date can not be less than Project Start Date")
raise Exception raise Exception
@ -32,31 +32,31 @@ class Project(Document):
def update_percent_complete(self): def update_percent_complete(self):
total = frappe.db.sql("""select count(*) from tabTask where project=%s""", total = frappe.db.sql("""select count(*) from tabTask where project=%s""",
self.doc.name)[0][0] self.name)[0][0]
if total: if total:
completed = frappe.db.sql("""select count(*) from tabTask where completed = frappe.db.sql("""select count(*) from tabTask where
project=%s and status in ('Closed', 'Cancelled')""", self.doc.name)[0][0] project=%s and status in ('Closed', 'Cancelled')""", self.name)[0][0]
frappe.db.set_value("Project", self.doc.name, "percent_complete", frappe.db.set_value("Project", self.name, "percent_complete",
int(float(completed) / total * 100)) int(float(completed) / total * 100))
def add_calendar_event(self): def add_calendar_event(self):
# delete any earlier event for this project # delete any earlier event for this project
delete_events(self.doc.doctype, self.doc.name) delete_events(self.doctype, self.name)
# add events # add events
for milestone in self.get("project_milestones"): for milestone in self.get("project_milestones"):
if milestone.milestone_date: if milestone.milestone_date:
description = (milestone.milestone or "Milestone") + " for " + self.doc.name description = (milestone.milestone or "Milestone") + " for " + self.name
frappe.bean({ frappe.bean({
"doctype": "Event", "doctype": "Event",
"owner": self.doc.owner, "owner": self.owner,
"subject": description, "subject": description,
"description": description, "description": description,
"starts_on": milestone.milestone_date + " 10:00:00", "starts_on": milestone.milestone_date + " 10:00:00",
"event_type": "Private", "event_type": "Private",
"ref_type": self.doc.doctype, "ref_type": self.doctype,
"ref_name": self.doc.name "ref_name": self.name
}).insert() }).insert()
def on_trash(self): def on_trash(self):
delete_events(self.doc.doctype, self.doc.name) delete_events(self.doctype, self.name)

View File

@ -13,38 +13,38 @@ from frappe.model.document import Document
class Task(Document): class Task(Document):
def get_project_details(self): def get_project_details(self):
return { return {
"project": self.doc.project "project": self.project
} }
def get_customer_details(self): def get_customer_details(self):
cust = frappe.db.sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer) cust = frappe.db.sql("select customer_name from `tabCustomer` where name=%s", self.customer)
if cust: if cust:
ret = {'customer_name': cust and cust[0][0] or ''} ret = {'customer_name': cust and cust[0][0] or ''}
return ret return ret
def validate(self): def validate(self):
if self.doc.exp_start_date and self.doc.exp_end_date and getdate(self.doc.exp_start_date) > getdate(self.doc.exp_end_date): if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
msgprint("'Expected Start Date' can not be greater than 'Expected End Date'") msgprint("'Expected Start Date' can not be greater than 'Expected End Date'")
raise Exception raise Exception
if self.doc.act_start_date and self.doc.act_end_date and getdate(self.doc.act_start_date) > getdate(self.doc.act_end_date): if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
msgprint("'Actual Start Date' can not be greater than 'Actual End Date'") msgprint("'Actual Start Date' can not be greater than 'Actual End Date'")
raise Exception raise Exception
self.update_status() self.update_status()
def update_status(self): def update_status(self):
status = frappe.db.get_value("Task", self.doc.name, "status") status = frappe.db.get_value("Task", self.name, "status")
if self.doc.status=="Working" and status !="Working" and not self.doc.act_start_date: if self.status=="Working" and status !="Working" and not self.act_start_date:
self.doc.act_start_date = today() self.act_start_date = today()
if self.doc.status=="Closed" and status != "Closed" and not self.doc.act_end_date: if self.status=="Closed" and status != "Closed" and not self.act_end_date:
self.doc.act_end_date = today() self.act_end_date = today()
def on_update(self): def on_update(self):
"""update percent complete in project""" """update percent complete in project"""
if self.doc.project: if self.project:
project = frappe.bean("Project", self.doc.project) project = frappe.bean("Project", self.project)
project.run_method("update_percent_complete") project.run_method("update_percent_complete")
@frappe.whitelist() @frappe.whitelist()

View File

@ -22,20 +22,20 @@ class TimeLog(Document):
def calculate_total_hours(self): def calculate_total_hours(self):
from frappe.utils import time_diff_in_hours from frappe.utils import time_diff_in_hours
self.doc.hours = time_diff_in_hours(self.doc.to_time, self.doc.from_time) self.hours = time_diff_in_hours(self.to_time, self.from_time)
def set_status(self): def set_status(self):
self.doc.status = { self.status = {
0: "Draft", 0: "Draft",
1: "Submitted", 1: "Submitted",
2: "Cancelled" 2: "Cancelled"
}[self.doc.docstatus or 0] }[self.docstatus or 0]
if self.doc.time_log_batch: if self.time_log_batch:
self.doc.status="Batched for Billing" self.status="Batched for Billing"
if self.doc.sales_invoice: if self.sales_invoice:
self.doc.status="Billed" self.status="Billed"
def validate_overlap(self): def validate_overlap(self):
existing = frappe.db.sql_list("""select name from `tabTime Log` where owner=%s and existing = frappe.db.sql_list("""select name from `tabTime Log` where owner=%s and
@ -46,9 +46,9 @@ class TimeLog(Document):
and name!=%s and name!=%s
and ifnull(task, "")=%s and ifnull(task, "")=%s
and docstatus < 2""", and docstatus < 2""",
(self.doc.owner, self.doc.from_time, self.doc.to_time, self.doc.from_time, (self.owner, self.from_time, self.to_time, self.from_time,
self.doc.to_time, self.doc.from_time, self.doc.name or "No Name", self.to_time, self.from_time, self.name or "No Name",
cstr(self.doc.task))) cstr(self.task)))
if existing: if existing:
frappe.msgprint(_("This Time Log conflicts with") + ":" + ', '.join(existing), frappe.msgprint(_("This Time Log conflicts with") + ":" + ', '.join(existing),

View File

@ -7,7 +7,7 @@ class TimeLogBatchTest(unittest.TestCase):
def test_time_log_status(self): def test_time_log_status(self):
from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records
time_log = frappe.bean(copy=time_log_records[0]) time_log = frappe.bean(copy=time_log_records[0])
time_log.doc.fields.update({ time_log.update({
"from_time": "2013-01-02 10:00:00.000000", "from_time": "2013-01-02 10:00:00.000000",
"to_time": "2013-01-02 11:00:00.000000", "to_time": "2013-01-02 11:00:00.000000",
"docstatus": 0 "docstatus": 0
@ -15,15 +15,15 @@ class TimeLogBatchTest(unittest.TestCase):
time_log.insert() time_log.insert()
time_log.submit() time_log.submit()
self.assertEquals(frappe.db.get_value("Time Log", time_log.doc.name, "status"), "Submitted") self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted")
tlb = frappe.bean(copy=test_records[0]) tlb = frappe.bean(copy=test_records[0])
tlb.doclist[1].time_log = time_log.doc.name tlb.doclist[1].time_log = time_log.name
tlb.insert() tlb.insert()
tlb.submit() tlb.submit()
self.assertEquals(frappe.db.get_value("Time Log", time_log.doc.name, "status"), "Batched for Billing") self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Batched for Billing")
tlb.cancel() tlb.cancel()
self.assertEquals(frappe.db.get_value("Time Log", time_log.doc.name, "status"), "Submitted") self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted")
test_records = [[ test_records = [[
{ {

View File

@ -13,12 +13,12 @@ class TimeLogBatch(Document):
def validate(self): def validate(self):
self.set_status() self.set_status()
self.doc.total_hours = 0.0 self.total_hours = 0.0
for d in self.doclist.get({"doctype":"Time Log Batch Detail"}): for d in self.doclist.get({"doctype":"Time Log Batch Detail"}):
tl = frappe.doc("Time Log", d.time_log) tl = frappe.doc("Time Log", d.time_log)
self.update_time_log_values(d, tl) self.update_time_log_values(d, tl)
self.validate_time_log_is_submitted(tl) self.validate_time_log_is_submitted(tl)
self.doc.total_hours += float(tl.hours or 0.0) self.total_hours += float(tl.hours or 0.0)
def update_time_log_values(self, d, tl): def update_time_log_values(self, d, tl):
d.fields.update({ d.fields.update({
@ -28,33 +28,33 @@ class TimeLogBatch(Document):
}) })
def validate_time_log_is_submitted(self, tl): def validate_time_log_is_submitted(self, tl):
if tl.status != "Submitted" and self.doc.docstatus == 0: if tl.status != "Submitted" and self.docstatus == 0:
frappe.msgprint(_("Time Log must have status 'Submitted'") + \ frappe.msgprint(_("Time Log must have status 'Submitted'") + \
" :" + tl.name + " (" + _(tl.status) + ")", raise_exception=True) " :" + tl.name + " (" + _(tl.status) + ")", raise_exception=True)
def set_status(self): def set_status(self):
self.doc.status = { self.status = {
"0": "Draft", "0": "Draft",
"1": "Submitted", "1": "Submitted",
"2": "Cancelled" "2": "Cancelled"
}[str(self.doc.docstatus or 0)] }[str(self.docstatus or 0)]
if self.doc.sales_invoice: if self.sales_invoice:
self.doc.status = "Billed" self.status = "Billed"
def on_submit(self): def on_submit(self):
self.update_status(self.doc.name) self.update_status(self.name)
def before_cancel(self): def before_cancel(self):
self.update_status(None) self.update_status(None)
def before_update_after_submit(self): def before_update_after_submit(self):
self.update_status(self.doc.name) self.update_status(self.name)
def update_status(self, time_log_batch): def update_status(self, time_log_batch):
self.set_status() self.set_status()
for d in self.doclist.get({"doctype":"Time Log Batch Detail"}): for d in self.doclist.get({"doctype":"Time Log Batch Detail"}):
tl = frappe.bean("Time Log", d.time_log) tl = frappe.bean("Time Log", d.time_log)
tl.doc.time_log_batch = time_log_batch tl.time_log_batch = time_log_batch
tl.doc.sales_invoice = self.doc.sales_invoice tl.sales_invoice = self.sales_invoice
tl.update_after_submit() tl.update_after_submit()

View File

@ -16,54 +16,54 @@ class Customer(TransactionBase):
def autoname(self): def autoname(self):
cust_master_name = frappe.defaults.get_global_default('cust_master_name') cust_master_name = frappe.defaults.get_global_default('cust_master_name')
if cust_master_name == 'Customer Name': if cust_master_name == 'Customer Name':
if frappe.db.exists("Supplier", self.doc.customer_name): if frappe.db.exists("Supplier", self.customer_name):
msgprint(_("A Supplier exists with same name"), raise_exception=1) msgprint(_("A Supplier exists with same name"), raise_exception=1)
self.doc.name = self.doc.customer_name self.name = self.customer_name
else: else:
self.doc.name = make_autoname(self.doc.naming_series+'.#####') self.name = make_autoname(self.naming_series+'.#####')
def get_company_abbr(self): def get_company_abbr(self):
return frappe.db.get_value('Company', self.doc.company, 'abbr') return frappe.db.get_value('Company', self.company, 'abbr')
def validate_values(self): def validate_values(self):
if frappe.defaults.get_global_default('cust_master_name') == 'Naming Series' and not self.doc.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()
def update_lead_status(self): def update_lead_status(self):
if self.doc.lead_name: if self.lead_name:
frappe.db.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name) frappe.db.sql("update `tabLead` set status='Converted' where name = %s", self.lead_name)
def update_address(self): def update_address(self):
frappe.db.sql("""update `tabAddress` set customer_name=%s, modified=NOW() frappe.db.sql("""update `tabAddress` set customer_name=%s, modified=NOW()
where customer=%s""", (self.doc.customer_name, self.doc.name)) where customer=%s""", (self.customer_name, self.name))
def update_contact(self): def update_contact(self):
frappe.db.sql("""update `tabContact` set customer_name=%s, modified=NOW() frappe.db.sql("""update `tabContact` set customer_name=%s, modified=NOW()
where customer=%s""", (self.doc.customer_name, self.doc.name)) where customer=%s""", (self.customer_name, self.name))
def update_credit_days_limit(self): def update_credit_days_limit(self):
frappe.db.sql("""update tabAccount set credit_days = %s, credit_limit = %s frappe.db.sql("""update tabAccount set credit_days = %s, credit_limit = %s
where master_type='Customer' and master_name = %s""", where master_type='Customer' and master_name = %s""",
(self.doc.credit_days or 0, self.doc.credit_limit or 0, self.doc.name)) (self.credit_days or 0, self.credit_limit or 0, self.name))
def create_lead_address_contact(self): def create_lead_address_contact(self):
if self.doc.lead_name: if self.lead_name:
if not frappe.db.get_value("Address", {"lead": self.doc.lead_name, "customer": self.doc.customer}): if not frappe.db.get_value("Address", {"lead": self.lead_name, "customer": self.customer}):
frappe.db.sql("""update `tabAddress` set customer=%s, customer_name=%s where lead=%s""", frappe.db.sql("""update `tabAddress` set customer=%s, customer_name=%s where lead=%s""",
(self.doc.name, self.doc.customer_name, self.doc.lead_name)) (self.name, self.customer_name, self.lead_name))
lead = frappe.db.get_value("Lead", self.doc.lead_name, ["lead_name", "email_id", "phone", "mobile_no"], as_dict=True) lead = frappe.db.get_value("Lead", self.lead_name, ["lead_name", "email_id", "phone", "mobile_no"], as_dict=True)
c = frappe.get_doc('Contact') c = frappe.get_doc('Contact')
c.set("__islocal", 1) c.set("__islocal", 1)
c.first_name = lead.lead_name c.first_name = lead.lead_name
c.email_id = lead.email_id c.email_id = lead.email_id
c.phone = lead.phone c.phone = lead.phone
c.mobile_no = lead.mobile_no c.mobile_no = lead.mobile_no
c.customer = self.doc.name c.customer = self.name
c.customer_name = self.doc.customer_name c.customer_name = self.customer_name
c.is_primary_contact = 1 c.is_primary_contact = 1
try: try:
c.save() c.save()
@ -78,7 +78,7 @@ class Customer(TransactionBase):
self.update_contact() self.update_contact()
# create account head # create account head
create_party_account(self.doc.name, "Customer", self.doc.company) create_party_account(self.name, "Customer", self.company)
# update credit days and limit in account # update credit days and limit in account
self.update_credit_days_limit() self.update_credit_days_limit()
@ -86,14 +86,14 @@ class Customer(TransactionBase):
self.create_lead_address_contact() self.create_lead_address_contact()
def validate_name_with_customer_group(self): def validate_name_with_customer_group(self):
if frappe.db.exists("Customer Group", self.doc.name): if frappe.db.exists("Customer Group", self.name):
frappe.msgprint("An Customer Group exists with same name (%s), \ frappe.msgprint("An Customer Group exists with same name (%s), \
please change the Customer name or rename the Customer Group" % please change the Customer name or rename the Customer Group" %
self.doc.name, raise_exception=1) self.name, raise_exception=1)
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`
where customer=%s""", (self.doc.name,)) where customer=%s""", (self.name,))
for name, lead in addresses: for name, lead in addresses:
if lead: if lead:
@ -104,13 +104,13 @@ class Customer(TransactionBase):
def delete_customer_contact(self): def delete_customer_contact(self):
for contact in frappe.db.sql_list("""select name from `tabContact` for contact in frappe.db.sql_list("""select name from `tabContact`
where customer=%s""", self.doc.name): where customer=%s""", self.name):
frappe.delete_doc("Contact", contact) frappe.delete_doc("Contact", contact)
def delete_customer_account(self): def delete_customer_account(self):
"""delete customer's ledger if exist and check balance before deletion""" """delete customer's ledger if exist and check balance before deletion"""
acc = frappe.db.sql("select name from `tabAccount` where master_type = 'Customer' \ acc = frappe.db.sql("select name from `tabAccount` where master_type = 'Customer' \
and master_name = %s and docstatus < 2", self.doc.name) and master_name = %s and docstatus < 2", self.name)
if acc: if acc:
frappe.delete_doc('Account', acc[0][0]) frappe.delete_doc('Account', acc[0][0])
@ -118,12 +118,12 @@ class Customer(TransactionBase):
self.delete_customer_address() self.delete_customer_address()
self.delete_customer_contact() self.delete_customer_contact()
self.delete_customer_account() self.delete_customer_account()
if self.doc.lead_name: if self.lead_name:
frappe.db.sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name) frappe.db.sql("update `tabLead` set status='Interested' where name=%s",self.lead_name)
def before_rename(self, olddn, newdn, merge=False): def before_rename(self, olddn, newdn, merge=False):
from erpnext.accounts.utils import rename_account_for from erpnext.accounts.utils import rename_account_for
rename_account_for("Customer", olddn, newdn, merge, self.doc.company) rename_account_for("Customer", olddn, newdn, merge, self.company)
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
set_field = '' set_field = ''

View File

@ -38,7 +38,7 @@ class InstallationNote(TransactionBase):
def validate_fiscal_year(self): def validate_fiscal_year(self):
from erpnext.accounts.utils import validate_fiscal_year from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.inst_date, self.doc.fiscal_year, "Installation Date") validate_fiscal_year(self.inst_date, self.fiscal_year, "Installation Date")
def is_serial_no_added(self, item_code, serial_no): def is_serial_no_added(self, item_code, serial_no):
ar_required = frappe.db.get_value("Item", item_code, "has_serial_no") ar_required = frappe.db.get_value("Item", item_code, "has_serial_no")
@ -91,7 +91,7 @@ class InstallationNote(TransactionBase):
for d in self.get('installed_item_details'): for d in self.get('installed_item_details'):
if d.prevdoc_docname: if d.prevdoc_docname:
d_date = frappe.db.get_value("Delivery Note", d.prevdoc_docname, "posting_date") d_date = frappe.db.get_value("Delivery Note", d.prevdoc_docname, "posting_date")
if d_date > getdate(self.doc.inst_date): if d_date > getdate(self.inst_date):
msgprint("Installation Date can not be before Delivery Date " + cstr(d_date) + msgprint("Installation Date can not be before Delivery Date " + cstr(d_date) +
" for item "+d.item_code, raise_exception=1) " for item "+d.item_code, raise_exception=1)

View File

@ -24,7 +24,7 @@ def add_sales_communication(subject, content, sender, real_name, mail=None,
lead.ignore_permissions = True lead.ignore_permissions = True
lead.ignore_mandatory = True lead.ignore_mandatory = True
lead.insert() lead.insert()
lead_name = lead.doc.name lead_name = lead.name
parent_doctype = "Contact" if contact_name else "Lead" parent_doctype = "Contact" if contact_name else "Lead"
parent_name = contact_name or lead_name parent_name = contact_name or lead_name

View File

@ -13,25 +13,25 @@ from erpnext.controllers.selling_controller import SellingController
class Lead(SellingController): class Lead(SellingController):
self._prev = frappe._dict({ self._prev = frappe._dict({
"contact_date": frappe.db.get_value("Lead", self.doc.name, "contact_date") if \ "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if \
(not cint(self.doc.fields.get("__islocal"))) else None, (not cint(self.get("__islocal"))) else None,
"contact_by": frappe.db.get_value("Lead", self.doc.name, "contact_by") if \ "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if \
(not cint(self.doc.fields.get("__islocal"))) else None, (not cint(self.get("__islocal"))) else None,
}) })
def onload(self): def onload(self):
customer = frappe.db.get_value("Customer", {"lead_name": self.doc.name}) customer = frappe.db.get_value("Customer", {"lead_name": self.name})
if customer: if customer:
self.doc.fields["__is_customer"] = customer self.set("__is_customer", customer)
def validate(self): def validate(self):
self.set_status() self.set_status()
if self.doc.source == 'Campaign' and not self.doc.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("Please specify campaign name")
if self.doc.email_id: if self.email_id:
if not validate_email_add(self.doc.email_id): if not validate_email_add(self.email_id):
frappe.throw('Please enter valid email id.') frappe.throw('Please enter valid email id.')
def on_update(self): def on_update(self):
@ -40,34 +40,34 @@ class Lead(SellingController):
def add_calendar_event(self, opts=None, force=False): def add_calendar_event(self, opts=None, force=False):
super(DocType, self).add_calendar_event({ super(DocType, self).add_calendar_event({
"owner": self.doc.lead_owner, "owner": self.lead_owner,
"subject": ('Contact ' + cstr(self.doc.lead_name)), "subject": ('Contact ' + cstr(self.lead_name)),
"description": ('Contact ' + cstr(self.doc.lead_name)) + \ "description": ('Contact ' + cstr(self.lead_name)) + \
(self.doc.contact_by and ('. By : ' + cstr(self.doc.contact_by)) or '') + \ (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '') + \
(self.doc.remark and ('.To Discuss : ' + cstr(self.doc.remark)) or '') (self.remark and ('.To Discuss : ' + cstr(self.remark)) or '')
}, force) }, force)
def check_email_id_is_unique(self): def check_email_id_is_unique(self):
if self.doc.email_id: if self.email_id:
# validate email is unique # validate email is unique
email_list = frappe.db.sql("""select name from tabLead where email_id=%s""", email_list = frappe.db.sql("""select name from tabLead where email_id=%s""",
self.doc.email_id) self.email_id)
if len(email_list) > 1: if len(email_list) > 1:
items = [e[0] for e in email_list if e[0]!=self.doc.name] items = [e[0] for e in email_list if e[0]!=self.name]
frappe.msgprint(_("""Email Id must be unique, already exists for: """) + \ frappe.msgprint(_("""Email Id must be unique, already exists for: """) + \
", ".join(items), raise_exception=True) ", ".join(items), raise_exception=True)
def on_trash(self): def on_trash(self):
frappe.db.sql("""update `tabSupport Ticket` set lead='' where lead=%s""", frappe.db.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
self.doc.name) self.name)
self.delete_events() self.delete_events()
def has_customer(self): def has_customer(self):
return frappe.db.get_value("Customer", {"lead_name": self.doc.name}) return frappe.db.get_value("Customer", {"lead_name": self.name})
def has_opportunity(self): def has_opportunity(self):
return frappe.db.get_value("Opportunity", {"lead": self.doc.name, "docstatus": 1, return frappe.db.get_value("Opportunity", {"lead": self.name, "docstatus": 1,
"status": ["!=", "Lost"]}) "status": ["!=", "Lost"]})
@frappe.whitelist() @frappe.whitelist()
@ -78,12 +78,12 @@ def _make_customer(source_name, target_doclist=None, ignore_permissions=False):
from frappe.model.mapper import get_mapped_doclist from frappe.model.mapper import get_mapped_doclist
def set_missing_values(source, target): def set_missing_values(source, target):
if source.doc.company_name: if source.company_name:
target[0].customer_type = "Company" target[0].customer_type = "Company"
target[0].customer_name = source.doc.company_name target[0].customer_name = source.company_name
else: else:
target[0].customer_type = "Individual" target[0].customer_type = "Individual"
target[0].customer_name = source.doc.lead_name target[0].customer_name = source.lead_name
target[0].customer_group = frappe.db.get_default("customer_group") target[0].customer_group = frappe.db.get_default("customer_group")

View File

@ -61,22 +61,22 @@ class Opportunity(TransactionBase):
opts.description = "" opts.description = ""
if self.doc.customer: if self.customer:
if self.doc.contact_person: if self.contact_person:
opts.description = 'Contact '+cstr(self.doc.contact_person) opts.description = 'Contact '+cstr(self.contact_person)
else: else:
opts.description = 'Contact customer '+cstr(self.doc.customer) opts.description = 'Contact customer '+cstr(self.customer)
elif self.doc.lead: elif self.lead:
if self.doc.contact_display: if self.contact_display:
opts.description = 'Contact '+cstr(self.doc.contact_display) opts.description = 'Contact '+cstr(self.contact_display)
else: else:
opts.description = 'Contact lead '+cstr(self.doc.lead) opts.description = 'Contact lead '+cstr(self.lead)
opts.subject = opts.description opts.subject = opts.description
opts.description += '. By : ' + cstr(self.doc.contact_by) opts.description += '. By : ' + cstr(self.contact_by)
if self.doc.to_discuss: if self.to_discuss:
opts.description += ' To Discuss : ' + cstr(self.doc.to_discuss) opts.description += ' To Discuss : ' + cstr(self.to_discuss)
super(DocType, self).add_calendar_event(opts, force) super(DocType, self).add_calendar_event(opts, force)
@ -86,17 +86,17 @@ class Opportunity(TransactionBase):
raise Exception raise Exception
def validate_lead_cust(self): def validate_lead_cust(self):
if self.doc.enquiry_from == 'Lead' and not self.doc.lead: if self.enquiry_from == 'Lead' and not self.lead:
msgprint("Lead Id is mandatory if 'Opportunity From' is selected as Lead", raise_exception=1) msgprint("Lead Id is mandatory if 'Opportunity From' is selected as Lead", raise_exception=1)
elif self.doc.enquiry_from == 'Customer' and not self.doc.customer: elif self.enquiry_from == 'Customer' and not self.customer:
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1) msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
def validate(self): def validate(self):
self._prev = frappe._dict({ self._prev = frappe._dict({
"contact_date": frappe.db.get_value("Opportunity", self.doc.name, "contact_date") if \ "contact_date": frappe.db.get_value("Opportunity", self.name, "contact_date") if \
(not cint(self.doc.fields.get("__islocal"))) else None, (not cint(self.get("__islocal"))) else None,
"contact_by": frappe.db.get_value("Opportunity", self.doc.name, "contact_by") if \ "contact_by": frappe.db.get_value("Opportunity", self.name, "contact_by") if \
(not cint(self.doc.fields.get("__islocal"))) else None, (not cint(self.get("__islocal"))) else None,
}) })
self.set_status() self.set_status()
@ -105,11 +105,11 @@ class Opportunity(TransactionBase):
self.validate_lead_cust() self.validate_lead_cust()
from erpnext.accounts.utils import validate_fiscal_year from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date") validate_fiscal_year(self.transaction_date, self.fiscal_year, "Opportunity Date")
def on_submit(self): def on_submit(self):
if self.doc.lead: if self.lead:
frappe.bean("Lead", self.doc.lead).get_controller().set_status(update=True) frappe.bean("Lead", self.lead).get_controller().set_status(update=True)
def on_cancel(self): def on_cancel(self):
if self.has_quotation(): if self.has_quotation():
@ -127,7 +127,7 @@ class Opportunity(TransactionBase):
self.delete_events() self.delete_events()
def has_quotation(self): def has_quotation(self):
return frappe.db.get_value("Quotation Item", {"prevdoc_docname": self.doc.name, "docstatus": 1}) return frappe.db.get_value("Quotation Item", {"prevdoc_docname": self.name, "docstatus": 1})
@frappe.whitelist() @frappe.whitelist()
def make_quotation(source_name, target_doclist=None): def make_quotation(source_name, target_doclist=None):

View File

@ -15,7 +15,7 @@ class Quotation(SellingController):
self.fname = 'quotation_details' self.fname = 'quotation_details'
def has_sales_order(self): def has_sales_order(self):
return frappe.db.get_value("Sales Order Item", {"prevdoc_docname": self.doc.name, "docstatus": 1}) return frappe.db.get_value("Sales Order Item", {"prevdoc_docname": self.name, "docstatus": 1})
def validate_for_items(self): def validate_for_items(self):
chk_dupl_itm = [] chk_dupl_itm = []
@ -29,7 +29,7 @@ class Quotation(SellingController):
def validate_order_type(self): def validate_order_type(self):
super(DocType, self).validate_order_type() super(DocType, self).validate_order_type()
if self.doc.order_type in ['Maintenance', 'Service']: if self.order_type in ['Maintenance', 'Service']:
for d in self.get('quotation_details'): for d in self.get('quotation_details'):
is_service_item = frappe.db.sql("select is_service_item from `tabItem` where name=%s", d.item_code) is_service_item = frappe.db.sql("select is_service_item from `tabItem` where name=%s", d.item_code)
is_service_item = is_service_item and is_service_item[0][0] or 'No' is_service_item = is_service_item and is_service_item[0][0] or 'No'
@ -74,7 +74,7 @@ class Quotation(SellingController):
self.check_item_table() self.check_item_table()
# Check for Approving Authority # Check for Approving Authority
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self) get_obj('Authorization Control').validate_approving_authority(self.doctype, self.company, self.grand_total, self)
#update enquiry status #update enquiry status
self.update_opportunity() self.update_opportunity()
@ -105,8 +105,8 @@ def _make_sales_order(source_name, target_doclist=None, ignore_permissions=False
def set_missing_values(source, target): def set_missing_values(source, target):
if customer: if customer:
target[0].customer = customer.doc.name target[0].customer = customer.name
target[0].customer_name = customer.doc.customer_name target[0].customer_name = customer.customer_name
si = frappe.bean(target) si = frappe.bean(target)
si.ignore_permissions = ignore_permissions si.ignore_permissions = ignore_permissions
@ -150,7 +150,7 @@ def _make_customer(source_name, ignore_permissions=False):
customer = frappe.bean(customer_doclist) customer = frappe.bean(customer_doclist)
customer.ignore_permissions = ignore_permissions customer.ignore_permissions = ignore_permissions
if quotation[1] == "Shopping Cart": if quotation[1] == "Shopping Cart":
customer.doc.customer_group = frappe.db.get_value("Shopping Cart Settings", None, customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None,
"default_customer_group") "default_customer_group")
try: try:
@ -159,7 +159,7 @@ def _make_customer(source_name, ignore_permissions=False):
except NameError: except NameError:
if frappe.defaults.get_global_default('cust_master_name') == "Customer Name": if frappe.defaults.get_global_default('cust_master_name') == "Customer Name":
customer.run_method("autoname") customer.run_method("autoname")
customer.doc.name += "-" + lead_name customer.name += "-" + lead_name
customer.insert() customer.insert()
return customer return customer
else: else:

View File

@ -14,16 +14,16 @@ class TestQuotation(unittest.TestCase):
quotation = frappe.bean(copy=test_records[0]) quotation = frappe.bean(copy=test_records[0])
quotation.insert() quotation.insert()
self.assertRaises(frappe.ValidationError, make_sales_order, quotation.doc.name) self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
quotation.submit() quotation.submit()
sales_order = make_sales_order(quotation.doc.name) sales_order = make_sales_order(quotation.name)
self.assertEquals(sales_order[0]["doctype"], "Sales Order") self.assertEquals(sales_order[0]["doctype"], "Sales Order")
self.assertEquals(len(sales_order), 2) self.assertEquals(len(sales_order), 2)
self.assertEquals(sales_order[1]["doctype"], "Sales Order Item") self.assertEquals(sales_order[1]["doctype"], "Sales Order Item")
self.assertEquals(sales_order[1]["prevdoc_docname"], quotation.doc.name) self.assertEquals(sales_order[1]["prevdoc_docname"], quotation.name)
self.assertEquals(sales_order[0]["customer"], "_Test Customer") self.assertEquals(sales_order[0]["customer"], "_Test Customer")
sales_order[0]["delivery_date"] = "2014-01-01" sales_order[0]["delivery_date"] = "2014-01-01"

View File

@ -10,7 +10,7 @@ class SalesBom(Document):
def autoname(self): def autoname(self):
self.doc.name = self.doc.new_item_code self.name = self.new_item_code
def validate(self): def validate(self):
self.validate_main_item() self.validate_main_item()
@ -21,7 +21,7 @@ class SalesBom(Document):
def validate_main_item(self): def validate_main_item(self):
"""main item must have Is Stock Item as No and Is Sales Item as Yes""" """main item must have Is Stock Item as No and Is Sales Item as Yes"""
if not frappe.db.sql("""select name from tabItem where name=%s and if not frappe.db.sql("""select name from tabItem where name=%s and
ifnull(is_stock_item,'')='No' and ifnull(is_sales_item,'')='Yes'""", self.doc.new_item_code): ifnull(is_stock_item,'')='No' and ifnull(is_sales_item,'')='Yes'""", self.new_item_code):
frappe.msgprint("""Parent Item %s is either a Stock Item or a not a Sales Item""", frappe.msgprint("""Parent Item %s is either a Stock Item or a not a Sales Item""",
raise_exception=1) raise_exception=1)

View File

@ -26,21 +26,21 @@ class SalesOrder(SellingController):
def validate_mandatory(self): def validate_mandatory(self):
# validate transaction date v/s delivery date # validate transaction date v/s delivery date
if self.doc.delivery_date: if self.delivery_date:
if getdate(self.doc.transaction_date) > getdate(self.doc.delivery_date): if getdate(self.transaction_date) > getdate(self.delivery_date):
msgprint("Expected Delivery Date cannot be before Sales Order Date") msgprint("Expected Delivery Date cannot be before Sales Order Date")
raise Exception raise Exception
def validate_po(self): def validate_po(self):
# validate p.o date v/s delivery date # validate p.o date v/s delivery date
if self.doc.po_date and self.doc.delivery_date and getdate(self.doc.po_date) > getdate(self.doc.delivery_date): if self.po_date and self.delivery_date and getdate(self.po_date) > getdate(self.delivery_date):
msgprint("Expected Delivery Date cannot be before Purchase Order Date") msgprint("Expected Delivery Date cannot be before Purchase Order Date")
raise Exception raise Exception
if self.doc.po_no and self.doc.customer: if self.po_no and self.customer:
so = frappe.db.sql("select name from `tabSales Order` \ so = frappe.db.sql("select name from `tabSales Order` \
where ifnull(po_no, '') = %s and name != %s and docstatus < 2\ where ifnull(po_no, '') = %s and name != %s and docstatus < 2\
and customer = %s", (self.doc.po_no, self.doc.name, self.doc.customer)) and customer = %s", (self.po_no, self.name, self.customer))
if so and so[0][0]: if so and so[0][0]:
msgprint("""Another Sales Order (%s) exists against same PO No and Customer. msgprint("""Another Sales Order (%s) exists against same PO No and Customer.
Please be sure, you are not making duplicate entry.""" % so[0][0]) Please be sure, you are not making duplicate entry.""" % so[0][0])
@ -68,7 +68,7 @@ class SalesOrder(SellingController):
chk_dupl_itm.append(f) chk_dupl_itm.append(f)
# used for production plan # used for production plan
d.transaction_date = self.doc.transaction_date d.transaction_date = self.transaction_date
tot_avail_qty = frappe.db.sql("select projected_qty from `tabBin` \ tot_avail_qty = frappe.db.sql("select projected_qty from `tabBin` \
where item_code = %s and warehouse = %s", (d.item_code,d.warehouse)) where item_code = %s and warehouse = %s", (d.item_code,d.warehouse))
@ -77,28 +77,28 @@ class SalesOrder(SellingController):
def validate_sales_mntc_quotation(self): def validate_sales_mntc_quotation(self):
for d in self.get('sales_order_details'): for d in self.get('sales_order_details'):
if d.prevdoc_docname: if d.prevdoc_docname:
res = frappe.db.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type)) res = frappe.db.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.order_type))
if not res: if not res:
msgprint("""Order Type (%s) should be same in Quotation: %s \ msgprint("""Order Type (%s) should be same in Quotation: %s \
and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname)) and current Sales Order""" % (self.order_type, d.prevdoc_docname))
def validate_order_type(self): def validate_order_type(self):
super(DocType, self).validate_order_type() super(DocType, self).validate_order_type()
def validate_delivery_date(self): def validate_delivery_date(self):
if self.doc.order_type == 'Sales' and not self.doc.delivery_date: if self.order_type == 'Sales' and not self.delivery_date:
msgprint("Please enter 'Expected Delivery Date'") msgprint("Please enter 'Expected Delivery Date'")
raise Exception raise Exception
self.validate_sales_mntc_quotation() self.validate_sales_mntc_quotation()
def validate_proj_cust(self): def validate_proj_cust(self):
if self.doc.project_name and self.doc.customer_name: if self.project_name and self.customer_name:
res = frappe.db.sql("""select name from `tabProject` where name = %s res = frappe.db.sql("""select name from `tabProject` where name = %s
and (customer = %s or ifnull(customer,'')='')""", and (customer = %s or ifnull(customer,'')='')""",
(self.doc.project_name, self.doc.customer)) (self.project_name, self.customer))
if not res: if not res:
msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name)) msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.customer,self.project_name,self.project_name))
raise Exception raise Exception
def validate(self): def validate(self):
@ -119,15 +119,15 @@ class SalesOrder(SellingController):
self.validate_with_previous_doc() self.validate_with_previous_doc()
if not self.doc.status: if not self.status:
self.doc.status = "Draft" self.status = "Draft"
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", validate_status(self.status, ["Draft", "Submitted", "Stopped",
"Cancelled"]) "Cancelled"])
if not self.doc.billing_status: self.doc.billing_status = 'Not Billed' if not self.billing_status: self.billing_status = 'Not Billed'
if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered' if not self.delivery_status: self.delivery_status = 'Not Delivered'
def validate_warehouse(self): def validate_warehouse(self):
from erpnext.stock.utils import validate_warehouse_company from erpnext.stock.utils import validate_warehouse_company
@ -136,7 +136,7 @@ class SalesOrder(SellingController):
self.doclist.get({"doctype": self.tname}) if d.warehouse])) self.doclist.get({"doctype": self.tname}) if d.warehouse]))
for w in warehouses: for w in warehouses:
validate_warehouse_company(w, self.doc.company) validate_warehouse_company(w, self.company)
def validate_with_previous_doc(self): def validate_with_previous_doc(self):
super(DocType, self).validate_with_previous_doc(self.tname, { super(DocType, self).validate_with_previous_doc(self.tname, {
@ -155,7 +155,7 @@ class SalesOrder(SellingController):
def update_prevdoc_status(self, flag): def update_prevdoc_status(self, flag):
for quotation in self.doclist.get_distinct_values("prevdoc_docname"): for quotation in self.doclist.get_distinct_values("prevdoc_docname"):
bean = frappe.bean("Quotation", quotation) bean = frappe.bean("Quotation", quotation)
if bean.doc.docstatus==2: if bean.docstatus==2:
frappe.throw(quotation + ": " + frappe._("Quotation is cancelled.")) frappe.throw(quotation + ": " + frappe._("Quotation is cancelled."))
bean.get_controller().set_status(update=True) bean.get_controller().set_status(update=True)
@ -163,17 +163,17 @@ class SalesOrder(SellingController):
def on_submit(self): def on_submit(self):
self.update_stock_ledger(update_stock = 1) self.update_stock_ledger(update_stock = 1)
self.check_credit(self.doc.grand_total) self.check_credit(self.grand_total)
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.grand_total, self) get_obj('Authorization Control').validate_approving_authority(self.doctype, self.grand_total, self)
self.update_prevdoc_status('submit') self.update_prevdoc_status('submit')
frappe.db.set(self.doc, 'status', 'Submitted') frappe.db.set(self.doc, 'status', 'Submitted')
def on_cancel(self): def on_cancel(self):
# Cannot cancel stopped SO # Cannot cancel stopped SO
if self.doc.status == 'Stopped': if self.status == 'Stopped':
msgprint("Sales Order : '%s' cannot be cancelled as it is Stopped. Unstop it for any further transactions" %(self.doc.name)) msgprint("Sales Order : '%s' cannot be cancelled as it is Stopped. Unstop it for any further transactions" %(self.name))
raise Exception raise Exception
self.check_nextdoc_docstatus() self.check_nextdoc_docstatus()
self.update_stock_ledger(update_stock = -1) self.update_stock_ledger(update_stock = -1)
@ -184,55 +184,55 @@ class SalesOrder(SellingController):
def check_nextdoc_docstatus(self): def check_nextdoc_docstatus(self):
# Checks Delivery Note # Checks Delivery Note
submit_dn = frappe.db.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1", self.doc.name) submit_dn = frappe.db.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1", self.name)
if submit_dn: if submit_dn:
msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doctype), raise_exception = 1)
# Checks Sales Invoice # Checks Sales Invoice
submit_rv = frappe.db.sql("""select t1.name submit_rv = frappe.db.sql("""select t1.name
from `tabSales Invoice` t1,`tabSales Invoice Item` t2 from `tabSales Invoice` t1,`tabSales Invoice Item` t2
where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus = 1""", where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus = 1""",
self.doc.name) self.name)
if submit_rv: if submit_rv:
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doctype), raise_exception = 1)
#check maintenance schedule #check maintenance schedule
submit_ms = frappe.db.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) submit_ms = frappe.db.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.name)
if submit_ms: if submit_ms:
msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doctype), raise_exception = 1)
# check maintenance visit # check maintenance visit
submit_mv = frappe.db.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) submit_mv = frappe.db.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.name)
if submit_mv: if submit_mv:
msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doctype), raise_exception = 1)
# check production order # check production order
pro_order = frappe.db.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name) pro_order = frappe.db.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.name)
if pro_order: if pro_order:
msgprint("""Production Order: %s exists against this sales order. msgprint("""Production Order: %s exists against this sales order.
Please cancel production order first and then cancel this sales order""" % Please cancel production order first and then cancel this sales order""" %
pro_order[0][0], raise_exception=1) pro_order[0][0], raise_exception=1)
def check_modified_date(self): def check_modified_date(self):
mod_db = frappe.db.get_value("Sales Order", self.doc.name, "modified") mod_db = frappe.db.get_value("Sales Order", self.name, "modified")
date_diff = frappe.db.sql("select TIMEDIFF('%s', '%s')" % date_diff = frappe.db.sql("select TIMEDIFF('%s', '%s')" %
( mod_db, cstr(self.doc.modified))) ( mod_db, cstr(self.modified)))
if date_diff and date_diff[0][0]: if date_diff and date_diff[0][0]:
msgprint("%s: %s has been modified after you have opened. Please Refresh" msgprint("%s: %s has been modified after you have opened. Please Refresh"
% (self.doc.doctype, self.doc.name), raise_exception=1) % (self.doctype, self.name), raise_exception=1)
def stop_sales_order(self): def stop_sales_order(self):
self.check_modified_date() self.check_modified_date()
self.update_stock_ledger(-1) self.update_stock_ledger(-1)
frappe.db.set(self.doc, 'status', 'Stopped') frappe.db.set(self.doc, 'status', 'Stopped')
msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order
you need to Unstop it.""" % (self.doc.doctype, self.doc.name)) you need to Unstop it.""" % (self.doctype, self.name))
def unstop_sales_order(self): def unstop_sales_order(self):
self.check_modified_date() self.check_modified_date()
self.update_stock_ledger(1) self.update_stock_ledger(1)
frappe.db.set(self.doc, 'status', 'Submitted') frappe.db.set(self.doc, 'status', 'Submitted')
msgprint("%s: %s has been Unstopped" % (self.doc.doctype, self.doc.name)) msgprint("%s: %s has been Unstopped" % (self.doctype, self.name))
def update_stock_ledger(self, update_stock): def update_stock_ledger(self, update_stock):
@ -243,10 +243,10 @@ class SalesOrder(SellingController):
"item_code": d['item_code'], "item_code": d['item_code'],
"warehouse": d['reserved_warehouse'], "warehouse": d['reserved_warehouse'],
"reserved_qty": flt(update_stock) * flt(d['reserved_qty']), "reserved_qty": flt(update_stock) * flt(d['reserved_qty']),
"posting_date": self.doc.transaction_date, "posting_date": self.transaction_date,
"voucher_type": self.doc.doctype, "voucher_type": self.doctype,
"voucher_no": self.doc.name, "voucher_no": self.name,
"is_amended": self.doc.amended_from and 'Yes' or 'No' "is_amended": self.amended_from and 'Yes' or 'No'
} }
update_bin(args) update_bin(args)
@ -254,7 +254,7 @@ class SalesOrder(SellingController):
pass pass
def get_portal_page(self): def get_portal_page(self):
return "order" if self.doc.docstatus==1 else None return "order" if self.docstatus==1 else None
def set_missing_values(source, target): def set_missing_values(source, target):
bean = frappe.bean(target) bean = frappe.bean(target)
@ -327,7 +327,7 @@ def make_delivery_note(source_name, target_doclist=None):
def make_sales_invoice(source_name, target_doclist=None): def make_sales_invoice(source_name, target_doclist=None):
def set_missing_values(source, target): def set_missing_values(source, target):
bean = frappe.bean(target) bean = frappe.bean(target)
bean.doc.is_pos = 0 bean.is_pos = 0
bean.run_method("onload_post_render") bean.run_method("onload_post_render")
def update_item(obj, target, source_parent): def update_item(obj, target, source_parent):

View File

@ -15,11 +15,11 @@ class TestSalesOrder(unittest.TestCase):
so = frappe.bean(copy=test_records[0]).insert() so = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_material_request, self.assertRaises(frappe.ValidationError, make_material_request,
so.doc.name) so.name)
sales_order = frappe.bean("Sales Order", so.doc.name) sales_order = frappe.bean("Sales Order", so.name)
sales_order.submit() sales_order.submit()
mr = make_material_request(so.doc.name) mr = make_material_request(so.name)
self.assertEquals(mr[0]["material_request_type"], "Purchase") self.assertEquals(mr[0]["material_request_type"], "Purchase")
self.assertEquals(len(mr), len(sales_order.doclist)) self.assertEquals(len(mr), len(sales_order.doclist))
@ -30,11 +30,11 @@ class TestSalesOrder(unittest.TestCase):
so = frappe.bean(copy=test_records[0]).insert() so = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_delivery_note, self.assertRaises(frappe.ValidationError, make_delivery_note,
so.doc.name) so.name)
sales_order = frappe.bean("Sales Order", so.doc.name) sales_order = frappe.bean("Sales Order", so.name)
sales_order.submit() sales_order.submit()
dn = make_delivery_note(so.doc.name) dn = make_delivery_note(so.name)
self.assertEquals(dn[0]["doctype"], "Delivery Note") self.assertEquals(dn[0]["doctype"], "Delivery Note")
self.assertEquals(len(dn), len(sales_order.doclist)) self.assertEquals(len(dn), len(sales_order.doclist))
@ -45,22 +45,22 @@ class TestSalesOrder(unittest.TestCase):
so = frappe.bean(copy=test_records[0]).insert() so = frappe.bean(copy=test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_sales_invoice, self.assertRaises(frappe.ValidationError, make_sales_invoice,
so.doc.name) so.name)
sales_order = frappe.bean("Sales Order", so.doc.name) sales_order = frappe.bean("Sales Order", so.name)
sales_order.submit() sales_order.submit()
si = make_sales_invoice(so.doc.name) si = make_sales_invoice(so.name)
self.assertEquals(si[0]["doctype"], "Sales Invoice") self.assertEquals(si[0]["doctype"], "Sales Invoice")
self.assertEquals(len(si), len(sales_order.doclist)) self.assertEquals(len(si), len(sales_order.doclist))
self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1) self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1)
si = frappe.bean(si) si = frappe.bean(si)
si.doc.posting_date = "2013-10-10" si.posting_date = "2013-10-10"
si.insert() si.insert()
si.submit() si.submit()
si1 = make_sales_invoice(so.doc.name) si1 = make_sales_invoice(so.name)
self.assertEquals(len([d for d in si1 if d["doctype"]=="Sales Invoice Item"]), 0) self.assertEquals(len([d for d in si1 if d["doctype"]=="Sales Invoice Item"]), 0)
@ -82,7 +82,7 @@ class TestSalesOrder(unittest.TestCase):
dn = frappe.bean(frappe.copy_doc(dn_test_records[0])) dn = frappe.bean(frappe.copy_doc(dn_test_records[0]))
dn.doclist[1].item_code = so.doclist[1].item_code dn.doclist[1].item_code = so.doclist[1].item_code
dn.doclist[1].against_sales_order = so.doc.name dn.doclist[1].against_sales_order = so.name
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
if delivered_qty: if delivered_qty:
dn.doclist[1].qty = delivered_qty dn.doclist[1].qty = delivered_qty
@ -291,9 +291,9 @@ class TestSalesOrder(unittest.TestCase):
from frappe.model.bean import BeanPermissionError from frappe.model.bean import BeanPermissionError
so = frappe.bean(copy = test_records[0]) so = frappe.bean(copy = test_records[0])
so.doc.company = "_Test Company 1" so.company = "_Test Company 1"
so.doc.conversion_rate = 0.02 so.conversion_rate = 0.02
so.doc.plc_conversion_rate = 0.02 so.plc_conversion_rate = 0.02
so.doclist[1].warehouse = "_Test Warehouse 2 - _TC1" so.doclist[1].warehouse = "_Test Warehouse 2 - _TC1"
self.assertRaises(BeanPermissionError, so.insert) self.assertRaises(BeanPermissionError, so.insert)

View File

@ -13,8 +13,8 @@ class SellingSettings(Document):
def validate(self): def validate(self):
for key in ["cust_master_name", "customer_group", "territory", "maintain_same_sales_rate", for key in ["cust_master_name", "customer_group", "territory", "maintain_same_sales_rate",
"editable_price_list_rate", "selling_price_list"]: "editable_price_list_rate", "selling_price_list"]:
frappe.db.set_default(key, self.doc.fields.get(key, "")) frappe.db.set_default(key, self.get(key, ""))
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
set_by_naming_series("Customer", "customer_name", set_by_naming_series("Customer", "customer_name",
self.doc.get("cust_master_name")=="Naming Series", hide_name_field=False) self.get("cust_master_name")=="Naming Series", hide_name_field=False)

View File

@ -14,50 +14,50 @@ class SmsCenter(Document):
def create_receiver_list(self): def create_receiver_list(self):
rec, where_clause = '', '' rec, where_clause = '', ''
if self.doc.send_to == 'All Customer Contact': if self.send_to == 'All Customer Contact':
where_clause = self.doc.customer and " and customer = '%s'" % \ where_clause = self.customer and " and customer = '%s'" % \
self.doc.customer.replace("'", "\'") or " and ifnull(customer, '') != ''" self.customer.replace("'", "\'") or " and ifnull(customer, '') != ''"
if self.doc.send_to == 'All Supplier Contact': if self.send_to == 'All Supplier Contact':
where_clause = self.doc.supplier and \ where_clause = self.supplier and \
" and ifnull(is_supplier, 0) = 1 and supplier = '%s'" % \ " and ifnull(is_supplier, 0) = 1 and supplier = '%s'" % \
self.doc.supplier.replace("'", "\'") or " and ifnull(supplier, '') != ''" self.supplier.replace("'", "\'") or " and ifnull(supplier, '') != ''"
if self.doc.send_to == 'All Sales Partner Contact': if self.send_to == 'All Sales Partner Contact':
where_clause = self.doc.sales_partner and \ where_clause = self.sales_partner and \
" and ifnull(is_sales_partner, 0) = 1 and sales_partner = '%s'" % \ " and ifnull(is_sales_partner, 0) = 1 and sales_partner = '%s'" % \
self.doc.sales_partner.replace("'", "\'") or " and ifnull(sales_partner, '') != ''" self.sales_partner.replace("'", "\'") or " and ifnull(sales_partner, '') != ''"
if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']: if self.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
rec = frappe.db.sql("""select CONCAT(ifnull(first_name,''), '', ifnull(last_name,'')), rec = frappe.db.sql("""select CONCAT(ifnull(first_name,''), '', ifnull(last_name,'')),
mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and
docstatus != 2 %s""", where_clause) docstatus != 2 %s""", where_clause)
elif self.doc.send_to == 'All Lead (Open)': elif self.send_to == 'All Lead (Open)':
rec = frappe.db.sql("""select lead_name, mobile_no from `tabLead` where rec = frappe.db.sql("""select lead_name, mobile_no from `tabLead` where
ifnull(mobile_no,'')!='' and docstatus != 2 and status='Open'""") ifnull(mobile_no,'')!='' and docstatus != 2 and status='Open'""")
elif self.doc.send_to == 'All Employee (Active)': elif self.send_to == 'All Employee (Active)':
where_clause = self.doc.department and " and department = '%s'" % \ where_clause = self.department and " and department = '%s'" % \
self.doc.department.replace("'", "\'") or "" self.department.replace("'", "\'") or ""
where_clause += self.doc.branch and " and branch = '%s'" % \ where_clause += self.branch and " and branch = '%s'" % \
self.doc.branch.replace("'", "\'") or "" self.branch.replace("'", "\'") or ""
rec = frappe.db.sql("""select employee_name, cell_number from rec = frappe.db.sql("""select employee_name, cell_number from
`tabEmployee` where status = 'Active' and docstatus < 2 and `tabEmployee` where status = 'Active' and docstatus < 2 and
ifnull(cell_number,'')!='' %s""", where_clause) ifnull(cell_number,'')!='' %s""", where_clause)
elif self.doc.send_to == 'All Sales Person': elif self.send_to == 'All Sales Person':
rec = frappe.db.sql("""select sales_person_name, mobile_no from rec = frappe.db.sql("""select sales_person_name, mobile_no from
`tabSales Person` where docstatus!=2 and ifnull(mobile_no,'')!=''""") `tabSales Person` where docstatus!=2 and ifnull(mobile_no,'')!=''""")
rec_list = '' rec_list = ''
for d in rec: for d in rec:
rec_list += d[0] + ' - ' + d[1] + '\n' rec_list += d[0] + ' - ' + d[1] + '\n'
self.doc.receiver_list = rec_list self.receiver_list = rec_list
def get_receiver_nos(self): def get_receiver_nos(self):
receiver_nos = [] receiver_nos = []
if self.doc.receiver_list: if self.receiver_list:
for d in self.doc.receiver_list.split('\n'): for d in self.receiver_list.split('\n'):
receiver_no = d receiver_no = d
if '-' in d: if '-' in d:
receiver_no = receiver_no.split('-')[1] receiver_no = receiver_no.split('-')[1]
@ -69,9 +69,9 @@ class SmsCenter(Document):
return receiver_nos return receiver_nos
def send_sms(self): def send_sms(self):
if not self.doc.message: if not self.message:
msgprint(_("Please enter message before sending")) msgprint(_("Please enter message before sending"))
else: else:
receiver_list = self.get_receiver_nos() receiver_list = self.get_receiver_nos()
if receiver_list: if receiver_list:
msgprint(get_obj('SMS Control', 'SMS Control').send_sms(receiver_list, cstr(self.doc.message))) msgprint(get_obj('SMS Control', 'SMS Control').send_sms(receiver_list, cstr(self.message)))

View File

@ -36,7 +36,7 @@ class AuthorizationControl(TransactionBase):
if not has_common(appr_roles, frappe.user.get_roles()) and not has_common(appr_users, [session['user']]): if not has_common(appr_roles, frappe.user.get_roles()) and not has_common(appr_users, [session['user']]):
msg, add_msg = '','' msg, add_msg = '',''
if max_amount: if max_amount:
dcc = get_company_currency(self.doc.company) dcc = get_company_currency(self.company)
if based_on == 'Grand Total': msg = "since Grand Total exceeds %s. %s" % (dcc, flt(max_amount)) if based_on == 'Grand Total': msg = "since Grand Total exceeds %s. %s" % (dcc, flt(max_amount))
elif based_on == 'Itemwise Discount': msg = "since Discount exceeds %s for Item Code : %s" % (cstr(max_amount)+'%', item) elif based_on == 'Itemwise Discount': msg = "since Discount exceeds %s for Item Code : %s" % (cstr(max_amount)+'%', item)
elif based_on == 'Average Discount' or based_on == 'Customerwise Discount': msg = "since Discount exceeds %s" % (cstr(max_amount)+'%') elif based_on == 'Average Discount' or based_on == 'Customerwise Discount': msg = "since Discount exceeds %s" % (cstr(max_amount)+'%')
@ -81,8 +81,8 @@ class AuthorizationControl(TransactionBase):
if based_on == 'Grand Total': auth_value = total if based_on == 'Grand Total': auth_value = total
elif based_on == 'Customerwise Discount': elif based_on == 'Customerwise Discount':
if doc_obj: if doc_obj:
if doc_obj.doc.doctype == 'Sales Invoice': customer = doc_obj.doc.customer if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer
else: customer = doc_obj.doc.customer_name else: customer = doc_obj.customer_name
add_cond = " and master_name = '"+make_esc("'")(cstr(customer))+"'" add_cond = " and master_name = '"+make_esc("'")(cstr(customer))+"'"
if based_on == 'Itemwise Discount': if based_on == 'Itemwise Discount':
if doc_obj: if doc_obj:
@ -170,11 +170,11 @@ class AuthorizationControl(TransactionBase):
if doc_obj: if doc_obj:
if doctype_name == 'Expense Claim': if doctype_name == 'Expense Claim':
rule = self.get_value_based_rule(doctype_name,doc_obj.doc.employee,doc_obj.doc.total_claimed_amount, doc_obj.doc.company) rule = self.get_value_based_rule(doctype_name,doc_obj.employee,doc_obj.total_claimed_amount, doc_obj.company)
elif doctype_name == 'Appraisal': elif doctype_name == 'Appraisal':
rule = frappe.db.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1) rule = frappe.db.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.employee, doc_obj.employee, doc_obj.company),as_dict=1)
if not rule: if not rule:
rule = frappe.db.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1) rule = frappe.db.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.employee, doc_obj.employee),as_dict=1)
if rule: if rule:
for m in rule: for m in rule:

View File

@ -17,10 +17,10 @@ class AuthorizationRule(Document):
where transaction = %s and based_on = %s and system_user = %s where transaction = %s and based_on = %s and system_user = %s
and system_role = %s and approving_user = %s and approving_role = %s and system_role = %s and approving_user = %s and approving_role = %s
and to_emp =%s and to_designation=%s and name != %s""", and to_emp =%s and to_designation=%s and name != %s""",
(self.doc.transaction, self.doc.based_on, cstr(self.doc.system_user), (self.transaction, self.based_on, cstr(self.system_user),
cstr(self.doc.system_role), cstr(self.doc.approving_user), cstr(self.system_role), cstr(self.approving_user),
cstr(self.doc.approving_role), cstr(self.doc.to_emp), cstr(self.approving_role), cstr(self.to_emp),
cstr(self.doc.to_designation), self.doc.name)) cstr(self.to_designation), self.name))
auth_exists = exists and exists[0][0] or '' auth_exists = exists and exists[0][0] or ''
if auth_exists: if auth_exists:
if cint(exists[0][1]) == 2: if cint(exists[0][1]) == 2:
@ -32,49 +32,49 @@ class AuthorizationRule(Document):
def validate_master_name(self): def validate_master_name(self):
if self.doc.based_on == 'Customerwise Discount' and \ if self.based_on == 'Customerwise Discount' and \
not frappe.db.sql("""select name from tabCustomer not frappe.db.sql("""select name from tabCustomer
where name = %s and docstatus != 2""", (self.doc.master_name)): where name = %s and docstatus != 2""", (self.master_name)):
msgprint("Please select valid Customer Name for Customerwise Discount", msgprint("Please select valid Customer Name for Customerwise Discount",
raise_exception=1) raise_exception=1)
elif self.doc.based_on == 'Itemwise Discount' and \ elif self.based_on == 'Itemwise Discount' and \
not frappe.db.sql("select name from tabItem where name = %s and docstatus != 2", not frappe.db.sql("select name from tabItem where name = %s and docstatus != 2",
(self.doc.master_name)): (self.master_name)):
msgprint("Please select valid Item Name for Itemwise Discount", raise_exception=1) msgprint("Please select valid Item Name for Itemwise Discount", raise_exception=1)
elif (self.doc.based_on == 'Grand Total' or \ elif (self.based_on == 'Grand Total' or \
self.doc.based_on == 'Average Discount') and self.doc.master_name: self.based_on == 'Average Discount') and self.master_name:
msgprint("Please remove Customer/Item Name for %s." % msgprint("Please remove Customer/Item Name for %s." %
self.doc.based_on, raise_exception=1) self.based_on, raise_exception=1)
def validate_rule(self): def validate_rule(self):
if self.doc.transaction != 'Appraisal': if self.transaction != 'Appraisal':
if not self.doc.approving_role and not self.doc.approving_user: if not self.approving_role and not self.approving_user:
msgprint("Please enter Approving Role or Approving User", raise_exception=1) msgprint("Please enter Approving Role or Approving User", raise_exception=1)
elif self.doc.system_user and self.doc.system_user == self.doc.approving_user: elif self.system_user and self.system_user == self.approving_user:
msgprint("Approving User cannot be same as user the rule is Applicable To (User)", msgprint("Approving User cannot be same as user the rule is Applicable To (User)",
raise_exception=1) raise_exception=1)
elif self.doc.system_role and self.doc.system_role == self.doc.approving_role: elif self.system_role and self.system_role == self.approving_role:
msgprint("Approving Role cannot be same as user the rule is \ msgprint("Approving Role cannot be same as user the rule is \
Applicable To (Role).", raise_exception=1) Applicable To (Role).", raise_exception=1)
elif self.doc.system_user and self.doc.approving_role and \ elif self.system_user and self.approving_role and \
has_common([self.doc.approving_role], [x[0] for x in \ has_common([self.approving_role], [x[0] for x in \
frappe.db.sql("select role from `tabUserRole` where parent = %s", \ frappe.db.sql("select role from `tabUserRole` where parent = %s", \
(self.doc.system_user))]): (self.system_user))]):
msgprint("System User : %s is assigned role : %s. So rule does not make sense" % msgprint("System User : %s is assigned role : %s. So rule does not make sense" %
(self.doc.system_user,self.doc.approving_role), raise_exception=1) (self.system_user,self.approving_role), raise_exception=1)
elif self.doc.transaction in ['Purchase Order', 'Purchase Receipt', \ elif self.transaction in ['Purchase Order', 'Purchase Receipt', \
'Purchase Invoice', 'Stock Entry'] and self.doc.based_on \ 'Purchase Invoice', 'Stock Entry'] and self.based_on \
in ['Average Discount', 'Customerwise Discount', 'Itemwise Discount']: in ['Average Discount', 'Customerwise Discount', 'Itemwise Discount']:
msgprint("You cannot set authorization on basis of Discount for %s" % msgprint("You cannot set authorization on basis of Discount for %s" %
self.doc.transaction, raise_exception=1) self.transaction, raise_exception=1)
elif self.doc.based_on == 'Average Discount' and flt(self.doc.value) > 100.00: elif self.based_on == 'Average Discount' and flt(self.value) > 100.00:
msgprint("Discount cannot given for more than 100%", raise_exception=1) msgprint("Discount cannot given for more than 100%", raise_exception=1)
elif self.doc.based_on == 'Customerwise Discount' and not self.doc.master_name: elif self.based_on == 'Customerwise Discount' and not self.master_name:
msgprint("Please enter Customer Name for 'Customerwise Discount'", msgprint("Please enter Customer Name for 'Customerwise Discount'",
raise_exception=1) raise_exception=1)
else: else:
if self.doc.transaction == 'Appraisal' and self.doc.based_on != 'Not Applicable': if self.transaction == 'Appraisal' and self.based_on != 'Not Applicable':
msgprint("Based on should be 'Not Applicable' while setting authorization rule\ msgprint("Based on should be 'Not Applicable' while setting authorization rule\
for 'Appraisal'", raise_exception=1) for 'Appraisal'", raise_exception=1)
@ -84,4 +84,4 @@ class AuthorizationRule(Document):
self.check_duplicate_entry() self.check_duplicate_entry()
self.validate_rule() self.validate_rule()
self.validate_master_name() self.validate_master_name()
if not self.doc.value: self.doc.value = 0.0 if not self.value: self.value = 0.0

View File

@ -15,77 +15,77 @@ class Company(Document):
def onload(self): def onload(self):
self.doc.fields["__transactions_exist"] = self.check_if_transactions_exist() self.set("__transactions_exist", self.check_if_transactions_exist())
def check_if_transactions_exist(self): def check_if_transactions_exist(self):
exists = False exists = False
for doctype in ["Sales Invoice", "Delivery Note", "Sales Order", "Quotation", for doctype in ["Sales Invoice", "Delivery Note", "Sales Order", "Quotation",
"Purchase Invoice", "Purchase Receipt", "Purchase Order", "Supplier Quotation"]: "Purchase Invoice", "Purchase Receipt", "Purchase Order", "Supplier Quotation"]:
if frappe.db.sql("""select name from `tab%s` where company=%s and docstatus=1 if frappe.db.sql("""select name from `tab%s` where company=%s and docstatus=1
limit 1""" % (doctype, "%s"), self.doc.name): limit 1""" % (doctype, "%s"), self.name):
exists = True exists = True
break break
return exists return exists
def validate(self): def validate(self):
if self.doc.fields.get('__islocal') and len(self.doc.abbr) > 5: if self.get('__islocal') and len(self.abbr) > 5:
frappe.msgprint("Abbreviation cannot have more than 5 characters", frappe.msgprint("Abbreviation cannot have more than 5 characters",
raise_exception=1) raise_exception=1)
self.previous_default_currency = frappe.db.get_value("Company", self.doc.name, "default_currency") self.previous_default_currency = frappe.db.get_value("Company", self.name, "default_currency")
if self.doc.default_currency and self.previous_default_currency and \ if self.default_currency and self.previous_default_currency and \
self.doc.default_currency != self.previous_default_currency and \ self.default_currency != self.previous_default_currency and \
self.check_if_transactions_exist(): self.check_if_transactions_exist():
msgprint(_("Sorry! You cannot change company's default currency, because there are existing transactions against it. You will need to cancel those transactions if you want to change the default currency."), raise_exception=True) msgprint(_("Sorry! You cannot change company's default currency, because there are existing transactions against it. You will need to cancel those transactions if you want to change the default currency."), raise_exception=True)
def on_update(self): def on_update(self):
if not frappe.db.sql("""select name from tabAccount if not frappe.db.sql("""select name from tabAccount
where company=%s and docstatus<2 limit 1""", self.doc.name): where company=%s and docstatus<2 limit 1""", self.name):
self.create_default_accounts() self.create_default_accounts()
self.create_default_warehouses() self.create_default_warehouses()
self.create_default_web_page() self.create_default_web_page()
if not frappe.db.get_value("Cost Center", {"group_or_ledger": "Ledger", if not frappe.db.get_value("Cost Center", {"group_or_ledger": "Ledger",
"company": self.doc.name}): "company": self.name}):
self.create_default_cost_center() self.create_default_cost_center()
self.set_default_accounts() self.set_default_accounts()
if self.doc.default_currency: if self.default_currency:
frappe.db.set_value("Currency", self.doc.default_currency, "enabled", 1) frappe.db.set_value("Currency", self.default_currency, "enabled", 1)
def create_default_warehouses(self): def create_default_warehouses(self):
for whname in ("Stores", "Work In Progress", "Finished Goods"): for whname in ("Stores", "Work In Progress", "Finished Goods"):
if not frappe.db.exists("Warehouse", whname + " - " + self.doc.abbr): if not frappe.db.exists("Warehouse", whname + " - " + self.abbr):
stock_group = frappe.db.get_value("Account", {"account_type": "Stock", stock_group = frappe.db.get_value("Account", {"account_type": "Stock",
"group_or_ledger": "Group"}) "group_or_ledger": "Group"})
if stock_group: if stock_group:
frappe.bean({ frappe.bean({
"doctype":"Warehouse", "doctype":"Warehouse",
"warehouse_name": whname, "warehouse_name": whname,
"company": self.doc.name, "company": self.name,
"create_account_under": stock_group "create_account_under": stock_group
}).insert() }).insert()
def create_default_web_page(self): def create_default_web_page(self):
if not frappe.db.get_value("Website Settings", None, "home_page") and \ if not frappe.db.get_value("Website Settings", None, "home_page") and \
not frappe.db.sql("select name from tabCompany where name!=%s", self.doc.name): not frappe.db.sql("select name from tabCompany where name!=%s", self.name):
import os import os
with open(os.path.join(os.path.dirname(__file__), "sample_home_page.html"), "r") as webfile: with open(os.path.join(os.path.dirname(__file__), "sample_home_page.html"), "r") as webfile:
webpage = frappe.bean({ webpage = frappe.bean({
"doctype": "Web Page", "doctype": "Web Page",
"title": self.doc.name + " Home", "title": self.name + " Home",
"published": 1, "published": 1,
"description": "Standard Home Page for " + self.doc.name, "description": "Standard Home Page for " + self.name,
"main_section": webfile.read() % self.doc.fields "main_section": webfile.read() % self.fields
}).insert() }).insert()
# update in home page in settings # update in home page in settings
website_settings = frappe.bean("Website Settings", "Website Settings") website_settings = frappe.bean("Website Settings", "Website Settings")
website_settings.doc.home_page = webpage.doc.name website_settings.home_page = webpage.name
website_settings.doc.brand_html = self.doc.name website_settings.brand_html = self.name
website_settings.doc.copyright = self.doc.name website_settings.copyright = self.name
website_settings.append("top_bar_items", { website_settings.append("top_bar_items", {
"doctype": "Top Bar Item", "doctype": "Top Bar Item",
"label":"Contact", "label":"Contact",
@ -98,21 +98,21 @@ class Company(Document):
}) })
website_settings.save() website_settings.save()
style_settings = frappe.bean("Style Settings", "Style Settings") style_settings = frappe.bean("Style Settings", "Style Settings")
style_settings.doc.top_bar_background = "F2F2F2" style_settings.top_bar_background = "F2F2F2"
style_settings.doc.font_size = "15px" style_settings.font_size = "15px"
style_settings.save() style_settings.save()
def create_default_accounts(self): def create_default_accounts(self):
if self.doc.chart_of_accounts: if self.chart_of_accounts:
self.import_chart_of_account() self.import_chart_of_account()
else: else:
self.create_standard_accounts() self.create_standard_accounts()
frappe.db.set(self.doc, "receivables_group", "Accounts Receivable - " + self.doc.abbr) frappe.db.set(self.doc, "receivables_group", "Accounts Receivable - " + self.abbr)
frappe.db.set(self.doc, "payables_group", "Accounts Payable - " + self.doc.abbr) frappe.db.set(self.doc, "payables_group", "Accounts Payable - " + self.abbr)
def import_chart_of_account(self): def import_chart_of_account(self):
chart = frappe.bean("Chart of Accounts", self.doc.chart_of_accounts) chart = frappe.bean("Chart of Accounts", self.chart_of_accounts)
chart.make_controller().create_accounts(self.doc.name) chart.make_controller().create_accounts(self.name)
def add_acc(self,lst): def add_acc(self,lst):
account = frappe.bean({ account = frappe.bean({
@ -122,16 +122,16 @@ class Company(Document):
}) })
for d in self.fld_dict.keys(): for d in self.fld_dict.keys():
account.doc.fields[d] = (d == 'parent_account' and lst[self.fld_dict[d]]) and lst[self.fld_dict[d]] +' - '+ self.doc.abbr or lst[self.fld_dict[d]] account.set(d, (d == 'parent_account' and lst[self.fld_dict[d]]) and lst[self.fld_dict[d]] +' - '+ self.abbr or lst[self.fld_dict[d]])
account.insert() account.insert()
def set_default_accounts(self): def set_default_accounts(self):
def _set_default_accounts(accounts): def _set_default_accounts(accounts):
for field, account_type in accounts.items(): for field, account_type in accounts.items():
account = frappe.db.get_value("Account", {"account_type": account_type, account = frappe.db.get_value("Account", {"account_type": account_type,
"group_or_ledger": "Ledger", "company": self.doc.name}) "group_or_ledger": "Ledger", "company": self.name})
if account and not self.doc.fields.get(field): if account and not self.get(field):
frappe.db.set(self.doc, field, account) frappe.db.set(self.doc, field, account)
_set_default_accounts({ _set_default_accounts({
@ -149,16 +149,16 @@ class Company(Document):
def create_default_cost_center(self): def create_default_cost_center(self):
cc_list = [ cc_list = [
{ {
'cost_center_name': self.doc.name, 'cost_center_name': self.name,
'company':self.doc.name, 'company':self.name,
'group_or_ledger':'Group', 'group_or_ledger':'Group',
'parent_cost_center':'' 'parent_cost_center':''
}, },
{ {
'cost_center_name':'Main', 'cost_center_name':'Main',
'company':self.doc.name, 'company':self.name,
'group_or_ledger':'Ledger', 'group_or_ledger':'Ledger',
'parent_cost_center':self.doc.name + ' - ' + self.doc.abbr 'parent_cost_center':self.name + ' - ' + self.abbr
}, },
] ]
for cc in cc_list: for cc in cc_list:
@ -166,34 +166,34 @@ class Company(Document):
cc_bean = frappe.bean(cc) cc_bean = frappe.bean(cc)
cc_bean.ignore_permissions = True cc_bean.ignore_permissions = True
if cc.get("cost_center_name") == self.doc.name: if cc.get("cost_center_name") == self.name:
cc_bean.ignore_mandatory = True cc_bean.ignore_mandatory = True
cc_bean.insert() cc_bean.insert()
frappe.db.set(self.doc, "cost_center", "Main - " + self.doc.abbr) frappe.db.set(self.doc, "cost_center", "Main - " + self.abbr)
def on_trash(self): def on_trash(self):
""" """
Trash accounts and cost centers for this company if no gl entry exists Trash accounts and cost centers for this company if no gl entry exists
""" """
rec = frappe.db.sql("SELECT name from `tabGL Entry` where company = %s", self.doc.name) rec = frappe.db.sql("SELECT name from `tabGL Entry` where company = %s", self.name)
if not rec: if not rec:
#delete tabAccount #delete tabAccount
frappe.db.sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.doc.name) frappe.db.sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.name)
#delete cost center child table - budget detail #delete cost center child table - budget detail
frappe.db.sql("delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc where bd.parent = cc.name and cc.company = %s", self.doc.name) frappe.db.sql("delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc where bd.parent = cc.name and cc.company = %s", self.name)
#delete cost center #delete cost center
frappe.db.sql("delete from `tabCost Center` WHERE company = %s order by lft desc, rgt desc", self.doc.name) frappe.db.sql("delete from `tabCost Center` WHERE company = %s order by lft desc, rgt desc", self.name)
if not frappe.db.get_value("Stock Ledger Entry", {"company": self.doc.name}): if not frappe.db.get_value("Stock Ledger Entry", {"company": self.name}):
frappe.db.sql("""delete from `tabWarehouse` where company=%s""", self.doc.name) frappe.db.sql("""delete from `tabWarehouse` where company=%s""", self.name)
frappe.defaults.clear_default("company", value=self.doc.name) frappe.defaults.clear_default("company", value=self.name)
frappe.db.sql("""update `tabSingles` set value="" frappe.db.sql("""update `tabSingles` set value=""
where doctype='Global Defaults' and field='default_company' where doctype='Global Defaults' and field='default_company'
and value=%s""", self.doc.name) and value=%s""", self.name)
def before_rename(self, olddn, newdn, merge=False): def before_rename(self, olddn, newdn, merge=False):
if merge: if merge:
@ -219,114 +219,114 @@ class Company(Document):
} }
acc_list_common = [ acc_list_common = [
['Application of Funds (Assets)','','Group','','Balance Sheet',self.doc.name,''], ['Application of Funds (Assets)','','Group','','Balance Sheet',self.name,''],
['Current Assets','Application of Funds (Assets)','Group','','Balance Sheet',self.doc.name,''], ['Current Assets','Application of Funds (Assets)','Group','','Balance Sheet',self.name,''],
['Accounts Receivable','Current Assets','Group','','Balance Sheet',self.doc.name,''], ['Accounts Receivable','Current Assets','Group','','Balance Sheet',self.name,''],
['Bank Accounts','Current Assets','Group','Bank','Balance Sheet',self.doc.name,''], ['Bank Accounts','Current Assets','Group','Bank','Balance Sheet',self.name,''],
['Cash In Hand','Current Assets','Group','Cash','Balance Sheet',self.doc.name,''], ['Cash In Hand','Current Assets','Group','Cash','Balance Sheet',self.name,''],
['Cash','Cash In Hand','Ledger','Cash','Balance Sheet',self.doc.name,''], ['Cash','Cash In Hand','Ledger','Cash','Balance Sheet',self.name,''],
['Loans and Advances (Assets)','Current Assets','Group','','Balance Sheet',self.doc.name,''], ['Loans and Advances (Assets)','Current Assets','Group','','Balance Sheet',self.name,''],
['Securities and Deposits','Current Assets','Group','','Balance Sheet',self.doc.name,''], ['Securities and Deposits','Current Assets','Group','','Balance Sheet',self.name,''],
['Earnest Money','Securities and Deposits','Ledger','','Balance Sheet',self.doc.name,''], ['Earnest Money','Securities and Deposits','Ledger','','Balance Sheet',self.name,''],
['Stock Assets','Current Assets','Group','Stock','Balance Sheet',self.doc.name,''], ['Stock Assets','Current Assets','Group','Stock','Balance Sheet',self.name,''],
['Tax Assets','Current Assets','Group','','Balance Sheet',self.doc.name,''], ['Tax Assets','Current Assets','Group','','Balance Sheet',self.name,''],
['Fixed Assets','Application of Funds (Assets)','Group','','Balance Sheet',self.doc.name,''], ['Fixed Assets','Application of Funds (Assets)','Group','','Balance Sheet',self.name,''],
['Capital Equipments','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.doc.name,''], ['Capital Equipments','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.name,''],
['Computers','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.doc.name,''], ['Computers','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.name,''],
['Furniture and Fixture','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.doc.name,''], ['Furniture and Fixture','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.name,''],
['Office Equipments','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.doc.name,''], ['Office Equipments','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.name,''],
['Plant and Machinery','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.doc.name,''], ['Plant and Machinery','Fixed Assets','Ledger','Fixed Asset','Balance Sheet',self.name,''],
['Investments','Application of Funds (Assets)','Group','','Balance Sheet',self.doc.name,''], ['Investments','Application of Funds (Assets)','Group','','Balance Sheet',self.name,''],
['Temporary Accounts (Assets)','Application of Funds (Assets)','Group','','Balance Sheet',self.doc.name,''], ['Temporary Accounts (Assets)','Application of Funds (Assets)','Group','','Balance Sheet',self.name,''],
['Temporary Account (Assets)','Temporary Accounts (Assets)','Ledger','','Balance Sheet',self.doc.name,''], ['Temporary Account (Assets)','Temporary Accounts (Assets)','Ledger','','Balance Sheet',self.name,''],
['Expenses','','Group','Expense Account','Profit and Loss',self.doc.name,''], ['Expenses','','Group','Expense Account','Profit and Loss',self.name,''],
['Direct Expenses','Expenses','Group','Expense Account','Profit and Loss',self.doc.name,''], ['Direct Expenses','Expenses','Group','Expense Account','Profit and Loss',self.name,''],
['Stock Expenses','Direct Expenses','Group','Expense Account','Profit and Loss',self.doc.name,''], ['Stock Expenses','Direct Expenses','Group','Expense Account','Profit and Loss',self.name,''],
['Cost of Goods Sold','Stock Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Cost of Goods Sold','Stock Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Stock Adjustment','Stock Expenses','Ledger','Stock Adjustment','Profit and Loss',self.doc.name,''], ['Stock Adjustment','Stock Expenses','Ledger','Stock Adjustment','Profit and Loss',self.name,''],
['Expenses Included In Valuation', "Stock Expenses", 'Ledger', 'Expenses Included In Valuation', 'Profit and Loss', self.doc.name, ''], ['Expenses Included In Valuation', "Stock Expenses", 'Ledger', 'Expenses Included In Valuation', 'Profit and Loss', self.name, ''],
['Indirect Expenses','Expenses','Group','Expense Account','Profit and Loss',self.doc.name,''], ['Indirect Expenses','Expenses','Group','Expense Account','Profit and Loss',self.name,''],
['Advertising and Publicity','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.doc.name,''], ['Advertising and Publicity','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.name,''],
['Bad Debts Written Off','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Bad Debts Written Off','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Bank Charges','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Bank Charges','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Books and Periodicals','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Books and Periodicals','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Charity and Donations','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Charity and Donations','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Commission on Sales','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Commission on Sales','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Conveyance Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Conveyance Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Customer Entertainment Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Customer Entertainment Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Depreciation Account','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Depreciation Account','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Freight and Forwarding Charges','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.doc.name,''], ['Freight and Forwarding Charges','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.name,''],
['Legal Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Legal Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Miscellaneous Expenses','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.doc.name,''], ['Miscellaneous Expenses','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.name,''],
['Office Maintenance Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Office Maintenance Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Office Rent','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Office Rent','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Postal Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Postal Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Print and Stationary','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Print and Stationary','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Rounded Off','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Rounded Off','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Salary','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Salary','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Sales Promotion Expenses','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.doc.name,''], ['Sales Promotion Expenses','Indirect Expenses','Ledger','Chargeable','Profit and Loss',self.name,''],
['Service Charges Paid','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Service Charges Paid','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Staff Welfare Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Staff Welfare Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Telephone Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Telephone Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Travelling Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Travelling Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Water and Electricity Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.doc.name,''], ['Water and Electricity Expenses','Indirect Expenses','Ledger','Expense Account','Profit and Loss',self.name,''],
['Income','','Group','','Profit and Loss',self.doc.name,''], ['Income','','Group','','Profit and Loss',self.name,''],
['Direct Income','Income','Group','Income Account','Profit and Loss',self.doc.name,''], ['Direct Income','Income','Group','Income Account','Profit and Loss',self.name,''],
['Sales','Direct Income','Ledger','Income Account','Profit and Loss',self.doc.name,''], ['Sales','Direct Income','Ledger','Income Account','Profit and Loss',self.name,''],
['Service','Direct Income','Ledger','Income Account','Profit and Loss',self.doc.name,''], ['Service','Direct Income','Ledger','Income Account','Profit and Loss',self.name,''],
['Indirect Income','Income','Group','Income Account','Profit and Loss',self.doc.name,''], ['Indirect Income','Income','Group','Income Account','Profit and Loss',self.name,''],
['Source of Funds (Liabilities)','','Group','','Balance Sheet',self.doc.name,''], ['Source of Funds (Liabilities)','','Group','','Balance Sheet',self.name,''],
['Capital Account','Source of Funds (Liabilities)','Group','','Balance Sheet',self.doc.name,''], ['Capital Account','Source of Funds (Liabilities)','Group','','Balance Sheet',self.name,''],
['Reserves and Surplus','Capital Account','Ledger','','Balance Sheet',self.doc.name,''], ['Reserves and Surplus','Capital Account','Ledger','','Balance Sheet',self.name,''],
['Shareholders Funds','Capital Account','Ledger','','Balance Sheet',self.doc.name,''], ['Shareholders Funds','Capital Account','Ledger','','Balance Sheet',self.name,''],
['Current Liabilities','Source of Funds (Liabilities)','Group','','Balance Sheet',self.doc.name,''], ['Current Liabilities','Source of Funds (Liabilities)','Group','','Balance Sheet',self.name,''],
['Accounts Payable','Current Liabilities','Group','','Balance Sheet',self.doc.name,''], ['Accounts Payable','Current Liabilities','Group','','Balance Sheet',self.name,''],
['Stock Liabilities','Current Liabilities','Group','','Balance Sheet',self.doc.name,''], ['Stock Liabilities','Current Liabilities','Group','','Balance Sheet',self.name,''],
['Stock Received But Not Billed', 'Stock Liabilities', 'Ledger', 'Stock Received But Not Billed', 'Balance Sheet', self.doc.name, ''], ['Stock Received But Not Billed', 'Stock Liabilities', 'Ledger', 'Stock Received But Not Billed', 'Balance Sheet', self.name, ''],
['Duties and Taxes','Current Liabilities','Group','','Balance Sheet',self.doc.name,''], ['Duties and Taxes','Current Liabilities','Group','','Balance Sheet',self.name,''],
['Loans (Liabilities)','Current Liabilities','Group','','Balance Sheet',self.doc.name,''], ['Loans (Liabilities)','Current Liabilities','Group','','Balance Sheet',self.name,''],
['Secured Loans','Loans (Liabilities)','Group','','Balance Sheet',self.doc.name,''], ['Secured Loans','Loans (Liabilities)','Group','','Balance Sheet',self.name,''],
['Unsecured Loans','Loans (Liabilities)','Group','','Balance Sheet',self.doc.name,''], ['Unsecured Loans','Loans (Liabilities)','Group','','Balance Sheet',self.name,''],
['Bank Overdraft Account','Loans (Liabilities)','Group','','Balance Sheet',self.doc.name,''], ['Bank Overdraft Account','Loans (Liabilities)','Group','','Balance Sheet',self.name,''],
['Temporary Accounts (Liabilities)','Source of Funds (Liabilities)','Group','','Balance Sheet',self.doc.name,''], ['Temporary Accounts (Liabilities)','Source of Funds (Liabilities)','Group','','Balance Sheet',self.name,''],
['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','','Balance Sheet',self.doc.name,''] ['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','','Balance Sheet',self.name,'']
] ]
acc_list_india = [ acc_list_india = [
['CENVAT Capital Goods','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT Capital Goods','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT Service Tax','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT Service Tax','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT Service Tax Cess 1','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT Service Tax Cess 1','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT Service Tax Cess 2','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT Service Tax Cess 2','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT Edu Cess','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT Edu Cess','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT SHE Cess','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['CENVAT SHE Cess','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['Excise Duty 4','Tax Assets','Ledger','Tax','Balance Sheet',self.doc.name,'4.00'], ['Excise Duty 4','Tax Assets','Ledger','Tax','Balance Sheet',self.name,'4.00'],
['Excise Duty 8','Tax Assets','Ledger','Tax','Balance Sheet',self.doc.name,'8.00'], ['Excise Duty 8','Tax Assets','Ledger','Tax','Balance Sheet',self.name,'8.00'],
['Excise Duty 10','Tax Assets','Ledger','Tax','Balance Sheet',self.doc.name,'10.00'], ['Excise Duty 10','Tax Assets','Ledger','Tax','Balance Sheet',self.name,'10.00'],
['Excise Duty 14','Tax Assets','Ledger','Tax','Balance Sheet',self.doc.name,'14.00'], ['Excise Duty 14','Tax Assets','Ledger','Tax','Balance Sheet',self.name,'14.00'],
['Excise Duty Edu Cess 2','Tax Assets','Ledger','Tax','Balance Sheet',self.doc.name,'2.00'], ['Excise Duty Edu Cess 2','Tax Assets','Ledger','Tax','Balance Sheet',self.name,'2.00'],
['Excise Duty SHE Cess 1','Tax Assets','Ledger','Tax','Balance Sheet',self.doc.name,'1.00'], ['Excise Duty SHE Cess 1','Tax Assets','Ledger','Tax','Balance Sheet',self.name,'1.00'],
['P L A','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['P L A','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['P L A - Cess Portion','Tax Assets','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['P L A - Cess Portion','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['Edu. Cess on Excise','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'2.00'], ['Edu. Cess on Excise','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'2.00'],
['Edu. Cess on Service Tax','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'2.00'], ['Edu. Cess on Service Tax','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'2.00'],
['Edu. Cess on TDS','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'2.00'], ['Edu. Cess on TDS','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'2.00'],
['Excise Duty @ 4','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'4.00'], ['Excise Duty @ 4','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'4.00'],
['Excise Duty @ 8','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'8.00'], ['Excise Duty @ 8','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'8.00'],
['Excise Duty @ 10','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'10.00'], ['Excise Duty @ 10','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'10.00'],
['Excise Duty @ 14','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'14.00'], ['Excise Duty @ 14','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'14.00'],
['Service Tax','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'10.3'], ['Service Tax','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'10.3'],
['SHE Cess on Excise','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'1.00'], ['SHE Cess on Excise','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'1.00'],
['SHE Cess on Service Tax','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'1.00'], ['SHE Cess on Service Tax','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'1.00'],
['SHE Cess on TDS','Duties and Taxes','Ledger','Tax','Balance Sheet',self.doc.name,'1.00'], ['SHE Cess on TDS','Duties and Taxes','Ledger','Tax','Balance Sheet',self.name,'1.00'],
['Professional Tax','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['Professional Tax','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['VAT','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['VAT','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['TDS (Advertisement)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['TDS (Advertisement)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['TDS (Commission)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['TDS (Commission)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['TDS (Contractor)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['TDS (Contractor)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['TDS (Interest)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['TDS (Interest)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['TDS (Rent)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''], ['TDS (Rent)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,''],
['TDS (Salary)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.doc.name,''] ['TDS (Salary)','Duties and Taxes','Ledger','Chargeable','Balance Sheet',self.name,'']
] ]
# load common account heads # load common account heads
for d in acc_list_common: for d in acc_list_common:

View File

@ -11,10 +11,10 @@ from frappe.model.controller import DocListController
class CurrencyExchange(DocListController): class CurrencyExchange(DocListController):
def autoname(self): def autoname(self):
self.doc.name = self.doc.from_currency + "-" + self.doc.to_currency self.name = self.from_currency + "-" + self.to_currency
def validate(self): def validate(self):
self.validate_value("exchange_rate", ">", 0) self.validate_value("exchange_rate", ">", 0)
if self.doc.from_currency == self.doc.to_currency: if self.from_currency == self.to_currency:
msgprint(_("From Currency and To Currency cannot be same"), raise_exception=True) msgprint(_("From Currency and To Currency cannot be same"), raise_exception=True)

View File

@ -12,10 +12,10 @@ class CustomerGroup(DocTypeNestedSet):
def validate(self): def validate(self):
if frappe.db.sql("select name from `tabCustomer Group` where name = %s and docstatus = 2", if frappe.db.sql("select name from `tabCustomer Group` where name = %s and docstatus = 2",
(self.doc.customer_group_name)): (self.customer_group_name)):
msgprint("""Another %s record is trashed. msgprint("""Another %s record is trashed.
To untrash please go to Setup -> Recycle Bin.""" % To untrash please go to Setup -> Recycle Bin.""" %
(self.doc.customer_group_name), raise_exception = 1) (self.customer_group_name), raise_exception = 1)
def on_update(self): def on_update(self):
self.validate_name_with_customer() self.validate_name_with_customer()
@ -23,23 +23,23 @@ class CustomerGroup(DocTypeNestedSet):
self.validate_one_root() self.validate_one_root()
def validate_name_with_customer(self): def validate_name_with_customer(self):
if frappe.db.exists("Customer", self.doc.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 (%s), \
please change the Customer Group name or rename the Customer" % please change the Customer Group name or rename the Customer" %
self.doc.name, raise_exception=1) self.name, raise_exception=1)
def on_trash(self): def on_trash(self):
cust = frappe.db.sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s", cust = frappe.db.sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s",
self.doc.name) self.name)
cust = [d[0] for d in cust] cust = [d[0] for d in cust]
if cust: if cust:
msgprint("""Customer Group: %s can not be trashed/deleted \ msgprint("""Customer Group: %s can not be trashed/deleted \
because it is used in customer: %s. because it is used in customer: %s.
To trash/delete this, remove/change customer group in customer master""" % To trash/delete this, remove/change customer group in customer master""" %
(self.doc.name, cust or ''), raise_exception=1) (self.name, cust or ''), raise_exception=1)
if frappe.db.sql("select name from `tabCustomer Group` where parent_customer_group = %s \ if frappe.db.sql("select name from `tabCustomer Group` where parent_customer_group = %s \
and docstatus != 2", self.doc.name): and docstatus != 2", self.name):
msgprint("Child customer group exists for this customer group. \ msgprint("Child customer group exists for this customer group. \
You can not trash/cancel/delete this customer group.", raise_exception=1) You can not trash/cancel/delete this customer group.", raise_exception=1)

View File

@ -50,7 +50,7 @@ class EmailDigest(DocListController):
super(EmailDigest, self).__init__(arg1, arg2) super(EmailDigest, self).__init__(arg1, arg2)
self.from_date, self.to_date = self.get_from_to_date() self.from_date, self.to_date = self.get_from_to_date()
self.future_from_date, self.future_to_date = self.get_future_from_to_date() self.future_from_date, self.future_to_date = self.get_future_from_to_date()
self.currency = frappe.db.get_value("Company", self.doc.company, self.currency = frappe.db.get_value("Company", self.company,
"default_currency") "default_currency")
def get_users(self): def get_users(self):
@ -61,8 +61,8 @@ class EmailDigest(DocListController):
and user_type != "Website User" and user_type != "Website User"
order by enabled desc, name asc""".format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS, as_dict=1) order by enabled desc, name asc""".format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS, as_dict=1)
if self.doc.recipient_list: if self.recipient_list:
recipient_list = self.doc.recipient_list.split("\n") recipient_list = self.recipient_list.split("\n")
else: else:
recipient_list = [] recipient_list = []
for p in user_list: for p in user_list:
@ -75,7 +75,7 @@ class EmailDigest(DocListController):
valid_users = [p[0] for p in frappe.db.sql("""select name from `tabUser` valid_users = [p[0] for p in frappe.db.sql("""select name from `tabUser`
where enabled=1""")] where enabled=1""")]
recipients = filter(lambda r: r in valid_users, recipients = filter(lambda r: r in valid_users,
self.doc.recipient_list.split("\n")) self.recipient_list.split("\n"))
common_msg = self.get_common_content() common_msg = self.get_common_content()
if recipients: if recipients:
@ -85,7 +85,7 @@ class EmailDigest(DocListController):
if msg_for_this_receipient: if msg_for_this_receipient:
sendmail(recipients=user_id, sendmail(recipients=user_id,
subject="[ERPNext] [{frequency} Digest] {name}".format( subject="[ERPNext] [{frequency} Digest] {name}".format(
frequency=self.doc.frequency, name=self.doc.name), frequency=self.frequency, name=self.name),
msg=msg_for_this_receipient) msg=msg_for_this_receipient)
def get_digest_msg(self): def get_digest_msg(self):
@ -97,7 +97,7 @@ class EmailDigest(DocListController):
for module, content in content_sequence: for module, content in content_sequence:
module_out = [] module_out = []
for ctype in content: for ctype in content:
if self.doc.fields.get(ctype) and hasattr(self, "get_"+ctype): if self.get(ctype) and hasattr(self, "get_"+ctype):
module_out.append(getattr(self, "get_"+ctype)()) module_out.append(getattr(self, "get_"+ctype)())
if any([m[0] for m in module_out]): if any([m[0] for m in module_out]):
out += [[1, "<h4>" + _(module) + "</h4>"]] + module_out + [[1, "<hr>"]] out += [[1, "<h4>" + _(module) + "</h4>"]] + module_out + [[1, "<hr>"]]
@ -114,7 +114,7 @@ class EmailDigest(DocListController):
out = [] out = []
for ctype in user_specific_content: for ctype in user_specific_content:
if self.doc.fields.get(ctype) and hasattr(self, "get_"+ctype): if self.get(ctype) and hasattr(self, "get_"+ctype):
out.append(getattr(self, "get_"+ctype)(user_id)) out.append(getattr(self, "get_"+ctype)(user_id))
frappe.session.user = original_session_user frappe.session.user = original_session_user
@ -139,16 +139,16 @@ class EmailDigest(DocListController):
if no_value: if no_value:
no_value = """<h4>No Updates For:</h4>""" + "\n".join(no_value) no_value = """<h4>No Updates For:</h4>""" + "\n".join(no_value)
date = self.doc.frequency == "Daily" and formatdate(self.from_date) or \ date = self.frequency == "Daily" and formatdate(self.from_date) or \
"%s to %s" % (formatdate(self.from_date), formatdate(self.to_date)) "%s to %s" % (formatdate(self.from_date), formatdate(self.to_date))
msg = digest_template % { msg = digest_template % {
"digest": self.doc.frequency + " Digest", "digest": self.frequency + " Digest",
"date": date, "date": date,
"company": self.doc.company, "company": self.company,
"with_value": with_value, "with_value": with_value,
"no_value": no_value or "", "no_value": no_value or "",
"name": self.doc.name "name": self.name
} }
return msg return msg
@ -337,7 +337,7 @@ class EmailDigest(DocListController):
def get_new_count(self, doctype, label, docstatus=0, filter_by_company=True): def get_new_count(self, doctype, label, docstatus=0, filter_by_company=True):
if filter_by_company: if filter_by_company:
company = """and company="%s" """ % self.doc.company.replace('"', '\"') company = """and company="%s" """ % self.company.replace('"', '\"')
else: else:
company = "" company = ""
count = frappe.db.sql("""select count(*) from `tab%s` count = frappe.db.sql("""select count(*) from `tab%s`
@ -352,7 +352,7 @@ class EmailDigest(DocListController):
count_sum = frappe.db.sql("""select count(*), sum(ifnull(`%s`, 0)) count_sum = frappe.db.sql("""select count(*), sum(ifnull(`%s`, 0))
from `tab%s` where docstatus=1 and company = %s and from `tab%s` where docstatus=1 and company = %s and
date(creation)>=%s and date(creation)<=%s""" % (sum_field, doctype, "%s", date(creation)>=%s and date(creation)<=%s""" % (sum_field, doctype, "%s",
"%s", "%s"), (self.doc.company, self.from_date, self.to_date)) "%s", "%s"), (self.company, self.from_date, self.to_date))
count, total = count_sum and count_sum[0] or (0, 0) count, total = count_sum and count_sum[0] or (0, 0)
return count, self.get_html(label, self.currency, return count, self.get_html(label, self.currency,
@ -379,7 +379,7 @@ class EmailDigest(DocListController):
where company=%s where company=%s
and posting_date <= %s %s""" % ("%s", "%s", and posting_date <= %s %s""" % ("%s", "%s",
from_date and "and posting_date>='%s'" % from_date or ""), from_date and "and posting_date>='%s'" % from_date or ""),
(self.doc.company, to_date or self.to_date), as_dict=1) (self.company, to_date or self.to_date), as_dict=1)
# cache if it is the normal cases # cache if it is the normal cases
if from_date==self.from_date and to_date==self.to_date: if from_date==self.from_date and to_date==self.to_date:
@ -393,17 +393,17 @@ class EmailDigest(DocListController):
root_type, account_type, account_name, master_type root_type, account_type, account_name, master_type
from `tabAccount` where company=%s and docstatus < 2 from `tabAccount` where company=%s and docstatus < 2
and group_or_ledger = "Ledger" order by lft""", and group_or_ledger = "Ledger" order by lft""",
(self.doc.company,), as_dict=1) (self.company,), as_dict=1)
return self.accounts return self.accounts
def get_from_to_date(self): def get_from_to_date(self):
today = now_datetime().date() today = now_datetime().date()
# decide from date based on email digest frequency # decide from date based on email digest frequency
if self.doc.frequency == "Daily": if self.frequency == "Daily":
# from date, to_date is yesterday # from date, to_date is yesterday
from_date = to_date = today - timedelta(days=1) from_date = to_date = today - timedelta(days=1)
elif self.doc.frequency == "Weekly": elif self.frequency == "Weekly":
# from date is the previous week's monday # from date is the previous week's monday
from_date = today - timedelta(days=today.weekday(), weeks=1) from_date = today - timedelta(days=today.weekday(), weeks=1)
# to date is sunday i.e. the previous day # to date is sunday i.e. the previous day
@ -420,10 +420,10 @@ class EmailDigest(DocListController):
today = now_datetime().date() today = now_datetime().date()
# decide from date based on email digest frequency # decide from date based on email digest frequency
if self.doc.frequency == "Daily": if self.frequency == "Daily":
# from date, to_date is today # from date, to_date is today
from_date = to_date = today from_date = to_date = today
elif self.doc.frequency == "Weekly": elif self.frequency == "Weekly":
# from date is the current week's monday # from date is the current week's monday
from_date = today - timedelta(days=today.weekday()) from_date = today - timedelta(days=today.weekday())
# to date is the current week's sunday # to date is the current week's sunday
@ -441,13 +441,13 @@ class EmailDigest(DocListController):
send_date = to_date + timedelta(days=1) send_date = to_date + timedelta(days=1)
if self.doc.frequency == "Daily": if self.frequency == "Daily":
next_send_date = send_date + timedelta(days=1) next_send_date = send_date + timedelta(days=1)
elif self.doc.frequency == "Weekly": elif self.frequency == "Weekly":
next_send_date = send_date + timedelta(weeks=1) next_send_date = send_date + timedelta(weeks=1)
else: else:
next_send_date = send_date + relativedelta(months=1) next_send_date = send_date + relativedelta(months=1)
self.doc.next_send = formatdate(next_send_date) + " at midnight" self.next_send = formatdate(next_send_date) + " at midnight"
return send_date return send_date

View File

@ -12,6 +12,6 @@ class FeaturesSetup(Document):
""" """
from frappe.model import default_fields from frappe.model import default_fields
from frappe.utils import set_default from frappe.utils import set_default
for key in self.doc.fields: for key in self.fields:
if key not in default_fields: if key not in default_fields:
set_default(key, self.doc.fields[key]) set_default(key, self.fields[key])

View File

@ -32,11 +32,11 @@ class GlobalDefaults(Document):
self.update_control_panel() self.update_control_panel()
for key in keydict: for key in keydict:
frappe.db.set_default(key, self.doc.fields.get(keydict[key], '')) frappe.db.set_default(key, self.get(keydict[key], ''))
# update year start date and year end date from fiscal_year # update year start date and year end date from fiscal_year
year_start_end_date = frappe.db.sql("""select year_start_date, year_end_date year_start_end_date = frappe.db.sql("""select year_start_date, year_end_date
from `tabFiscal Year` where name=%s""", self.doc.current_fiscal_year) from `tabFiscal Year` where name=%s""", self.current_fiscal_year)
ysd = year_start_end_date[0][0] or '' ysd = year_start_end_date[0][0] or ''
yed = year_start_end_date[0][1] or '' yed = year_start_end_date[0][1] or ''
@ -46,25 +46,25 @@ class GlobalDefaults(Document):
frappe.db.set_default('year_end_date', yed.strftime('%Y-%m-%d')) frappe.db.set_default('year_end_date', yed.strftime('%Y-%m-%d'))
# enable default currency # enable default currency
if self.doc.default_currency: if self.default_currency:
frappe.db.set_value("Currency", self.doc.default_currency, "enabled", 1) frappe.db.set_value("Currency", self.default_currency, "enabled", 1)
# clear cache # clear cache
frappe.clear_cache() frappe.clear_cache()
def validate_session_expiry(self): def validate_session_expiry(self):
if self.doc.session_expiry: if self.session_expiry:
parts = self.doc.session_expiry.split(":") parts = self.session_expiry.split(":")
if len(parts)!=2 or not (cint(parts[0]) or cint(parts[1])): if len(parts)!=2 or not (cint(parts[0]) or cint(parts[1])):
frappe.msgprint("""Session Expiry must be in format hh:mm""", frappe.msgprint("""Session Expiry must be in format hh:mm""",
raise_exception=1) raise_exception=1)
def update_control_panel(self): def update_control_panel(self):
cp_bean = frappe.bean("Control Panel") cp_bean = frappe.bean("Control Panel")
if self.doc.country: if self.country:
cp_bean.doc.country = self.doc.country cp_bean.country = self.country
if self.doc.time_zone: if self.time_zone:
cp_bean.doc.time_zone = self.doc.time_zone cp_bean.time_zone = self.time_zone
cp_bean.ignore_permissions = True cp_bean.ignore_permissions = True
cp_bean.save() cp_bean.save()

View File

@ -10,9 +10,9 @@ class ItemGroup(DocTypeNestedSet):
self.nsm_parent_field = 'parent_item_group' self.nsm_parent_field = 'parent_item_group'
def validate(self): def validate(self):
if not self.doc.parent_website_route: if not self.parent_website_route:
self.doc.parent_website_route = frappe.get_website_route("Item Group", self.parent_website_route = frappe.get_website_route("Item Group",
self.doc.parent_item_group) self.parent_item_group)
def on_update(self): def on_update(self):
DocTypeNestedSet.on_update(self) DocTypeNestedSet.on_update(self)
@ -22,6 +22,6 @@ class ItemGroup(DocTypeNestedSet):
self.validate_one_root() self.validate_one_root()
def validate_name_with_item(self): def validate_name_with_item(self):
if frappe.db.exists("Item", self.doc.name): if frappe.db.exists("Item", self.name):
frappe.msgprint("An item exists with same name (%s), please change the \ frappe.msgprint("An item exists with same name (%s), please change the \
item group name or rename the item" % self.doc.name, raise_exception=1) item group name or rename the item" % self.name, raise_exception=1)

View File

@ -128,11 +128,11 @@ class TestItem(unittest.TestCase):
def test_recursion(self): def test_recursion(self):
group_b = frappe.bean("Item Group", "_Test Item Group B") group_b = frappe.bean("Item Group", "_Test Item Group B")
group_b.doc.parent_item_group = "_Test Item Group B - 3" group_b.parent_item_group = "_Test Item Group B - 3"
self.assertRaises(NestedSetRecursionError, group_b.save) self.assertRaises(NestedSetRecursionError, group_b.save)
# cleanup # cleanup
group_b.doc.parent_item_group = "All Item Groups" group_b.parent_item_group = "All Item Groups"
group_b.save() group_b.save()
def test_rebuild_tree(self): def test_rebuild_tree(self):
@ -141,7 +141,7 @@ class TestItem(unittest.TestCase):
def move_it_back(self): def move_it_back(self):
group_b = frappe.bean("Item Group", "_Test Item Group B") group_b = frappe.bean("Item Group", "_Test Item Group B")
group_b.doc.parent_item_group = "All Item Groups" group_b.parent_item_group = "All Item Groups"
group_b.save() group_b.save()
self.test_basic_tree() self.test_basic_tree()
@ -151,9 +151,9 @@ class TestItem(unittest.TestCase):
# put B under C # put B under C
group_b = frappe.bean("Item Group", "_Test Item Group B") group_b = frappe.bean("Item Group", "_Test Item Group B")
lft, rgt = group_b.doc.lft, group_b.doc.rgt lft, rgt = group_b.lft, group_b.rgt
group_b.doc.parent_item_group = "_Test Item Group C" group_b.parent_item_group = "_Test Item Group C"
group_b.save() group_b.save()
self.test_basic_tree() self.test_basic_tree()
@ -170,7 +170,7 @@ class TestItem(unittest.TestCase):
def test_move_group_into_root(self): def test_move_group_into_root(self):
group_b = frappe.bean("Item Group", "_Test Item Group B") group_b = frappe.bean("Item Group", "_Test Item Group B")
group_b.doc.parent_item_group = "" group_b.parent_item_group = ""
self.assertRaises(NestedSetMultipleRootsError, group_b.save) self.assertRaises(NestedSetMultipleRootsError, group_b.save)
# trick! works because it hasn't been rolled back :D # trick! works because it hasn't been rolled back :D
@ -187,10 +187,10 @@ class TestItem(unittest.TestCase):
old_lft, old_rgt = frappe.db.get_value("Item Group", "_Test Item Group C", ["lft", "rgt"]) old_lft, old_rgt = frappe.db.get_value("Item Group", "_Test Item Group C", ["lft", "rgt"])
group_b_3 = frappe.bean("Item Group", "_Test Item Group B - 3") group_b_3 = frappe.bean("Item Group", "_Test Item Group B - 3")
lft, rgt = group_b_3.doc.lft, group_b_3.doc.rgt lft, rgt = group_b_3.lft, group_b_3.rgt
# child of right sibling is moved into it # child of right sibling is moved into it
group_b_3.doc.parent_item_group = "_Test Item Group C" group_b_3.parent_item_group = "_Test Item Group C"
group_b_3.save() group_b_3.save()
self.test_basic_tree() self.test_basic_tree()
@ -204,7 +204,7 @@ class TestItem(unittest.TestCase):
# move it back # move it back
group_b_3 = frappe.bean("Item Group", "_Test Item Group B - 3") group_b_3 = frappe.bean("Item Group", "_Test Item Group B - 3")
group_b_3.doc.parent_item_group = "_Test Item Group B" group_b_3.parent_item_group = "_Test Item Group B"
group_b_3.save() group_b_3.save()
self.test_basic_tree() self.test_basic_tree()
@ -251,7 +251,7 @@ class TestItem(unittest.TestCase):
where parent_item_group='_Test Item Group C'"""): where parent_item_group='_Test Item Group C'"""):
bean = frappe.bean("Item Group", name) bean = frappe.bean("Item Group", name)
bean.doc.parent_item_group = "_Test Item Group B" bean.parent_item_group = "_Test Item Group B"
bean.save() bean.save()
self.test_basic_tree() self.test_basic_tree()

View File

@ -13,8 +13,8 @@ from frappe.model.document import Document
class JobsEmailSettings(Document): class JobsEmailSettings(Document):
def validate(self): def validate(self):
if cint(self.doc.extract_emails) and not (self.doc.email_id and self.doc.host and \ if cint(self.extract_emails) and not (self.email_id and self.host and \
self.doc.username and self.doc.password): self.username and self.password):
frappe.msgprint(_("""Host, Email and Password required if emails are to be pulled"""), frappe.msgprint(_("""Host, Email and Password required if emails are to be pulled"""),
raise_exception=True) raise_exception=True)

View File

@ -31,10 +31,10 @@ class NamingSeries(Document):
def update_series(self, arg=None): def update_series(self, arg=None):
"""update series list""" """update series list"""
self.check_duplicate() self.check_duplicate()
series_list = self.doc.set_options.split("\n") series_list = self.set_options.split("\n")
# set in doctype # set in doctype
self.set_series_for(self.doc.select_doc_for_series, series_list) self.set_series_for(self.select_doc_for_series, series_list)
# create series # create series
map(self.insert_series, [d.split('.')[0] for d in series_list]) map(self.insert_series, [d.split('.')[0] for d in series_list])
@ -49,7 +49,7 @@ class NamingSeries(Document):
# validate names # validate names
for i in options: self.validate_series_name(i) for i in options: self.validate_series_name(i)
if self.doc.user_must_always_select: if self.user_must_always_select:
options = [''] + options options = [''] + options
default = '' default = ''
else: else:
@ -78,7 +78,7 @@ class NamingSeries(Document):
}) })
ps.save() ps.save()
self.doc.set_options = "\n".join(options) self.set_options = "\n".join(options)
frappe.clear_cache(doctype=doctype) frappe.clear_cache(doctype=doctype)
@ -90,17 +90,17 @@ class NamingSeries(Document):
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.doc.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.doc.select_doc_for_series) self.select_doc_for_series)
)) ))
sr = [[frappe.model.doctype.get_property(p, 'options', 'naming_series'), p] sr = [[frappe.model.doctype.get_property(p, 'options', 'naming_series'), p]
for p in parent] for p in parent]
options = self.scrub_options_list(self.doc.set_options.split("\n")) options = self.scrub_options_list(self.set_options.split("\n"))
for series in options: for series in options:
dt.validate_series(series, self.doc.select_doc_for_series) dt.validate_series(series, self.select_doc_for_series)
for i in sr: for i in sr:
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")]
@ -120,15 +120,15 @@ class NamingSeries(Document):
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=''):
sr = frappe.model.doctype.get_property(self.doc.select_doc_for_series, sr = frappe.model.doctype.get_property(self.select_doc_for_series,
'options', 'naming_series') 'options', 'naming_series')
return sr return sr
def get_current(self, arg=None): def get_current(self, arg=None):
"""get series current""" """get series current"""
if self.doc.prefix: if self.prefix:
self.doc.current_value = frappe.db.get_value("Series", self.current_value = frappe.db.get_value("Series",
self.doc.prefix.split('.')[0], "current") self.prefix.split('.')[0], "current")
def insert_series(self, series): def insert_series(self, series):
"""insert series if missing""" """insert series if missing"""
@ -136,11 +136,11 @@ class NamingSeries(Document):
frappe.db.sql("insert into tabSeries (name, current) values (%s, 0)", (series)) frappe.db.sql("insert into tabSeries (name, current) values (%s, 0)", (series))
def update_series_start(self): def update_series_start(self):
if self.doc.prefix: if self.prefix:
prefix = self.doc.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.doc.current_value, prefix)) (self.current_value, prefix))
msgprint(_("Series Updated Successfully")) msgprint(_("Series Updated Successfully"))
else: else:
msgprint(_("Please select prefix first")) msgprint(_("Please select prefix first"))

View File

@ -18,7 +18,7 @@ class NotificationControl(Document):
return v and v[0][0] or '' return v and v[0][0] or ''
def set_message(self, arg = ''): def set_message(self, arg = ''):
fn = self.doc.select_transaction.lower().replace(' ', '_') + '_message' fn = self.select_transaction.lower().replace(' ', '_') + '_message'
frappe.db.set(self.doc, fn, self.doc.custom_message) frappe.db.set(self.doc, fn, self.custom_message)
msgprint("Custom Message for %s updated!" % self.doc.select_transaction) msgprint("Custom Message for %s updated!" % self.select_transaction)

View File

@ -13,8 +13,8 @@ from frappe.model.document import Document
class SalesEmailSettings(Document): class SalesEmailSettings(Document):
def validate(self): def validate(self):
if cint(self.doc.extract_emails) and not (self.doc.email_id and self.doc.host and \ if cint(self.extract_emails) and not (self.email_id and self.host and \
self.doc.username and self.doc.password): self.username and self.password):
frappe.msgprint(_("""Host, Email and Password required if emails are to be pulled"""), frappe.msgprint(_("""Host, Email and Password required if emails are to be pulled"""),
raise_exception=True) raise_exception=True)

View File

@ -8,8 +8,8 @@ from frappe.model.document import Document
class SalesPartner(Document): class SalesPartner(Document):
def validate(self): def validate(self):
if self.doc.partner_website and not self.doc.partner_website.startswith("http"): if self.partner_website and not self.partner_website.startswith("http"):
self.doc.partner_website = "http://" + self.doc.partner_website self.partner_website = "http://" + self.partner_website
def get_contacts(self, nm): def get_contacts(self, nm):
if nm: if nm:
@ -21,4 +21,4 @@ class SalesPartner(Document):
return '' return ''
def get_page_title(self): def get_page_title(self):
return self.doc.partner_name return self.partner_name

View File

@ -20,9 +20,9 @@ class SalesPerson(DocTypeNestedSet):
self.validate_one_root() self.validate_one_root()
def get_email_id(self): def get_email_id(self):
if self.doc.employee: if self.employee:
user = frappe.db.get_value("Employee", self.doc.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.doc.employee) frappe.throw("User ID not set for Employee %s" % self.employee)
else: else:
return frappe.db.get_value("User", user, "email") or user return frappe.db.get_value("User", user, "email") or user

View File

@ -114,8 +114,8 @@ def import_defaults():
bean = frappe.bean(r) bean = frappe.bean(r)
# ignore mandatory for root # ignore mandatory for root
parent_link_field = ("parent_" + scrub(bean.doc.doctype)) parent_link_field = ("parent_" + scrub(bean.doctype))
if parent_link_field in bean.doc.fields and not bean.doc.fields.get(parent_link_field): if parent_link_field in bean.fields and not bean.get(parent_link_field):
bean.ignore_mandatory = True bean.ignore_mandatory = True
bean.insert() bean.insert()
@ -133,7 +133,7 @@ def feature_setup():
'fs_recurring_invoice', 'fs_pos', 'fs_manufacturing', 'fs_quality', 'fs_recurring_invoice', 'fs_pos', 'fs_manufacturing', 'fs_quality',
'fs_page_break', 'fs_more_info', 'fs_pos_view' 'fs_page_break', 'fs_more_info', 'fs_pos_view'
] ]
bean.doc.fields.update(dict(zip(flds, [1]*len(flds)))) bean.update(dict(zip(flds, [1]*len(flds))))
bean.save() bean.save()
def set_single_defaults(): def set_single_defaults():
@ -144,7 +144,7 @@ def set_single_defaults():
try: try:
b = frappe.bean(dt, dt) b = frappe.bean(dt, dt)
for fieldname, value in default_values: for fieldname, value in default_values:
b.doc.fields[fieldname] = value b.set(fieldname, value)
b.save() b.save()
except frappe.MandatoryError: except frappe.MandatoryError:
pass pass

View File

@ -117,7 +117,7 @@ def set_defaults(args):
frappe.db.set_value("Currency", args.get("currency"), "enabled", 1) frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
global_defaults = frappe.bean("Global Defaults", "Global Defaults") global_defaults = frappe.bean("Global Defaults", "Global Defaults")
global_defaults.doc.fields.update({ global_defaults.update({
'current_fiscal_year': args.curr_fiscal_year, 'current_fiscal_year': args.curr_fiscal_year,
'default_currency': args.get('currency'), 'default_currency': args.get('currency'),
'default_company':args.get('company_name'), 'default_company':args.get('company_name'),
@ -129,41 +129,41 @@ def set_defaults(args):
global_defaults.save() global_defaults.save()
accounts_settings = frappe.bean("Accounts Settings") accounts_settings = frappe.bean("Accounts Settings")
accounts_settings.doc.auto_accounting_for_stock = 1 accounts_settings.auto_accounting_for_stock = 1
accounts_settings.save() accounts_settings.save()
stock_settings = frappe.bean("Stock Settings") stock_settings = frappe.bean("Stock Settings")
stock_settings.doc.item_naming_by = "Item Code" stock_settings.item_naming_by = "Item Code"
stock_settings.doc.valuation_method = "FIFO" stock_settings.valuation_method = "FIFO"
stock_settings.doc.stock_uom = "Nos" stock_settings.stock_uom = "Nos"
stock_settings.doc.auto_indent = 1 stock_settings.auto_indent = 1
stock_settings.save() stock_settings.save()
selling_settings = frappe.bean("Selling Settings") selling_settings = frappe.bean("Selling Settings")
selling_settings.doc.cust_master_name = "Customer Name" selling_settings.cust_master_name = "Customer Name"
selling_settings.doc.so_required = "No" selling_settings.so_required = "No"
selling_settings.doc.dn_required = "No" selling_settings.dn_required = "No"
selling_settings.save() selling_settings.save()
buying_settings = frappe.bean("Buying Settings") buying_settings = frappe.bean("Buying Settings")
buying_settings.doc.supp_master_name = "Supplier Name" buying_settings.supp_master_name = "Supplier Name"
buying_settings.doc.po_required = "No" buying_settings.po_required = "No"
buying_settings.doc.pr_required = "No" buying_settings.pr_required = "No"
buying_settings.doc.maintain_same_rate = 1 buying_settings.maintain_same_rate = 1
buying_settings.save() buying_settings.save()
notification_control = frappe.bean("Notification Control") notification_control = frappe.bean("Notification Control")
notification_control.doc.quotation = 1 notification_control.quotation = 1
notification_control.doc.sales_invoice = 1 notification_control.sales_invoice = 1
notification_control.doc.purchase_order = 1 notification_control.purchase_order = 1
notification_control.save() notification_control.save()
hr_settings = frappe.bean("HR Settings") hr_settings = frappe.bean("HR Settings")
hr_settings.doc.emp_created_by = "Naming Series" hr_settings.emp_created_by = "Naming Series"
hr_settings.save() hr_settings.save()
email_settings = frappe.bean("Outgoing Email Settings") email_settings = frappe.bean("Outgoing Email Settings")
email_settings.doc.send_print_in_body_and_attachment = 1 email_settings.send_print_in_body_and_attachment = 1
email_settings.save() email_settings.save()
# control panel # control panel
@ -196,14 +196,14 @@ def create_email_digest():
for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}): for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
if fieldname != "scheduler_errors": if fieldname != "scheduler_errors":
edigest.doc.fields[fieldname] = 1 edigest.set(fieldname, 1)
edigest.insert() edigest.insert()
# scheduler errors digest # scheduler errors digest
if companies: if companies:
edigest = frappe.new_bean("Email Digest") edigest = frappe.new_bean("Email Digest")
edigest.doc.fields.update({ edigest.update({
"name": "Scheduler Errors", "name": "Scheduler Errors",
"company": companies[0], "company": companies[0],
"frequency": "Daily", "frequency": "Daily",

View File

@ -11,7 +11,7 @@ def boot_session(bootinfo):
import frappe.model.doc import frappe.model.doc
bootinfo['custom_css'] = frappe.db.get_value('Style Settings', None, 'custom_css') or '' bootinfo['custom_css'] = frappe.db.get_value('Style Settings', None, 'custom_css') or ''
bootinfo['website_settings'] = frappe.model.doc.getsingle('Website Settings') bootinfo['website_settings'] = frappe.model.getsingle('Website Settings')
if frappe.session['user']!='Guest': if frappe.session['user']!='Guest':
bootinfo['letter_heads'] = get_letter_heads() bootinfo['letter_heads'] = get_letter_heads()

View File

@ -14,19 +14,19 @@ from frappe.model.document import Document
class Bin(Document): class Bin(Document):
def validate(self): def validate(self):
if self.doc.fields.get("__islocal") or not self.doc.stock_uom: if self.get("__islocal") or not self.stock_uom:
self.doc.stock_uom = frappe.db.get_value('Item', self.doc.item_code, 'stock_uom') self.stock_uom = frappe.db.get_value('Item', self.item_code, 'stock_uom')
self.validate_mandatory() self.validate_mandatory()
self.doc.projected_qty = flt(self.doc.actual_qty) + flt(self.doc.ordered_qty) + \ self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \
flt(self.doc.indented_qty) + flt(self.doc.planned_qty) - flt(self.doc.reserved_qty) flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty)
def validate_mandatory(self): def validate_mandatory(self):
qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty'] qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
for f in qf: for f in qf:
if (not self.doc.fields.has_key(f)) or (not self.doc.fields[f]): if (not self.has_key(f)) or (not self.fields[f]):
self.doc.fields[f] = 0.0 self.set(f, 0.0)
def update_stock(self, args): def update_stock(self, args):
self.update_qty(args) self.update_qty(args)
@ -39,24 +39,24 @@ class Bin(Document):
# update valuation and qty after transaction for post dated entry # update valuation and qty after transaction for post dated entry
update_entries_after({ update_entries_after({
"item_code": self.doc.item_code, "item_code": self.item_code,
"warehouse": self.doc.warehouse, "warehouse": self.warehouse,
"posting_date": args.get("posting_date"), "posting_date": args.get("posting_date"),
"posting_time": args.get("posting_time") "posting_time": args.get("posting_time")
}) })
def update_qty(self, args): def update_qty(self, args):
# update the stock values (for current quantities) # update the stock values (for current quantities)
self.doc.actual_qty = flt(self.doc.actual_qty) + flt(args.get("actual_qty")) self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty"))
self.doc.ordered_qty = flt(self.doc.ordered_qty) + flt(args.get("ordered_qty")) self.ordered_qty = flt(self.ordered_qty) + flt(args.get("ordered_qty"))
self.doc.reserved_qty = flt(self.doc.reserved_qty) + flt(args.get("reserved_qty")) self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty"))
self.doc.indented_qty = flt(self.doc.indented_qty) + flt(args.get("indented_qty")) self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty"))
self.doc.planned_qty = flt(self.doc.planned_qty) + flt(args.get("planned_qty")) self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty"))
self.doc.projected_qty = flt(self.doc.actual_qty) + flt(self.doc.ordered_qty) + \ self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \
flt(self.doc.indented_qty) + flt(self.doc.planned_qty) - flt(self.doc.reserved_qty) flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty)
self.doc.save() self.save()
def get_first_sle(self): def get_first_sle(self):
sle = frappe.db.sql(""" sle = frappe.db.sql("""
@ -65,5 +65,5 @@ class Bin(Document):
and warehouse = %s and warehouse = %s
order by timestamp(posting_date, posting_time) asc, name asc order by timestamp(posting_date, posting_time) asc, name asc
limit 1 limit 1
""", (self.doc.item_code, self.doc.warehouse), as_dict=1) """, (self.item_code, self.warehouse), as_dict=1)
return sle and sle[0] or None return sle and sle[0] or None

Some files were not shown because too many files have changed in this diff Show More