update translation strings #1403

This commit is contained in:
Rushabh Mehta 2014-04-14 19:20:45 +05:30
parent 7da01d6007
commit 9f0d625300
70 changed files with 1325 additions and 1639 deletions

View File

@ -12,17 +12,17 @@ class BankReconciliation(Document):
if not (self.bank_account and self.from_date and self.to_date):
msgprint("Bank Account, From Date and To Date are Mandatory")
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""",
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.total_amount = 0.0
@ -43,13 +43,13 @@ class BankReconciliation(Document):
if d.clearance_date:
if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
frappe.throw("Clearance Date can not be before Cheque Date (Row #%s)" % d.idx)
frappe.db.set_value("Journal Voucher", d.voucher_id, "clearance_date", d.clearance_date)
frappe.db.sql("""update `tabJournal Voucher` set clearance_date = %s, modified = %s
frappe.db.sql("""update `tabJournal Voucher` set clearance_date = %s, modified = %s
where name=%s""", (d.clearance_date, nowdate(), d.voucher_id))
vouchers.append(d.voucher_id)
if vouchers:
msgprint("Clearance Date updated in %s" % ", ".join(vouchers))
msgprint("Clearance Date updated in: {0}".format(", ".join(vouchers)))
else:
msgprint(_("Clearance Date not mentioned"))
msgprint(_("Clearance Date not mentioned"))

View File

@ -10,33 +10,33 @@ from frappe.utils.nestedset import NestedSet
class CostCenter(NestedSet):
nsm_parent_field = 'parent_cost_center'
def autoname(self):
self.name = self.cost_center_name.strip() + ' - ' + \
frappe.db.get_value("Company", self.company, "abbr")
def validate_mandatory(self):
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.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.cost_center_name == self.company and self.parent_cost_center:
msgprint(_("Root cannot have a parent cost center"), raise_exception=1)
def convert_group_to_ledger(self):
if self.check_if_child_exists():
msgprint("Cost Center: %s has existing child. You can not convert this cost center to ledger" % (self.name), raise_exception=1)
msgprint(_("Cannot convert Cost Center to ledger as it has child nodes"), raise_exception=1)
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 transactions can not be converted to ledger"), raise_exception=1)
else:
self.group_or_ledger = 'Ledger'
self.save()
return 1
def convert_ledger_to_group(self):
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 transactions can not be converted to group"), raise_exception=1)
else:
self.group_or_ledger = 'Group'
self.save()
@ -44,7 +44,7 @@ class CostCenter(NestedSet):
def check_gle_exists(self):
return frappe.db.get_value("GL Entry", {"cost_center": self.name})
def check_if_child_exists(self):
return frappe.db.sql("select name from `tabCost Center` where \
parent_cost_center = %s and docstatus != 2", self.name)
@ -53,11 +53,11 @@ class CostCenter(NestedSet):
check_acc_list = []
for d in self.get('budget_details'):
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:
msgprint("Account " + d.account + "has been entered more than once for fiscal year " + d.fiscal_year, raise_exception=1)
else:
msgprint(_("Account {0} has been entered more than once for fiscal year {1}").format(d.account, d.fiscal_year), raise_exception=1)
else:
check_acc_list.append([d.account, d.fiscal_year])
def validate(self):
@ -65,25 +65,25 @@ class CostCenter(NestedSet):
Cost Center name must be unique
"""
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"), raise_exception=1)
self.validate_mandatory()
self.validate_budget_details()
def before_rename(self, olddn, newdn, merge=False):
# Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr
new_cost_center = get_name_with_abbr(newdn, self.company)
# Validate properties before merging
super(CostCenter, self).before_rename(olddn, new_cost_center, merge, "group_or_ledger")
return new_cost_center
def after_rename(self, olddn, newdn, merge=False):
if not merge:
frappe.db.set_value("Cost Center", newdn, "cost_center_name",
frappe.db.set_value("Cost Center", newdn, "cost_center_name",
" - ".join(newdn.split(" - ")[:-1]))
else:
super(CostCenter, self).after_rename(olddn, newdn, merge)

View File

@ -9,19 +9,18 @@ from frappe.utils import getdate
from frappe.model.document import Document
class FiscalYear(Document):
def set_as_default(self):
frappe.db.set_value("Global Defaults", None, "current_fiscal_year", self.name)
frappe.get_doc("Global Defaults").on_update()
# clear cache
frappe.clear_cache()
msgprint(self.name + _(""" is now the default Fiscal Year. \
Please refresh your browser for the change to take effect."""))
msgprint(_("{0} is now the default Fiscal Year. Please refresh your browser for the change to take effect.").format(self.name))
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.name))
if year_start_end_dates:
@ -36,10 +35,10 @@ class FiscalYear(Document):
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."))
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.name))
for fiscal_year, ysd, yed in year_start_end_dates:
if (getdate(self.year_start_date) == ysd and getdate(self.year_end_date) == yed) \
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

@ -57,17 +57,16 @@ class JournalVoucher(AccountsController):
def validate_debit_credit(self):
for d in self.get('entries'):
if d.debit and d.credit:
msgprint("You cannot credit and debit same account at the same time.",
raise_exception=1)
msgprint(_("You cannot credit and debit same account at the same time."), raise_exception=1)
def validate_cheque_info(self):
if self.voucher_type in ['Bank Voucher']:
if not self.cheque_no or not self.cheque_date:
msgprint("Reference No & Reference Date is required for %s" %
self.voucher_type, raise_exception=1)
msgprint(_("Reference No & Reference Date is required for {0}").format(self.voucher_type),
raise_exception=1)
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):
for d in self.get('entries'):
@ -76,19 +75,17 @@ class JournalVoucher(AccountsController):
master_type = frappe.db.get_value("Account", d.account, "master_type")
if (master_type == 'Customer' and flt(d.credit) > 0) or \
(master_type == 'Supplier' and flt(d.debit) > 0):
msgprint("Message: Please check Is Advance as 'Yes' against \
Account %s if this is an advance entry." % d.account)
msgprint(_("Please check 'Is Advance' against Account {0} if this is an advance entry.").format(d.account))
def validate_against_jv(self):
for d in self.get('entries'):
if d.against_jv:
if d.against_jv == self.name:
msgprint("You can not enter current voucher in 'Against JV' column",
raise_exception=1)
msgprint(_("You can not enter current voucher in 'Against Journal Voucher' column"), raise_exception=1)
elif not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where account = %s and docstatus = 1 and parent = %s""",
(d.account, d.against_jv)):
msgprint("Against JV: %s is not valid." % d.against_jv, raise_exception=1)
msgprint(_("Journal Voucher {0} does not have account {1}.").format(d.against_jv, d.account), raise_exception=1)
def set_against_account(self):
# Debit = Credit
@ -104,8 +101,8 @@ class JournalVoucher(AccountsController):
self.total_credit = credit
if abs(self.total_debit-self.total_credit) > 0.001:
msgprint("Debit must be equal to Credit. The difference is %s" %
(self.total_debit-self.total_credit), raise_exception=1)
msgprint(_("Debit must equal Credit. The difference is {0}").format(self.total_debit-self.total_credit),
raise_exception=1)
# update against account
for d in self.get('entries'):
@ -116,10 +113,9 @@ class JournalVoucher(AccountsController):
r = []
if self.cheque_no:
if self.cheque_date:
r.append('Via Reference #%s dated %s' %
(self.cheque_no, formatdate(self.cheque_date)))
r.append(_('Reference #{0} dated {1}').fomrat(self.cheque_no, formatdate(self.cheque_date)))
else :
msgprint("Please enter Reference date", raise_exception=1)
msgprint(_("Please enter Reference date"), raise_exception=1)
for d in self.get('entries'):
if d.against_invoice and d.credit:
@ -137,12 +133,12 @@ class JournalVoucher(AccountsController):
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d')) or ''))
if self.user_remark:
r.append("User Remark : %s"%self.user_remark)
r.append(_("Note: {0}").format(self.user_remark))
if r:
self.remark = ("\n").join(r)
else:
frappe.msgprint("User Remarks is mandatory", raise_exception=1)
frappe.msgprint(_("User Remarks is mandatory"), raise_exception=1)
def set_aging_date(self):
if self.is_opening != 'Yes':
@ -158,7 +154,7 @@ class JournalVoucher(AccountsController):
# If customer/supplier account, aging date is mandatory
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:
self.aging_date = self.posting_date
@ -195,8 +191,8 @@ class JournalVoucher(AccountsController):
credit_days = self.get_credit_days_for(d.account)
# Check credit days
if credit_days > 0 and not self.get_authorized_user() and cint(date_diff) > credit_days:
msgprint("Credit Not Allowed: Cannot allow a check that is dated \
more than %s days after the posting date" % credit_days, raise_exception=1)
msgprint(_("Maximum allowed credit is {0} days after posting date").format(credit_days),
raise_exception=1)
def get_credit_days_for(self, ac):
if not self.credit_days_for.has_key(ac):
@ -272,7 +268,7 @@ class JournalVoucher(AccountsController):
def get_balance(self):
if not self.get('entries'):
msgprint("Please enter atleast 1 entry in 'GL Entries' table")
msgprint(_("'Entries' cannot be empty"), raise_exception=True)
else:
flag, self.total_debit, self.total_credit = 0, 0, 0
diff = flt(self.difference, 2)
@ -390,7 +386,7 @@ def get_payment_entry(doc):
jv.company = doc.company
jv.fiscal_year = doc.fiscal_year
d1 = jv.append("entries")
jv.append("entries")
d2 = jv.append("entries")
if bank_account:

View File

@ -12,23 +12,23 @@ from frappe.model.document import Document
class PaymenttoInvoiceMatchingTool(Document):
def get_voucher_details(self):
total_amount = frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry`
where voucher_type = %s and voucher_no = %s
total_amount = frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry`
where voucher_type = %s and voucher_no = %s
and account = %s""", (self.voucher_type, self.voucher_no, self.account))
total_amount = total_amount and flt(total_amount[0][0]) or 0
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
and account = %s""", (self.voucher_no, self.voucher_no, self.account))
reconciled_payment = reconciled_payment and flt(reconciled_payment[0][0]) or 0
ret = {
'total_amount': total_amount,
'total_amount': total_amount,
'pending_amt_to_reconcile': total_amount - reconciled_payment
}
return ret
def get_payment_entries(self):
@ -37,16 +37,16 @@ class PaymenttoInvoiceMatchingTool(Document):
Payment entry will be decided based on account type (Dr/Cr)
"""
self.set('ir_payment_details', [])
self.set('ir_payment_details', [])
gle = self.get_gl_entries()
self.create_payment_table(gle)
def get_gl_entries(self):
self.validate_mandatory()
cond = self.from_date and " and t1.posting_date >= '" + self.from_date + "'" or ""
cond += self.to_date and " and t1.posting_date <= '" + self.to_date + "'"or ""
if self.amt_greater_than:
cond += ' and abs(ifnull(t2.debit, 0) - ifnull(t2.credit, 0)) >= ' + \
self.amt_greater_than
@ -55,13 +55,13 @@ class PaymenttoInvoiceMatchingTool(Document):
self.amt_less_than
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,
abs(sum(ifnull(t2.credit, 0)) - sum(ifnull(t2.debit, 0))) as amt_due, t1.remark,
t2.against_account, t2.name as voucher_detail_no
from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
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_jv, '')='' and t1.name != %s %s group by t1.name, t2.name """ %
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 """ %
('%s', '%s', cond), (self.account, self.voucher_no), as_dict=1)
return gle
@ -76,11 +76,11 @@ class PaymenttoInvoiceMatchingTool(Document):
ch.against_account = d.get('against_account')
ch.remarks = d.get('remark')
ch.voucher_detail_no = d.get('voucher_detail_no')
def validate_mandatory(self):
if not self.account:
msgprint("Please select Account first", raise_exception=1)
msgprint(_("Please select Account first"), raise_exception=1)
def reconcile(self):
"""
Links booking and payment voucher
@ -88,59 +88,59 @@ class PaymenttoInvoiceMatchingTool(Document):
2. split into multiple rows if partially adjusted, assign against voucher
3. submit payment voucher
"""
if not self.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.voucher_type, '%s'), self.voucher_no):
frappe.throw(_("Please select valid Voucher No to proceed"))
lst = []
for d in self.get('ir_payment_details'):
if flt(d.amt_to_be_reconciled) > 0:
args = {
'voucher_no' : d.voucher_no,
'voucher_detail_no' : d.voucher_detail_no,
'against_voucher_type' : self.voucher_type,
'voucher_detail_no' : d.voucher_detail_no,
'against_voucher_type' : self.voucher_type,
'against_voucher' : self.voucher_no,
'account' : self.account,
'is_advance' : 'No',
# 'dr_or_cr' : self.account_type=='debit' and 'credit' or 'debit',
'account' : self.account,
'is_advance' : 'No',
# 'dr_or_cr' : self.account_type=='debit' and 'credit' or 'debit',
'unadjusted_amt' : flt(d.amt_due),
'allocated_amt' : flt(d.amt_to_be_reconciled)
}
lst.append(args)
if lst:
from erpnext.accounts.utils import reconcile_against_document
reconcile_against_document(lst)
msgprint("Successfully allocated.")
msgprint(_("Successfully allocated"))
else:
msgprint("No amount allocated.", raise_exception=1)
msgprint(_("No amount allocated"), raise_exception=1)
def gl_entry_details(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
return frappe.db.sql("""select gle.voucher_no, gle.posting_date,
return frappe.db.sql("""select gle.voucher_no, gle.posting_date,
gle.debit, gle.credit from `tabGL Entry` gle
where gle.account = '%(acc)s'
where gle.account = '%(acc)s'
and gle.voucher_type = '%(dt)s'
and gle.voucher_no like '%(txt)s'
and (ifnull(gle.against_voucher, '') = ''
or ifnull(gle.against_voucher, '') = gle.voucher_no )
and (select ifnull(abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))), 0)
from `tabGL Entry`
and gle.voucher_no like '%(txt)s'
and (ifnull(gle.against_voucher, '') = ''
or ifnull(gle.against_voucher, '') = gle.voucher_no )
and (select ifnull(abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))), 0)
from `tabGL Entry`
where account = '%(acc)s'
and against_voucher_type = '%(dt)s'
and against_voucher = gle.voucher_no
and voucher_no != gle.voucher_no)
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0))
and if(gle.voucher_type='Sales Invoice', ifnull((select is_pos from `tabSales Invoice`
and against_voucher_type = '%(dt)s'
and against_voucher = gle.voucher_no
and voucher_no != gle.voucher_no)
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0))
and if(gle.voucher_type='Sales Invoice', ifnull((select is_pos from `tabSales Invoice`
where name=gle.voucher_no), 0), 0)=0
%(mcond)s
ORDER BY gle.posting_date desc, gle.voucher_no desc
ORDER BY gle.posting_date desc, gle.voucher_no desc
limit %(start)s, %(page_len)s""" % {
"dt":filters["dt"],
"acc":filters["acc"],
'mcond':get_match_cond(doctype),
'txt': "%%%s%%" % txt,
"start": start,
"dt":filters["dt"],
"acc":filters["acc"],
'mcond':get_match_cond(doctype),
'txt': "%%%s%%" % txt,
"start": start,
"page_len": page_len
})

View File

@ -16,18 +16,18 @@ class POSSetting(Document):
self.check_for_duplicate()
self.validate_expense_account()
self.validate_all_link_fields()
def check_for_duplicate(self):
res = frappe.db.sql("""select name, user from `tabPOS Setting`
where ifnull(user, '') = %s and name != %s and company = %s""",
res = frappe.db.sql("""select name, user from `tabPOS Setting`
where ifnull(user, '') = %s and name != %s and company = %s""",
(self.user, self.name, self.company))
if res:
if res[0][1]:
msgprint("POS Setting '%s' already created for user: '%s' and company: '%s'" %
(res[0][0], res[0][1], self.company), raise_exception=1)
msgprint(_("POS Setting {0} already created for user: {1} and company {2}").format(res[0][0],
res[0][1], self.company), raise_exception=1)
else:
msgprint("Global POS Setting already created - %s for this company: '%s'" %
(res[0][0], self.company), raise_exception=1)
msgprint(_("Global POS Setting {0} already created for company {1}").format(res[0][0],
self.company), raise_exception=1)
def validate_expense_account(self):
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
@ -35,13 +35,13 @@ class POSSetting(Document):
msgprint(_("Expense Account is mandatory"), raise_exception=1)
def validate_all_link_fields(self):
accounts = {"Account": [self.cash_bank_account, self.income_account,
self.expense_account], "Cost Center": [self.cost_center],
accounts = {"Account": [self.cash_bank_account, self.income_account,
self.expense_account], "Cost Center": [self.cost_center],
"Warehouse": [self.warehouse]}
for link_dt, dn_list in accounts.items():
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.company, "name": link_dn}):
frappe.throw(link_dn +_(" does not belong to ") + self.company)
@ -53,17 +53,17 @@ class POSSetting(Document):
def set_defaults(self, include_current_pos=True):
frappe.defaults.clear_default("is_pos")
if not include_current_pos:
condition = " where name != '%s'" % self.name.replace("'", "\'")
else:
condition = ""
pos_view_users = frappe.db.sql_list("""select user
pos_view_users = frappe.db.sql_list("""select user
from `tabPOS Setting` {0}""".format(condition))
for user in pos_view_users:
if user:
frappe.defaults.set_user_default("is_pos", 1, user)
else:
frappe.defaults.set_global_default("is_pos", 1)
frappe.defaults.set_global_default("is_pos", 1)

View File

@ -6,7 +6,7 @@ import frappe
from frappe.utils import cint, cstr, flt, formatdate
from frappe import msgprint, _
from frappe import msgprint, _, throw
from erpnext.setup.utils import get_company_currency
import frappe.defaults
@ -73,22 +73,15 @@ class PurchaseInvoice(BuyingController):
def check_active_purchase_items(self):
for d in self.get('entries'):
if d.item_code: # extra condn coz item_code is not mandatory in PV
valid_item = frappe.db.sql("select docstatus,is_purchase_item from tabItem where name = %s",d.item_code)
if valid_item[0][0] == 2:
msgprint("Item : '%s' is Inactive, you can restore it from Trash" %(d.item_code))
raise Exception
if not valid_item[0][1] == 'Yes':
msgprint("Item : '%s' is not Purchase Item"%(d.item_code))
raise Exception
if frappe.db.get_value("Item", d.item_code, "is_purchase_item") != 'Yes':
msgprint(_("Item {0} is not Purchase Item").format(d.item_code), raise_exception=True)
def check_conversion_rate(self):
default_currency = get_company_currency(self.company)
if not default_currency:
msgprint('Message: Please enter default currency in Company Master')
raise Exception
throw(_('Please enter default currency in Company Master'))
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.")
raise Exception
throw(_("Conversion rate cannot be 0 or 1"))
def validate_bill_no(self):
if self.bill_no and self.bill_no.lower().strip() \
@ -97,13 +90,12 @@ class PurchaseInvoice(BuyingController):
where bill_no = %s and credit_to = %s and docstatus = 1 and name != %s""",
(self.bill_no, self.credit_to, self.name))
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 \
in Purchase Invoice %s" % (cstr(b_no[0][0]), cstr(b_no[0][1])),
raise_exception=1)
throw(_("Bill No {0} already booked in Purchase Invoice {1}").format(cstr(b_no[0][0]),
cstr(b_no[0][1])))
if not self.remarks and self.bill_date:
self.remarks = (self.remarks or '') + "\n" + ("Against Bill %s dated %s"
% (self.bill_no, formatdate(self.bill_date)))
self.remarks = (self.remarks or '') + "\n" \
+ _("Against Bill %s dated %s").format(self.bill_no, formatdate(self.bill_date))
if not self.remarks:
self.remarks = "No Remarks"
@ -130,7 +122,7 @@ class PurchaseInvoice(BuyingController):
check_list.append(d.purchase_order)
stopped = frappe.db.sql("select name from `tabPurchase Order` where status = 'Stopped' and name = %s", d.purchase_order)
if stopped:
msgprint("One cannot do any transaction against 'Purchase Order' : %s, it's status is 'Stopped'" % (d.purhcase_order))
throw(_("Purchase Order {0} is 'Stopped'").format(d.purchase_order))
raise Exception
def validate_with_previous_doc(self):
@ -176,7 +168,7 @@ class PurchaseInvoice(BuyingController):
if self.is_opening != 'Yes':
self.aging_date = self.posting_date
elif not self.aging_date:
msgprint("Aging Date is mandatory for opening entry")
msgprint(_("Ageing date is mandatory for opening entry"))
raise Exception
def set_against_expense_account(self):
@ -199,8 +191,7 @@ class PurchaseInvoice(BuyingController):
against_accounts.append(stock_not_billed_account)
elif not item.expense_account:
msgprint(_("Expense account is mandatory for item") + ": " +
(item.item_code or item.item_name), raise_exception=1)
throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
elif item.expense_account not in against_accounts:
# if no auto_accounting_for_stock or not a stock item
@ -212,19 +203,18 @@ class PurchaseInvoice(BuyingController):
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
for d in self.get('entries'):
if not d.purchase_order:
msgprint("Purchse Order No. required against item %s"%d.item_code)
raise Exception
throw(_("Purchse Order number required for Item {0}").format(d.item_code))
def pr_required(self):
if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes':
for d in self.get('entries'):
if not d.purchase_receipt:
msgprint("Purchase Receipt No. required against item %s"%d.item_code)
throw(_("Purchase Receipt number required for Item {0}").format(d.item_code))
raise Exception
def validate_write_off_account(self):
if self.write_off_amount and not self.write_off_account:
msgprint("Please enter Write Off Account", raise_exception=1)
throw(_("Please enter Write Off Account"))
def check_prev_docstatus(self):
for d in self.get('entries'):

View File

@ -6,9 +6,9 @@ import frappe
import frappe.defaults
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
get_first_day, get_last_day, comma_and
get_first_day, get_last_day
from frappe.model.naming import make_autoname
from frappe import _, msgprint
from frappe import _, msgprint, throw
from erpnext.accounts.party import get_party_account, get_due_date
from erpnext.controllers.stock_controller import update_gl_entries_after
@ -165,8 +165,7 @@ class SalesInvoice(SellingController):
if d.time_log_batch:
status = frappe.db.get_value("Time Log Batch", d.time_log_batch, "status")
if status!="Submitted":
frappe.msgprint(_("Time Log Batch status must be 'Submitted'") + ":" + d.time_log_batch,
raise_exception=True)
frappe.throw(_("Time Log Batch {0} must be 'Submitted'").format(d.time_log_batch))
def set_pos_fields(self, for_validate=False):
"""Set retail related fields from pos settings"""
@ -263,10 +262,8 @@ class SalesInvoice(SellingController):
where name = %s and (ifnull(end_of_life,'')='' or end_of_life > now())""", d.item_code)
acc = frappe.db.sql("""select account_type from `tabAccount`
where name = %s and docstatus != 2""", d.income_account)
if not acc:
msgprint("Account: "+d.income_account+" does not exist in the system", raise_exception=True)
elif item and item[0][1] == 'Yes' and not acc[0][0] == 'Fixed Asset':
msgprint("Please select income head with account type 'Fixed Asset' as Item %s is an asset item" % d.item_code, raise_exception=True)
if item and item[0][1] == 'Yes' and not acc[0][0] == 'Fixed Asset':
msgprint(_("Account {0} must be of type 'Fixed Asset' as Item {1} is an Asset Item").format(d.item_code), raise_exception=True)
def validate_with_previous_doc(self):
super(SalesInvoice, self).validate_with_previous_doc(self.tname, {
@ -302,7 +299,7 @@ class SalesInvoice(SellingController):
if self.is_opening != 'Yes':
self.aging_date = self.posting_date
elif not self.aging_date:
msgprint("Aging Date is mandatory for opening entry")
msgprint(_("Ageing Date is mandatory for opening entry"))
raise Exception
@ -327,7 +324,7 @@ class SalesInvoice(SellingController):
for d in self.get('entries'):
if frappe.db.get_value('Item', d.item_code, 'is_stock_item') == 'Yes' \
and not d.get(i.lower().replace(' ','_')):
msgprint("%s is mandatory for stock item which is not mentioed against item: %s"%(i,d.item_code), raise_exception=1)
msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1)
def validate_proj_cust(self):
@ -337,34 +334,32 @@ class SalesInvoice(SellingController):
where name = %s and (customer = %s or
ifnull(customer,'')='')""", (self.project_name, self.customer))
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.customer,self.project_name))
msgprint(_("Customer {0} does not belong to project {1}").format(self.customer,self.project_name))
raise Exception
def validate_pos(self):
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 or Bank Account is mandatory for making payment entry"))
raise Exception
if flt(self.paid_amount) + flt(self.write_off_amount) \
- flt(self.grand_total) > 1/(10**(self.precision("grand_total") + 1)):
frappe.throw(_("""(Paid amount + Write Off Amount) can not be \
greater than Grand Total"""))
frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total"""))
def validate_item_code(self):
for d in self.get('entries'):
if not d.item_code:
msgprint("Please enter Item Code at line no : %s to update stock or remove check from Update Stock in Basic Info Tab." % (d.idx),
raise_exception=True)
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
def validate_delivery_note(self):
for d in self.get("entries"):
if d.delivery_note:
msgprint("""Stock update can not be made against Delivery Note""", raise_exception=1)
msgprint(_("Stock cannot be updated against Delivery Note {0}").format(d.delivery_note), raise_exception=1)
def validate_write_off_account(self):
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):
@ -396,9 +391,9 @@ class SalesInvoice(SellingController):
ps = frappe.db.sql("""select name, warehouse from `tabPOS Setting`
where ifnull(user,'') = '' and company = %s""", self.company)
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(_("POS Setting required to make POS Entry"), raise_exception=True)
elif not ps[0][1]:
msgprint("Please enter warehouse in POS Setting")
msgprint(_("Warehouse required in POS Setting"))
else:
w = ps[0][1]
return w
@ -426,7 +421,7 @@ class SalesInvoice(SellingController):
else:
# show message that the amount is not paid
frappe.db.set(self,'paid_amount',0)
frappe.msgprint("Note: Payment Entry will not be created since 'Cash/Bank Account' was not specified.")
frappe.msgprint(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"))
else:
frappe.db.set(self,'paid_amount',0)
@ -436,15 +431,15 @@ class SalesInvoice(SellingController):
submitted = frappe.db.sql("""select name from `tabSales Order`
where docstatus = 1 and name = %s""", d.sales_order)
if not submitted:
msgprint("Sales Order : "+ cstr(d.sales_order) +" is not submitted")
raise Exception , "Validation Error."
msgprint(_("Sales Order {0} is not submitted").format(d.sales_order))
raise Exception
if d.delivery_note:
submitted = frappe.db.sql("""select name from `tabDelivery Note`
where docstatus = 1 and name = %s""", d.delivery_note)
if not submitted:
msgprint("Delivery Note : "+ cstr(d.delivery_note) +" is not submitted")
raise Exception , "Validation Error."
msgprint(_("Delivery Note {0} is not submitted").format(d.delivery_note))
raise Exception
def update_stock_ledger(self):
sl_entries = []
@ -594,15 +589,12 @@ class SalesInvoice(SellingController):
self.validate_notification_email_id()
if not self.recurring_type:
msgprint(_("Please select: ") + self.meta.get_label("recurring_type"),
msgprint(_("Please select {0}").format(self.meta.get_label("recurring_type")),
raise_exception=1)
elif not (self.invoice_period_from_date and \
self.invoice_period_to_date):
msgprint(comma_and([self.meta.get_label("invoice_period_from_date"),
self.meta.get_label("invoice_period_to_date")])
+ _(": Mandatory for a Recurring Invoice."),
raise_exception=True)
throw(_("Invoice Period From and Invoice Period To dates mandatory for recurring invoice"))
def convert_to_recurring(self):
if self.convert_into_recurring_invoice:
@ -625,20 +617,15 @@ class SalesInvoice(SellingController):
from frappe.utils import validate_email_add
for email in email_list:
if not validate_email_add(email):
msgprint(self.meta.get_label("notification_email_address") \
+ " - " + _("Invalid Email Address") + ": \"%s\"" % email,
raise_exception=1)
throw(_("{0} is an invalid email address in 'Notification Email Address'").format(email))
else:
msgprint("Notification Email Addresses not specified for recurring invoice",
raise_exception=1)
throw(_("'Notification Email Addresses' not specified for recurring invoice"))
def set_next_date(self):
""" Set next date on which auto invoice will be created"""
if not self.repeat_on_day_of_month:
msgprint("""Please enter 'Repeat on Day of Month' field value.
The day of the month on which auto invoice
will be generated e.g. 05, 28 etc.""", raise_exception=1)
msgprint(_("Please enter 'Repeat on Day of Month' field value"), raise_exception=1)
next_date = get_next_date(self.posting_date,
month_map[self.recurring_type], cint(self.repeat_on_day_of_month))
@ -765,7 +752,7 @@ def assign_task_to_owner(inv, msg, users):
def get_bank_cash_account(mode_of_payment):
val = frappe.db.get_value("Mode of Payment", mode_of_payment, "default_account")
if not val:
frappe.msgprint("Default Bank / Cash Account not set in Mode of Payment: %s. Please add a Default Account in Mode of Payment master." % mode_of_payment)
frappe.msgprint(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment))
return {
"cash_bank_account": val
}

View File

@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe import _, msgprint, throw
from frappe.utils import flt, fmt_money
from frappe.model.controller import DocListController
from erpnext.setup.utils import get_company_currency
@ -15,36 +15,34 @@ class FromGreaterThanToError(frappe.ValidationError): pass
class ManyBlankToValuesError(frappe.ValidationError): pass
class ShippingRule(DocListController):
def validate(self):
self.validate_value("calculate_based_on", "in", ["Net Total", "Net Weight"])
self.shipping_rule_conditions = self.get("shipping_rule_conditions")
self.validate_from_to_values()
self.sort_shipping_rule_conditions()
self.validate_overlapping_shipping_rule_conditions()
def validate_from_to_values(self):
zero_to_values = []
for d in self.get("shipping_rule_conditions"):
self.round_floats_in(d)
# values cannot be negative
self.validate_value("from_value", ">=", 0.0, d)
self.validate_value("to_value", ">=", 0.0, d)
if not d.to_value:
zero_to_values.append(d)
elif d.from_value >= d.to_value:
msgprint(_("Error") + ": " + _("Row") + " # %d: " % d.idx +
_("From Value should be less than To Value"),
raise_exception=FromGreaterThanToError)
throw(_("From value must be less than to value in row {0}").format(d.idx), FromGreaterThanToError)
# check if more than two or more rows has To Value = 0
if len(zero_to_values) >= 2:
msgprint(_('''There can only be one Shipping Rule Condition with 0 or blank value for "To Value"'''),
raise_exception=ManyBlankToValuesError)
throw(_('There can only be one Shipping Rule Condition with 0 or blank value for "To Value"'),
ManyBlankToValuesError)
def sort_shipping_rule_conditions(self):
"""Sort Shipping Rule Conditions based on increasing From Value"""
self.shipping_rules_conditions = sorted(self.shipping_rule_conditions, key=lambda d: flt(d.from_value))
@ -61,7 +59,7 @@ class ShippingRule(DocListController):
"""
separate = (x1 <= x2 <= y1 <= y2) or (y1 <= y2 <= x1 <= x2)
return (not separate)
overlaps = []
for i in xrange(0, len(self.shipping_rule_conditions)):
for j in xrange(i+1, len(self.shipping_rule_conditions)):
@ -72,13 +70,13 @@ class ShippingRule(DocListController):
range_b = (d2.from_value, d2.to_value or d2.from_value)
if overlap_exists_between(range_a, range_b):
overlaps.append([d1, d2])
if overlaps:
company_currency = get_company_currency(self.company)
msgprint(_("Error") + ": " + _("Overlapping Conditions found between") + ":")
msgprint(_("Overlapping conditions found between:"))
messages = []
for d1, d2 in overlaps:
messages.append("%s-%s = %s " % (d1.from_value, d1.to_value, fmt_money(d1.shipping_amount, currency=company_currency)) +
messages.append("%s-%s = %s " % (d1.from_value, d1.to_value, fmt_money(d1.shipping_amount, currency=company_currency)) +
_("and") + " %s-%s = %s" % (d2.from_value, d2.to_value, fmt_money(d2.shipping_amount, currency=company_currency)))
msgprint("\n".join(messages), raise_exception=OverlappingConditionError)
msgprint("\n".join(messages), raise_exception=OverlappingConditionError)

View File

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

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import nowdate, cstr, flt, now, getdate, add_months
from frappe import msgprint, throw, _
from frappe import throw, _
from frappe.utils import formatdate
from erpnext.utilities import build_filter_conditions
@ -29,9 +29,7 @@ def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
from `tabFiscal Year` where %s order by year_start_date desc""" % cond)
if not fy:
error_msg = """%s %s not in any Fiscal Year""" % (label, formatdate(date))
error_msg = """{msg}: {date}""".format(msg=_("Fiscal Year does not exist for date"),
date=formatdate(date))
error_msg = _("""{0} {1} not in any Fiscal Year""").format(label, formatdate(date))
if verbose: frappe.msgprint(error_msg)
raise FiscalYearError, error_msg
@ -40,12 +38,7 @@ def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
def validate_fiscal_year(date, fiscal_year, label="Date"):
years = [f[0] for f in get_fiscal_years(date, label=label)]
if fiscal_year not in years:
throw(("%(label)s '%(posting_date)s': " + _("not within Fiscal Year") + \
": '%(fiscal_year)s'") % {
"label": label,
"posting_date": formatdate(date),
"fiscal_year": fiscal_year
})
throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
@frappe.whitelist()
def get_balance_on(account=None, date=None):
@ -62,7 +55,7 @@ def get_balance_on(account=None, date=None):
try:
year_start_date = get_fiscal_year(date, verbose=0)[1]
except FiscalYearError, e:
except FiscalYearError:
if getdate(date) > getdate(nowdate()):
# if fiscal year not found and the date is greater than today
# get fiscal year for today's date and its corresponding year start date
@ -232,9 +225,7 @@ def remove_against_link_from_jv(ref_type, ref_no, against_field):
and voucher_no != ifnull(against_voucher, '')""",
(now(), frappe.session.user, ref_type, ref_no))
frappe.msgprint("{msg} {linked_jv}".format(msg = _("""Following linked Journal Vouchers \
made against this transaction has been unlinked. You can link them again with other \
transactions via Payment Reconciliation Tool."""), linked_jv="\n".join(linked_jv)))
frappe.msgprint(_("Following Journal Vouchers Unlinked: {0}".format("\n".join(linked_jv))))
@frappe.whitelist()

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt
from frappe import msgprint
from frappe import msgprint, _
from erpnext.controllers.buying_controller import BuyingController
class PurchaseOrder(BuyingController):
@ -128,8 +128,8 @@ class PurchaseOrder(BuyingController):
date_diff = frappe.db.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.modified)))
if date_diff and date_diff[0][0]:
msgprint(cstr(self.doctype) +" => "+ cstr(self.name) +" has been modified. Please Refresh. ")
raise Exception
msgprint(_("{0} {1} has been modified. Please refresh").format(self.doctype, self.name),
raise_exception=True)
def update_status(self, status):
self.check_modified_date()
@ -140,7 +140,7 @@ class PurchaseOrder(BuyingController):
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
# step 3:=> Acknowledge user
msgprint(self.doctype + ": " + self.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
def on_submit(self):
purchase_controller = frappe.get_doc("Purchase Common")
@ -163,12 +163,12 @@ class PurchaseOrder(BuyingController):
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
submitted = frappe.db.sql("""select t1.name
submitted = frappe.db.sql_list("""select t1.name
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2
where t1.name = t2.parent and t2.purchase_order = %s and t1.docstatus = 1""",
self.name)
if submitted:
msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
msgprint(_("Purchase Invoice {0} is already submitted").format(", ".join(submitted)))
raise Exception
frappe.db.set(self,'status','Cancelled')

View File

@ -55,7 +55,7 @@ class Supplier(TransactionBase):
#validation for Naming Series mandatory field...
if frappe.defaults.get_global_default('supp_master_name') == '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):
if nm:
@ -106,7 +106,7 @@ class Supplier(TransactionBase):
@frappe.whitelist()
def get_dashboard_info(supplier):
if not frappe.has_permission("Supplier", "read", supplier):
frappe.msgprint("No Permission", raise_exception=True)
frappe.throw(_("No permission"))
out = {}
for doctype in ["Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"]:

View File

@ -417,8 +417,7 @@ class AccountsController(TransactionBase):
ref_amt = flt(frappe.db.get_value(ref_dt + " Item",
item.get(item_ref_dn), based_on), self.precision(based_on, item))
if not ref_amt:
frappe.msgprint(_("As amount for item") + ": " + item.item_code + _(" in ") +
ref_dt + _(" is zero, system will not check for over-billed"))
frappe.msgprint(_("Warning: System will not check overbilling since amount for Item {0} in {1} is zero").format(item.item_code, ref_dt))
else:
already_billed = frappe.db.sql("""select sum(%s) from `tab%s`
where %s=%s and docstatus=1 and parent != %s""" %

View File

@ -14,22 +14,22 @@ class BuyingController(StockController):
def onload_post_render(self):
# contact, address, item details
self.set_missing_values()
def validate(self):
super(BuyingController, self).validate()
if getattr(self, "supplier", None) and not self.supplier_name:
self.supplier_name = frappe.db.get_value("Supplier",
self.supplier_name = frappe.db.get_value("Supplier",
self.supplier, "supplier_name")
self.is_item_table_empty()
self.validate_stock_or_nonstock_items()
self.validate_warehouse()
def set_missing_values(self, for_validate=False):
super(BuyingController, self).set_missing_values(for_validate)
self.set_supplier_from_item_default()
self.set_price_list_currency("Buying")
# set contact and address details for supplier, if they are not mentioned
if getattr(self, "supplier", None):
self.update_if_missing(get_party_details(self.supplier, party_type="Supplier"))
@ -45,24 +45,24 @@ class BuyingController(StockController):
if supplier:
self.supplier = supplier
break
def validate_warehouse(self):
from erpnext.stock.utils import validate_warehouse_company
warehouses = list(set([d.warehouse for d in
warehouses = list(set([d.warehouse for d in
self.get(self.fname) if getattr(d, "warehouse", None)]))
for w in warehouses:
validate_warehouse_company(w, self.company)
def validate_stock_or_nonstock_items(self):
if not self.get_stock_items():
tax_for_valuation = [d.account_head for d in
self.get("other_charges")
tax_for_valuation = [d.account_head for d in
self.get("other_charges")
if d.category in ["Valuation", "Valuation and Total"]]
if tax_for_valuation:
frappe.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total' as all items are non-stock items"""), raise_exception=1)
frappe.throw(_("Tax Category can not be 'Valuation' or 'Valuation and Total' as all items are non-stock items"))
def set_total_in_words(self):
from frappe.utils import money_in_words
company_currency = get_company_currency(self.company)
@ -71,12 +71,12 @@ class BuyingController(StockController):
if self.meta.get_field("in_words_import"):
self.in_words_import = money_in_words(self.grand_total_import,
self.currency)
def calculate_taxes_and_totals(self):
self.other_fname = "other_charges"
super(BuyingController, self).calculate_taxes_and_totals()
self.calculate_total_advance("Purchase Invoice", "advance_allocation_details")
def calculate_item_values(self):
for item in self.item_doclist:
self.round_floats_in(item)
@ -86,7 +86,7 @@ class BuyingController(StockController):
elif not item.rate:
item.rate = flt(item.price_list_rate * (1.0 - (item.discount_percentage / 100.0)),
self.precision("rate", item))
item.amount = flt(item.rate * item.qty,
self.precision("amount", item))
item.item_tax_amount = 0.0;
@ -94,19 +94,19 @@ class BuyingController(StockController):
self._set_in_company_currency(item, "amount", "base_amount")
self._set_in_company_currency(item, "price_list_rate", "base_price_list_rate")
self._set_in_company_currency(item, "rate", "base_rate")
def calculate_net_total(self):
self.net_total = self.net_total_import = 0.0
for item in self.item_doclist:
self.net_total += item.base_amount
self.net_total_import += item.amount
self.round_floats_in(self, ["net_total", "net_total_import"])
def calculate_totals(self):
self.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.net_total, self.precision("grand_total"))
self.grand_total_import = flt(self.grand_total / self.conversion_rate,
self.precision("grand_total_import"))
@ -116,28 +116,28 @@ class BuyingController(StockController):
if self.meta.get_field("rounded_total"):
self.rounded_total = _round(self.grand_total)
if self.meta.get_field("rounded_total_import"):
self.rounded_total_import = _round(self.grand_total_import)
if self.meta.get_field("other_charges_added"):
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"]]),
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"]]),
self.precision("other_charges_added"))
if self.meta.get_field("other_charges_deducted"):
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"]]),
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"]]),
self.precision("other_charges_deducted"))
if self.meta.get_field("other_charges_added_import"):
self.other_charges_added_import = flt(self.other_charges_added /
self.other_charges_added_import = flt(self.other_charges_added /
self.conversion_rate, self.precision("other_charges_added_import"))
if self.meta.get_field("other_charges_deducted_import"):
self.other_charges_deducted_import = flt(self.other_charges_deducted /
self.other_charges_deducted_import = flt(self.other_charges_deducted /
self.conversion_rate, self.precision("other_charges_deducted_import"))
def calculate_outstanding_amount(self):
if self.doctype == "Purchase Invoice" and self.docstatus == 0:
self.total_advance = flt(self.total_advance,
@ -146,17 +146,17 @@ class BuyingController(StockController):
self.precision("write_off_amount")), self.precision("total_amount_to_pay"))
self.outstanding_amount = flt(self.total_amount_to_pay - self.total_advance,
self.precision("outstanding_amount"))
# update valuation rate
def update_valuation_rate(self, parentfield):
"""
item_tax_amount is the total tax amount applied on that item
stored for valuation
stored for valuation
TODO: rename item_tax_amount to valuation_tax_amount
"""
stock_items = self.get_stock_items()
stock_items_qty, stock_items_amount = 0, 0
last_stock_item_idx = 1
for d in self.get(parentfield):
@ -164,47 +164,45 @@ class BuyingController(StockController):
stock_items_qty += flt(d.qty)
stock_items_amount += flt(d.base_amount)
last_stock_item_idx = d.idx
total_valuation_amount = sum([flt(d.tax_amount) for d in
self.get("other_charges")
total_valuation_amount = sum([flt(d.tax_amount) for d in
self.get("other_charges")
if d.category in ["Valuation", "Valuation and Total"]])
valuation_amount_adjustment = total_valuation_amount
for i, item in enumerate(self.get(parentfield)):
if item.item_code and item.qty and item.item_code in stock_items:
item_proportion = flt(item.base_amount) / stock_items_amount if stock_items_amount \
else flt(item.qty) / stock_items_qty
if i == (last_stock_item_idx - 1):
item.item_tax_amount = flt(valuation_amount_adjustment,
item.item_tax_amount = flt(valuation_amount_adjustment,
self.precision("item_tax_amount", item))
else:
item.item_tax_amount = flt(item_proportion * total_valuation_amount,
item.item_tax_amount = flt(item_proportion * total_valuation_amount,
self.precision("item_tax_amount", item))
valuation_amount_adjustment -= item.item_tax_amount
self.round_floats_in(item)
item.conversion_factor = item.conversion_factor or flt(frappe.db.get_value(
"UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom},
"UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom},
"conversion_factor")) or 1
qty_in_stock_uom = flt(item.qty * item.conversion_factor)
item.valuation_rate = ((item.base_amount + item.item_tax_amount + item.rm_supp_cost)
/ qty_in_stock_uom)
else:
item.valuation_rate = 0.0
def validate_for_subcontracting(self):
if not self.is_subcontracted and self.sub_contracted_items:
frappe.msgprint(_("""Please enter whether %s is made for subcontracting or purchasing,
in 'Is Subcontracted' field""" % self.doctype), raise_exception=1)
frappe.throw(_("Please enter 'Is Subcontracted' as Yes or No"))
if self.doctype == "Purchase Receipt" and self.is_subcontracted=="Yes" \
and not self.supplier_warehouse:
frappe.msgprint(_("Supplier Warehouse mandatory subcontracted purchase receipt"),
raise_exception=1)
frappe.throw(_("Supplier Warehouse mandatory for sub-contracted Purchase Receipt"))
def update_raw_materials_supplied(self, raw_material_table):
self.set(raw_material_table, [])
if self.is_subcontracted=="Yes":
@ -234,30 +232,30 @@ class BuyingController(StockController):
"consumed_qty": required_qty,
"description": item.description,
})
self.append(raw_material_table, rm_doclist)
raw_materials_cost += required_qty * flt(item.rate)
if self.doctype == "Purchase Receipt":
d.rm_supp_cost = raw_materials_cost
def get_items_from_default_bom(self, item_code):
bom_items = frappe.db.sql("""select t2.item_code, t2.qty_consumed_per_unit,
t2.rate, t2.stock_uom, t2.name, t2.description
from `tabBOM` t1, `tabBOM Item` t2
where t2.parent = t1.name and t1.item = %s and t1.is_default = 1
bom_items = frappe.db.sql("""select t2.item_code, t2.qty_consumed_per_unit,
t2.rate, t2.stock_uom, t2.name, t2.description
from `tabBOM` t1, `tabBOM Item` t2
where t2.parent = t1.name and t1.item = %s and t1.is_default = 1
and t1.docstatus = 1 and t1.is_active = 1""", item_code, as_dict=1)
if not bom_items:
msgprint(_("No default BOM exists for item: ") + item_code, raise_exception=1)
msgprint(_("No default BOM exists for Item {0}").format(item_code), raise_exception=1)
return bom_items
@property
def sub_contracted_items(self):
if not hasattr(self, "_sub_contracted_items"):
self._sub_contracted_items = []
item_codes = list(set(item.item_code for item in
item_codes = list(set(item.item_code for item in
self.get(self.fname)))
if item_codes:
self._sub_contracted_items = [r[0] for r in frappe.db.sql("""select name
@ -265,12 +263,12 @@ class BuyingController(StockController):
(", ".join((["%s"]*len(item_codes))),), item_codes)]
return self._sub_contracted_items
@property
def purchase_items(self):
if not hasattr(self, "_purchase_items"):
self._purchase_items = []
item_codes = list(set(item.item_code for item in
item_codes = list(set(item.item_code for item in
self.get(self.fname)))
if item_codes:
self._purchase_items = [r[0] for r in frappe.db.sql("""select name
@ -282,4 +280,4 @@ class BuyingController(StockController):
def is_item_table_empty(self):
if not len(self.get(self.fname)):
frappe.throw(_("Item table can not be blank"))
frappe.throw(_("Item table can not be blank"))

View File

@ -3,9 +3,9 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, flt, comma_or, _round, cstr
from frappe.utils import cint, flt, _round, cstr
from erpnext.setup.utils import get_company_currency
from frappe import msgprint, _
from frappe import _, throw
from erpnext.controllers.stock_controller import StockController
@ -233,8 +233,7 @@ class SellingController(StockController):
if self.meta.get_field("commission_rate"):
self.round_floats_in(self, ["net_total", "commission_rate"])
if self.commission_rate > 100.0:
msgprint(_(self.meta.get_label("commission_rate")) + " " +
_("cannot be greater than 100"), raise_exception=True)
throw(_("Commission rate cannot be greater than 100"))
self.total_commission = flt(self.net_total * self.commission_rate / 100.0,
self.precision("total_commission"))
@ -252,17 +251,14 @@ class SellingController(StockController):
total += sales_person.allocated_percentage
if sales_team and total != 100.0:
msgprint(_("Total") + " " +
_(self.meta.get_label("allocated_percentage", parentfield="sales_team")) +
" " + _("should be 100%"), raise_exception=True)
throw(_("Total allocated percentage for sales team should be 100"))
def validate_order_type(self):
valid_types = ["Sales", "Maintenance", "Shopping Cart"]
if not self.order_type:
self.order_type = "Sales"
elif self.order_type not in valid_types:
msgprint(_(self.meta.get_label("order_type")) + " " +
_("must be one of") + ": " + comma_or(valid_types), raise_exception=True)
throw(_("Order Type must be one of {1}").comma_or(valid_types))
def check_credit(self, grand_total):
customer_account = frappe.db.get_value("Account", {"company": self.company,

View File

@ -3,8 +3,8 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cstr
from frappe import msgprint
from frappe.utils import flt
from frappe import msgprint, _, throw
from frappe.model.controller import DocListController
@ -129,19 +129,13 @@ class StatusUpdater(DocListController):
item['target_ref_field'] = args['target_ref_field'].replace('_', ' ')
if not item[args['target_ref_field']]:
msgprint("""As %(target_ref_field)s for item: %(item_code)s in \
%(parenttype)s: %(parent)s is zero, system will not check \
over-delivery or over-billed""" % item)
msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code))
elif args.get('no_tolerance'):
item['reduce_by'] = item[args['target_field']] - \
item[args['target_ref_field']]
if item['reduce_by'] > .01:
msgprint("""
Row #%(idx)s: Max %(target_ref_field)s allowed for <b>Item \
%(item_code)s</b> against <b>%(parenttype)s %(parent)s</b> \
is <b>""" % item + cstr(item[args['target_ref_field']]) +
"""</b>.<br>You must reduce the %(target_ref_field)s by \
%(reduce_by)s""" % item, raise_exception=1)
msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}").format(item.item_code))
throw(_("{0} must be less than or equal to {1}").format(_(item.target_ref_field), item[args["target_ref_field"]]))
else:
self.check_overflow_with_tolerance(item, args)
@ -161,18 +155,8 @@ class StatusUpdater(DocListController):
item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100)
item['reduce_by'] = item[args['target_field']] - item['max_allowed']
msgprint("""
Row #%(idx)s: Max %(target_ref_field)s allowed for <b>Item %(item_code)s</b> \
against <b>%(parenttype)s %(parent)s</b> is <b>%(max_allowed)s</b>.
If you want to increase your overflow tolerance, please increase tolerance %% in \
Global Defaults or Item master.
Or, you must reduce the %(target_ref_field)s by %(reduce_by)s
Also, please check if the order item has already been billed in the Sales Order""" %
item, raise_exception=1)
msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}").format(item["item_code"]))
throw(_("{0} must be less than or equal to {1}").format(_(item["target_ref_field"]), item[args["max_allowed"]]))
def update_qty(self, change_modified=True):
"""

View File

@ -65,7 +65,7 @@ class StockController(AccountsController):
warehouse_with_no_account.append(sle.warehouse)
if warehouse_with_no_account:
msgprint(_("No accounting entries for following warehouses") + ": \n" +
msgprint(_("No accounting entries for the following warehouses") + ": \n" +
"\n".join(warehouse_with_no_account))
return process_gl_map(gl_list)
@ -231,12 +231,10 @@ class StockController(AccountsController):
def check_expense_account(self, item):
if item.meta.get_field("expense_account") and not item.expense_account:
msgprint(_("""Expense/Difference account is mandatory for item: """) + item.item_code,
raise_exception=1)
frappe.throw(_("Expense or Difference account is mandatory for Item {0}").format(item.item_code))
if item.meta.get_field("expense_account") and not item.cost_center:
msgprint(_("""Cost Center is mandatory for item: """) + item.item_code,
raise_exception=1)
frappe.throw(_("""Cost Center is mandatory for item {0}""").format(item.item_code))
def get_sl_entries(self, d, args):
sl_dict = {

View File

@ -3,12 +3,12 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import add_days, add_months, cstr, getdate
from frappe.utils import getdate
from frappe import _
def get_columns(filters, trans):
validate_filters(filters)
# get conditions for based_on filter cond
based_on_details = based_wise_colums_query(filters.get("based_on"), trans)
# get conditions for periodic filter cond
@ -17,11 +17,11 @@ def get_columns(filters, trans):
group_by_cols = group_wise_column(filters.get("group_by"))
columns = based_on_details["based_on_cols"] + period_cols + ["Total(Qty):Float:120", "Total(Amt):Currency:120"]
if group_by_cols:
if group_by_cols:
columns = based_on_details["based_on_cols"] + group_by_cols + period_cols + \
["Total(Qty):Float:120", "Total(Amt):Currency:120"]
["Total(Qty):Float:120", "Total(Amt):Currency:120"]
conditions = {"based_on_select": based_on_details["based_on_select"], "period_wise_select": period_select,
conditions = {"based_on_select": based_on_details["based_on_select"], "period_wise_select": period_select,
"columns": columns, "group_by": based_on_details["based_on_group_by"], "grbc": group_by_cols, "trans": trans,
"addl_tables": based_on_details["addl_tables"]}
@ -30,16 +30,16 @@ def get_columns(filters, trans):
def validate_filters(filters):
for f in ["Fiscal Year", "Based On", "Period", "Company"]:
if not filters.get(f.lower().replace(" ", "_")):
frappe.msgprint(f + _(" is mandatory"), raise_exception=1)
frappe.throw(_("{0} is mandatory").format(f))
if filters.get("based_on") == filters.get("group_by"):
frappe.msgprint("'Based On' and 'Group By' can not be same", raise_exception=1)
frappe.throw(_("'Based On' and 'Group By' can not be same"))
def get_data(filters, conditions):
data = []
inc, cond= '',''
query_details = conditions["based_on_select"] + conditions["period_wise_select"]
if conditions["based_on_select"] in ["t1.project_name,", "t2.project_name,"]:
cond = 'and '+ conditions["based_on_select"][:-1] +' IS Not NULL'
@ -59,55 +59,55 @@ def get_data(filters, conditions):
else :
inc = 1
data1 = frappe.db.sql(""" select %s from `tab%s` t1, `tab%s Item` t2 %s
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s and
t1.docstatus = 1 %s
group by %s
""" % (query_details, conditions["trans"], conditions["trans"], conditions["addl_tables"], "%s",
"%s", cond, conditions["group_by"]), (filters.get("company"),
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s and
t1.docstatus = 1 %s
group by %s
""" % (query_details, conditions["trans"], conditions["trans"], conditions["addl_tables"], "%s",
"%s", cond, conditions["group_by"]), (filters.get("company"),
filters["fiscal_year"]),as_list=1)
for d in range(len(data1)):
#to add blanck column
dt = data1[d]
dt.insert(ind,'')
dt.insert(ind,'')
data.append(dt)
#to get distinct value of col specified by group_by in filter
row = frappe.db.sql("""select DISTINCT(%s) from `tab%s` t1, `tab%s Item` t2 %s
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s
and t1.docstatus = 1 and %s = %s
""" %
(sel_col, conditions["trans"], conditions["trans"], conditions["addl_tables"],
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s
and t1.docstatus = 1 and %s = %s
""" %
(sel_col, conditions["trans"], conditions["trans"], conditions["addl_tables"],
"%s", "%s", conditions["group_by"], "%s"),
(filters.get("company"), filters.get("fiscal_year"), data1[d][0]), as_list=1)
for i in range(len(row)):
des = ['' for q in range(len(conditions["columns"]))]
#get data for group_by filter
#get data for group_by filter
row1 = frappe.db.sql(""" select %s , %s from `tab%s` t1, `tab%s Item` t2 %s
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s
and t1.docstatus = 1 and %s = %s and %s = %s
""" %
(sel_col, conditions["period_wise_select"], conditions["trans"],
conditions["trans"], conditions["addl_tables"], "%s", "%s", sel_col,
"%s", conditions["group_by"], "%s"),
(filters.get("company"), filters.get("fiscal_year"), row[i][0],
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s
and t1.docstatus = 1 and %s = %s and %s = %s
""" %
(sel_col, conditions["period_wise_select"], conditions["trans"],
conditions["trans"], conditions["addl_tables"], "%s", "%s", sel_col,
"%s", conditions["group_by"], "%s"),
(filters.get("company"), filters.get("fiscal_year"), row[i][0],
data1[d][0]), as_list=1)
des[ind] = row[i]
for j in range(1,len(conditions["columns"])-inc):
for j in range(1,len(conditions["columns"])-inc):
des[j+inc] = row1[0][j]
data.append(des)
else:
data = frappe.db.sql(""" select %s from `tab%s` t1, `tab%s Item` t2 %s
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s and
t1.docstatus = 1 %s
group by %s
""" %
(query_details, conditions["trans"], conditions["trans"], conditions["addl_tables"],
"%s", "%s", cond,conditions["group_by"]),
where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s and
t1.docstatus = 1 %s
group by %s
""" %
(query_details, conditions["trans"], conditions["trans"], conditions["addl_tables"],
"%s", "%s", cond,conditions["group_by"]),
(filters.get("company"), filters.get("fiscal_year")), as_list=1)
return data
@ -124,13 +124,13 @@ def period_wise_colums_query(filters, trans):
trans_date = 'posting_date'
else:
trans_date = 'transaction_date'
if filters.get("period") != 'Yearly':
for dt in bet_dates:
get_period_wise_columns(dt, filters.get("period"), pwc)
query_details = get_period_wise_query(dt, trans_date, query_details)
else:
pwc = [filters.get("fiscal_year") + " (Qty):Float:120",
pwc = [filters.get("fiscal_year") + " (Qty):Float:120",
filters.get("fiscal_year") + " (Amt):Currency:120"]
query_details = " SUM(t2.qty), SUM(t1.grand_total),"
@ -139,14 +139,14 @@ def period_wise_colums_query(filters, trans):
def get_period_wise_columns(bet_dates, period, pwc):
if period == 'Monthly':
pwc += [get_mon(bet_dates[0]) + " (Qty):Float:120",
pwc += [get_mon(bet_dates[0]) + " (Qty):Float:120",
get_mon(bet_dates[0]) + " (Amt):Currency:120"]
else:
pwc += [get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Qty):Float:120",
pwc += [get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Qty):Float:120",
get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Amt):Currency:120"]
def get_period_wise_query(bet_dates, trans_date, query_details):
query_details += """SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t2.qty, NULL)),
query_details += """SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t2.qty, NULL)),
SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t1.grand_total, NULL)),
""" % {"trans_date": trans_date, "sd": bet_dates[0],"ed": bet_dates[1]}
return query_details
@ -156,7 +156,7 @@ def get_period_date_ranges(period, fiscal_year=None, year_start_date=None):
from dateutil.relativedelta import relativedelta
if not year_start_date:
year_start_date, year_end_date = frappe.db.get_value("Fiscal Year",
year_start_date, year_end_date = frappe.db.get_value("Fiscal Year",
fiscal_year, ["year_start_date", "year_end_date"])
increment = {
@ -197,13 +197,13 @@ def based_wise_colums_query(based_on, trans):
# based_on_cols, based_on_select, based_on_group_by, addl_tables
if based_on == "Item":
based_on_details["based_on_cols"] = ["Item:Link/Item:120", "Item Name:Data:120"]
based_on_details["based_on_select"] = "t2.item_code, t2.item_name,"
based_on_details["based_on_select"] = "t2.item_code, t2.item_name,"
based_on_details["based_on_group_by"] = 't2.item_code'
based_on_details["addl_tables"] = ''
elif based_on == "Item Group":
based_on_details["based_on_cols"] = ["Item Group:Link/Item Group:120"]
based_on_details["based_on_select"] = "t2.item_group,"
based_on_details["based_on_select"] = "t2.item_group,"
based_on_details["based_on_group_by"] = 't2.item_group'
based_on_details["addl_tables"] = ''
@ -224,7 +224,7 @@ def based_wise_colums_query(based_on, trans):
based_on_details["based_on_select"] = "t1.supplier, t3.supplier_type,"
based_on_details["based_on_group_by"] = 't1.supplier'
based_on_details["addl_tables"] = ',`tabSupplier` t3'
elif based_on == 'Supplier Type':
based_on_details["based_on_cols"] = ["Supplier Type:Link/Supplier Type:140"]
based_on_details["based_on_select"] = "t3.supplier_type,"
@ -249,7 +249,7 @@ def based_wise_colums_query(based_on, trans):
based_on_details["based_on_group_by"] = 't2.project_name'
based_on_details["addl_tables"] = ''
else:
frappe.msgprint("Project-wise data is not available for Quotation", raise_exception=1)
frappe.throw(_("Project-wise data is not available for Quotation"))
return based_on_details
@ -257,4 +257,4 @@ def group_wise_column(group_by):
if group_by:
return [group_by+":Link/"+group_by+":120"]
else:
return []
return []

View File

@ -22,22 +22,22 @@ class Appraisal(Document):
def get_employee_name(self):
self.employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
return self.employee_name
def validate_dates(self):
if getdate(self.start_date) > getdate(self.end_date):
frappe.throw(_("End Date can not be less than Start Date"))
def validate_existing_appraisal(self):
chk = frappe.db.sql("""select name from `tabAppraisal` where employee=%s
and (status='Submitted' or status='Completed')
and ((start_date>=%s and start_date<=%s)
chk = frappe.db.sql("""select name from `tabAppraisal` where employee=%s
and (status='Submitted' or status='Completed')
and ((start_date>=%s and start_date<=%s)
or (end_date>=%s and end_date<=%s))""",
(self.employee,self.start_date,self.end_date,self.start_date,self.end_date))
if chk:
frappe.throw("You have already created Appraisal "\
+cstr(chk[0][0])+" in the current date range for employee "\
+cstr(self.employee_name))
def calculate_total(self):
total, total_w = 0, 0
for d in self.get('appraisal_details'):
@ -47,30 +47,29 @@ class Appraisal(Document):
total_w += flt(d.per_weightage)
if int(total_w) != 100:
msgprint("Total weightage assigned should be 100%. It is :" + str(total_w) + "%",
raise_exception=1)
frappe.throw(_("Total weightage assigned should be 100%. It is {0}").format(str(total_w) + "%"))
if frappe.db.get_value("Employee", self.employee, "user_id") != \
frappe.session.user and total == 0:
msgprint("Total can't be zero. You must atleast give some points!", raise_exception=1)
frappe.throw(_("Total cannot be zero"))
self.total_score = total
def on_submit(self):
frappe.db.set(self, 'status', 'Submitted')
def on_cancel(self):
def on_cancel(self):
frappe.db.set(self, 'status', 'Cancelled')
@frappe.whitelist()
def fetch_appraisal_template(source_name, target_doc=None):
target_doc = get_mapped_doc("Appraisal Template", source_name, {
"Appraisal Template": {
"doctype": "Appraisal",
},
"doctype": "Appraisal",
},
"Appraisal Template Goal": {
"doctype": "Appraisal Goal",
"doctype": "Appraisal Goal",
}
}, target_doc)
return target_doc
return target_doc

View File

@ -12,8 +12,6 @@ class AppraisalTemplate(Document):
self.total_points = 0
for d in self.get("kra_sheet"):
self.total_points += int(d.per_weightage or 0)
if int(self.total_points) != 100:
frappe.msgprint(_("Total (sum of) points distribution for all goals should be 100.") \
+ " " + _("Not") + " " + str(self.total_points),
raise_exception=True)
frappe.throw(_("Total points for all goals should be 100. It is {0}").format(self.total_points))

View File

@ -5,44 +5,41 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, nowdate
from frappe import msgprint, _
from frappe import _
from frappe.model.document import Document
class Attendance(Document):
def validate_duplicate_record(self):
res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and att_date = %s
and name != %s and docstatus = 1""",
def validate_duplicate_record(self):
res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and att_date = %s
and name != %s and docstatus = 1""",
(self.employee, self.att_date, self.name))
if res:
msgprint(_("Attendance for the employee: ") + self.employee +
_(" already marked"), raise_exception=1)
frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee))
def check_leave_record(self):
if self.status == 'Present':
leave = frappe.db.sql("""select name from `tabLeave Application`
where employee = %s and %s between from_date and to_date and status = 'Approved'
leave = frappe.db.sql("""select name from `tabLeave Application`
where employee = %s and %s between from_date and to_date and status = 'Approved'
and docstatus = 1""", (self.employee, self.att_date))
if leave:
frappe.msgprint(_("Employee: ") + self.employee + _(" was on leave on ")
+ self.att_date + _(". You can not mark his attendance as 'Present'"),
raise_exception=1)
frappe.throw(_("Employee {0} was on leave on {1}. Cannot mark attendance.").format(self.employee,
self.att_date))
def validate_fiscal_year(self):
from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.att_date, self.fiscal_year)
def validate_att_date(self):
if getdate(self.att_date) > getdate(nowdate()):
msgprint(_("Attendance can not be marked for future dates"), raise_exception=1)
frappe.throw(_("Attendance can not be marked for future dates"))
def validate_employee(self):
emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
self.employee)
if not emp:
msgprint(_("Employee: ") + self.employee +
_(" not active or does not exists in the system"), raise_exception=1)
frappe.throw(_("Employee {0} is not active or does not exist").format(self.employee))
def validate(self):
from erpnext.utilities import validate_status
validate_status(self.status, ["Present", "Absent", "Half Day"])
@ -50,9 +47,9 @@ class Attendance(Document):
self.validate_att_date()
self.validate_duplicate_record()
self.check_leave_record()
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
employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
frappe.db.set(self, 'employee_name', employee_name)
frappe.db.set(self, 'employee_name', employee_name)

View File

@ -3,25 +3,22 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint
from frappe import _
from frappe.model.document import Document
class ExpenseClaim(Document):
def validate(self):
self.validate_fiscal_year()
self.validate_exp_details()
def on_submit(self):
if self.approval_status=="Draft":
frappe.msgprint("""Please set Approval Status to 'Approved' or \
'Rejected' before submitting""", raise_exception=1)
frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'"""))
def validate_fiscal_year(self):
from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.posting_date, self.fiscal_year, "Posting Date")
def validate_exp_details(self):
if not self.get('expense_voucher_details'):
msgprint("Please add expense voucher details")
raise Exception
frappe.throw(_("Please add expense voucher details"))

View File

@ -4,20 +4,19 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import add_days, add_years, cint, getdate
from frappe.utils import cint
from frappe.model.naming import make_autoname
from frappe import msgprint, throw, _
import datetime
from frappe import throw, _
from frappe.model.document import Document
class HolidayList(Document):
def autoname(self):
self.name = make_autoname(self.fiscal_year + "/" + self.holiday_list_name + "/.###")
def validate(self):
self.update_default_holiday_list()
def get_weekly_off_dates(self):
self.validate_values()
yr_start_date, yr_end_date = self.get_fy_start_end_dates()
@ -42,24 +41,24 @@ class HolidayList(Document):
def get_weekly_off_date_list(self, year_start_date, year_end_date):
from frappe.utils import getdate
year_start_date, year_end_date = getdate(year_start_date), getdate(year_end_date)
from dateutil import relativedelta
from datetime import timedelta
import calendar
date_list = []
weekday = getattr(calendar, (self.weekly_off).upper())
reference_date = year_start_date + relativedelta.relativedelta(weekday=weekday)
while reference_date <= year_end_date:
date_list.append(reference_date)
reference_date += timedelta(days=7)
return date_list
def clear_table(self):
self.set('holiday_list_details', [])
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.fiscal_year,))

View File

@ -4,67 +4,46 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, flt
from frappe import msgprint
from frappe import _
from frappe.model.document import Document
class LeaveAllocation(Document):
def validate(self):
self.validate_new_leaves_allocated_value()
self.check_existing_leave_allocation()
self.validate_new_leaves_allocated()
def on_update_after_submit(self):
self.validate_new_leaves_allocated_value()
self.validate_new_leaves_allocated()
def on_update(self):
self.get_total_allocated_leaves()
def on_cancel(self):
self.check_for_leave_application()
def validate_new_leaves_allocated_value(self):
"""validate that leave allocation is in multiples of 0.5"""
if flt(self.new_leaves_allocated) % 0.5:
guess = round(flt(self.new_leaves_allocated) * 2.0) / 2.0
msgprint("""New Leaves Allocated should be a multiple of 0.5.
Perhaps you should enter %s or %s""" % (guess, guess + 0.5),
raise_exception=1)
frappe.throw(_("Leaves must be allocated in multiples of 0.5"))
def check_existing_leave_allocation(self):
"""check whether leave for same type is already allocated or not"""
leave_allocation = frappe.db.sql("""select name from `tabLeave Allocation`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.employee, self.leave_type, self.fiscal_year))
if leave_allocation:
msgprint("""%s is already allocated to Employee: %s for Fiscal Year: %s.
Please refere Leave Allocation: \
<a href="#Form/Leave Allocation/%s">%s</a>""" % \
(self.leave_type, self.employee, self.fiscal_year,
leave_allocation[0][0], leave_allocation[0][0]), raise_exception=1)
def validate_new_leaves_allocated(self):
"""check if Total Leaves Allocated >= Leave Applications"""
self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + \
flt(self.new_leaves_allocated)
leaves_applied = self.get_leaves_applied(self.fiscal_year)
if leaves_applied > self.total_leaves_allocated:
expected_new_leaves = flt(self.new_leaves_allocated) + \
(leaves_applied - self.total_leaves_allocated)
msgprint("""Employee: %s has already applied for %s leaves.
Hence, New Leaves Allocated should be atleast %s""" % \
(self.employee, leaves_applied, expected_new_leaves),
raise_exception=1)
frappe.msgprint(_("Leaves for type {0} already allocated for Employee {1} for Fiscal Year {0}").format(self.leave_type,
self.employee, self.fiscal_year))
frappe.throw('<a href="#Form/Leave Allocation/{0}">{0}</a>'.format(leave_allocation[0][0]))
def get_leave_bal(self, prev_fyear):
return self.get_leaves_allocated(prev_fyear) - self.get_leaves_applied(prev_fyear)
def get_leaves_applied(self, fiscal_year):
leaves_applied = frappe.db.sql("""select SUM(ifnull(total_leave_days, 0))
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.employee, self.leave_type, fiscal_year))
return leaves_applied and flt(leaves_applied[0][0]) or 0
@ -74,7 +53,7 @@ class LeaveAllocation(Document):
and fiscal_year=%s and docstatus=1 and name!=%s""",
(self.employee, self.leave_type, fiscal_year, self.name))
return leaves_allocated and flt(leaves_allocated[0][0]) or 0
def allow_carry_forward(self):
"""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""",
@ -82,15 +61,14 @@ class LeaveAllocation(Document):
cf = cf and cint(cf[0][0]) or 0
if not cf:
frappe.db.set(self,'carry_forward',0)
msgprint("Sorry! You cannot carry forward %s" % (self.leave_type),
raise_exception=1)
frappe.throw("Cannot carry forward {0}".format(self.leave_type))
def get_carry_forwarded_leaves(self):
if self.carry_forward:
self.allow_carry_forward()
prev_fiscal_year = frappe.db.sql("""select name from `tabFiscal Year`
where year_start_date = (select date_add(year_start_date, interval -1 year)
from `tabFiscal Year` where name=%s)
prev_fiscal_year = frappe.db.sql("""select name from `tabFiscal Year`
where year_start_date = (select date_add(year_start_date, interval -1 year)
from `tabFiscal Year` where name=%s)
order by name desc limit 1""", self.fiscal_year)
prev_fiscal_year = prev_fiscal_year and prev_fiscal_year[0][0] or ''
prev_bal = 0
@ -112,10 +90,7 @@ class LeaveAllocation(Document):
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.employee, self.leave_type, self.fiscal_year))
if exists:
msgprint("""Cannot cancel this Leave Allocation as \
Employee : %s has already applied for %s.
Please check Leave Application: \
<a href="#Form/Leave Application/%s">%s</a>""" % \
(self.employee, self.leave_type, exists[0][0], exists[0][0]))
raise Exception
frappe.msgprint(_("Cannot cancel because Employee {0} is already approved for {1}").format(self.employee,
self.leave_type))
frappe.throw('<a href="#Form/Leave Application/{0}">{0}</a>'.format(exists[0][0]))

View File

@ -13,7 +13,7 @@ class LeaveDayBlockedError(frappe.ValidationError): pass
class OverlapError(frappe.ValidationError): pass
class InvalidLeaveApproverError(frappe.ValidationError): pass
class LeaveApproverIdentityError(frappe.ValidationError): pass
from frappe.model.controller import DocListController
class LeaveApplication(DocListController):
def setup(self):
@ -21,7 +21,7 @@ class LeaveApplication(DocListController):
self.previous_doc = frappe.db.get_value(self.doctype, self.name, "*", as_dict=True)
else:
self.previous_doc = None
def validate(self):
self.validate_to_date()
self.validate_balance_leaves()
@ -30,7 +30,7 @@ class LeaveApplication(DocListController):
self.show_block_day_warning()
self.validate_block_days()
self.validate_leave_approver()
def on_update(self):
if (not self.previous_doc and self.leave_approver) or (self.previous_doc and \
self.status == "Open" and self.previous_doc.leave_approver != self.leave_approver):
@ -40,25 +40,24 @@ class LeaveApplication(DocListController):
self.previous_doc.status == "Open" and self.status == "Rejected":
# notify employee about rejection
self.notify_employee(self.status)
def on_submit(self):
if self.status != "Approved":
frappe.msgprint("""Only Leave Applications with status 'Approved' can be Submitted.""",
raise_exception=True)
frappe.throw(_("Only Leave Applications with status 'Approved' can be submitted"))
# notify leave applier about approval
self.notify_employee(self.status)
def on_cancel(self):
# notify leave applier about cancellation
self.notify_employee("cancelled")
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.from_date, self.to_date,
block_dates = get_applicable_block_dates(self.from_date, self.to_date,
self.employee, self.company, all_lists=True)
if block_dates:
frappe.msgprint(_("Warning: Leave application contains following block dates") + ":")
for d in block_dates:
@ -67,20 +66,20 @@ class LeaveApplication(DocListController):
def validate_block_days(self):
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
block_dates = get_applicable_block_dates(self.from_date, self.to_date,
block_dates = get_applicable_block_dates(self.from_date, self.to_date,
self.employee, self.company)
if block_dates:
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
def get_holidays(self):
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
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
and h1.holiday_date between %s and %s""", (self.employee, self.from_date, self.to_date))
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
and ifnull(h2.is_default,0) = 1 and h2.fiscal_year = %s""",
(self.from_date, self.to_date, self.fiscal_year))
@ -100,17 +99,15 @@ class LeaveApplication(DocListController):
def validate_to_date(self):
if self.from_date and self.to_date and \
(getdate(self.to_date) < getdate(self.from_date)):
msgprint("To date cannot be before from date")
raise Exception
frappe.throw(_("To date cannot be before from date"))
def validate_balance_leaves(self):
if self.from_date and self.to_date:
self.total_leave_days = self.get_total_leave_days()["total_leave_days"]
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."),
raise_exception=1)
frappe.throw(_("The day(s) on which you are applying for leave are holiday. You need not apply for leave."))
if not is_lwp(self.leave_type):
self.leave_balance = get_leave_balance(self.employee,
self.leave_type, self.fiscal_year)["leave_balance"]
@ -118,94 +115,96 @@ class LeaveApplication(DocListController):
if self.status != "Rejected" \
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.
msgprint("There is not enough leave balance for Leave Type: %s" % \
(self.leave_type,),
raise_exception=not(frappe.db.get_value("Leave Type", self.leave_type,"allow_negative") or None))
if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
frappe.msgprint(_("Note: There is not enough leave balance for Leave Type {0}").format(self.leave_type))
else:
frappe.throw(_("There is not enough leave balance for Leave Type {0}").format(self.leave_type))
def validate_leave_overlap(self):
if not self.name:
self.name = "New Leave Application"
for d in frappe.db.sql("""select name, leave_type, posting_date,
from_date, to_date
from `tabLeave Application`
where
for d in frappe.db.sql("""select name, leave_type, posting_date,
from_date, to_date
from `tabLeave Application`
where
employee = %(employee)s
and docstatus < 2
and status in ("Open", "Approved")
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 %(from_date)s between from_date and to_date)
and name != %(name)s""", self.as_dict(), 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.employee, cstr(d['leave_type']), formatdate(d['from_date']), formatdate(d['to_date']), formatdate(d['posting_date']), d['name'], d['name']), raise_exception = OverlapError)
frappe.msgprint(_("Employee {0} has already applied for {1} between {2} and {3}").format(self.employee,
cstr(d['leave_type']), formatdate(d['from_date']), formatdate(d['to_date'])))
frappe.throw('<a href="#Form/Leave Application/{0}">{0}</a>'.format(d["name"]), OverlapError)
def validate_max_days(self):
max_days = frappe.db.get_value("Leave Type", self.leave_type, "max_days_allowed")
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.leave_type, max_days))
def validate_leave_approver(self):
employee = frappe.get_doc("Employee", self.employee)
leave_approvers = [l.leave_approver for l in
leave_approvers = [l.leave_approver for l in
employee.get("employee_leave_approvers")]
if len(leave_approvers) and self.leave_approver not in leave_approvers:
msgprint(("[" + _("For Employee") + ' "' + self.employee + '"] '
+ _("Leave Approver can be one of") + ": "
+ comma_or(leave_approvers)), raise_exception=InvalidLeaveApproverError)
elif self.leave_approver and not frappe.db.sql("""select name from `tabUserRole`
frappe.throw(_("Leave approver must be one of {0}").format(comma_or(leave_approvers)), InvalidLeaveApproverError)
elif self.leave_approver and not frappe.db.sql("""select name from `tabUserRole`
where parent=%s and role='Leave Approver'""", self.leave_approver):
msgprint(get_fullname(self.leave_approver) + ": " \
+ _("does not have role 'Leave Approver'"), raise_exception=InvalidLeaveApproverError)
frappe.throw(_("{0} must have role 'Leave Approver'").format(get_fullname(self.leave_approver)),
InvalidLeaveApproverError)
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"),
raise_exception=LeaveApproverIdentityError)
def notify_employee(self, status):
employee = frappe.get_doc("Employee", self.employee)
if not employee.user_id:
return
def _get_message(url=False):
if url:
name = get_url_to_form(self.doctype, self.name)
else:
name = self.name
return (_("Leave Application") + ": %s - %s") % (name, _(status))
self.notify({
# for post in messages
"message": _get_message(url=True),
"message_to": employee.user_id,
"subject": _get_message(),
})
def notify_leave_approver(self):
employee = frappe.get_doc("Employee", self.employee)
def _get_message(url=False):
name = self.name
employee_name = cstr(employee.employee_name)
if url:
name = get_url_to_form(self.doctype, self.name)
employee_name = get_url_to_form("Employee", self.employee, label=employee_name)
return (_("New Leave Application") + ": %s - " + _("Employee") + ": %s") % (name, employee_name)
self.notify({
# for post in messages
"message": _get_message(url=True),
"message_to": self.leave_approver,
# for email
"subject": _get_message()
})
def notify(self, args):
args = frappe._dict(args)
from frappe.core.page.messages.messages import post
@ -213,62 +212,62 @@ class LeaveApplication(DocListController):
"notify": cint(self.follow_via_email)})
@frappe.whitelist()
def get_leave_balance(employee, leave_type, fiscal_year):
leave_all = frappe.db.sql("""select total_leaves_allocated
def get_leave_balance(employee, leave_type, fiscal_year):
leave_all = frappe.db.sql("""select total_leaves_allocated
from `tabLeave Allocation` where employee = %s and leave_type = %s
and fiscal_year = %s and docstatus = 1""", (employee,
and fiscal_year = %s and docstatus = 1""", (employee,
leave_type, fiscal_year))
leave_all = leave_all and flt(leave_all[0][0]) or 0
leave_app = frappe.db.sql("""select SUM(total_leave_days)
from `tabLeave Application`
leave_app = frappe.db.sql("""select SUM(total_leave_days)
from `tabLeave Application`
where employee = %s and leave_type = %s and fiscal_year = %s
and status="Approved" and docstatus = 1""", (employee, leave_type, fiscal_year))
leave_app = leave_app and flt(leave_app[0][0]) or 0
ret = {'leave_balance': leave_all - leave_app}
return ret
def is_lwp(leave_type):
lwp = frappe.db.sql("select is_lwp from `tabLeave Type` where name = %s", leave_type)
return lwp and cint(lwp[0][0]) or 0
@frappe.whitelist()
def get_events(start, end):
events = []
employee = frappe.db.get_default("employee", frappe.session.user)
company = frappe.db.get_default("company", frappe.session.user)
from frappe.widgets.reportview import build_match_conditions
match_conditions = build_match_conditions("Leave Application")
# show department leaves for employee
if "Employee" in frappe.get_roles():
add_department_leaves(events, start, end, employee, company)
add_leaves(events, start, end, employee, company, match_conditions)
add_block_dates(events, start, end, employee, company)
add_holidays(events, start, end, employee, company)
return events
def add_department_leaves(events, start, end, employee, company):
department = frappe.db.get_value("Employee", employee, "department")
if not department:
return
# department leaves
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
and company=%s""", (department, company))
match_conditions = "employee in (\"%s\")" % '", "'.join(department_employees)
add_leaves(events, start, end, employee, company, match_conditions=match_conditions)
def add_leaves(events, start, end, employee, company, match_conditions=None):
query = """select name, from_date, to_date, employee_name, half_day,
query = """select name, from_date, to_date, employee_name, half_day,
status, employee, docstatus
from `tabLeave Application` where
(from_date between %s and %s or to_date between %s and %s)
@ -276,7 +275,7 @@ def add_leaves(events, start, end, employee, company, match_conditions=None):
and status!="Rejected" """
if match_conditions:
query += " and " + match_conditions
for d in frappe.db.sql(query, (start, end, start, end), as_dict=True):
e = {
"name": d.name,
@ -311,9 +310,9 @@ def add_holidays(events, start, end, employee, company):
applicable_holiday_list = frappe.db.get_value("Employee", employee, "holiday_list")
if not applicable_holiday_list:
return
for holiday in frappe.db.sql("""select name, holiday_date, description
from `tabHoliday` where parent=%s and holiday_date between %s and %s""",
from `tabHoliday` where parent=%s and holiday_date between %s and %s""",
(applicable_holiday_list, start, end), as_dict=True):
events.append({
"doctype": "Holiday",
@ -325,24 +324,24 @@ def add_holidays(events, start, end, employee, company):
@frappe.whitelist()
def query_for_permitted_employees(doctype, txt, searchfield, start, page_len, filters):
txt = "%" + cstr(txt) + "%"
if "Leave Approver" in frappe.user.get_roles():
user = frappe.session.user.replace('"', '\"')
condition = """and (exists(select ela.name from `tabEmployee Leave Approver` ela
where ela.parent=`tabEmployee`.name and ela.leave_approver= "%s") or
not exists(select ela.name from `tabEmployee Leave Approver` ela
where ela.parent=`tabEmployee`.name and ela.leave_approver= "%s") or
not exists(select ela.name from `tabEmployee Leave Approver` ela
where ela.parent=`tabEmployee`.name)
or user_id = "%s")""" % (user, user)
else:
from frappe.widgets.reportview import build_match_conditions
condition = build_match_conditions("Employee")
condition = ("and " + condition) if condition else ""
return frappe.db.sql("""select name, employee_name from `tabEmployee`
where status = 'Active' and docstatus < 2 and
(`%s` like %s or employee_name like %s) %s
order by
case when name like %s then 0 else 1 end,
case when employee_name like %s then 0 else 1 end,
name limit %s, %s""" % tuple([searchfield] + ["%s"]*2 + [condition] + ["%s"]*4),
name limit %s, %s""" % tuple([searchfield] + ["%s"]*2 + [condition] + ["%s"]*4),
(txt, txt, txt, txt, start, page_len))

View File

@ -4,16 +4,16 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt, nowdate
from frappe.utils import cint, cstr, flt, nowdate, comma_and
from frappe import msgprint, _
from frappe.model.document import Document
class LeaveControlPanel(Document):
def get_employees(self):
def get_employees(self):
lst1 = [[self.employee_type,"employment_type"],[self.branch,"branch"],[self.designation,"designation"],[self.department, "department"],[self.grade,"grade"]]
condition = "where "
flag = 0
@ -26,7 +26,7 @@ class LeaveControlPanel(Document):
flag = 1
emp_query = "select name from `tabEmployee` "
if flag == 1:
emp_query += condition
emp_query += condition
e = frappe.db.sql(emp_query)
return e
@ -41,7 +41,7 @@ class LeaveControlPanel(Document):
employees = self.get_employees()
if not employees:
frappe.throw(_("No employee found"))
for d in self.get_employees():
try:
la = frappe.get_doc('Leave Allocation')
@ -59,4 +59,4 @@ class LeaveControlPanel(Document):
except:
pass
if leave_allocated_for:
msgprint("Leaves Allocated Successfully for " + ", ".join(leave_allocated_for))
msgprint(_("Leaves Allocated Successfully for {0}").format(comma_and(leave_allocated_for)))

View File

@ -4,57 +4,56 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, flt
from frappe import msgprint
from frappe import _
from frappe.model.document import Document
class SalaryManager(Document):
def get_emp_list(self):
"""
Returns list of active employees based on selected criteria
and for which salary structure exists
Returns list of active employees based on selected criteria
and for which salary structure exists
"""
cond = self.get_filter_condition()
cond += self.get_joining_releiving_condition()
emp_list = frappe.db.sql("""
select t1.name
from `tabEmployee` t1, `tabSalary Structure` t2
where t1.docstatus!=2 and t2.docstatus != 2
from `tabEmployee` t1, `tabSalary Structure` t2
where t1.docstatus!=2 and t2.docstatus != 2
and t1.name = t2.employee
%s """% cond)
return emp_list
def get_filter_condition(self):
self.check_mandatory()
cond = ''
for f in ['company', 'branch', 'department', 'designation', 'grade']:
if self.get(f):
cond += " and t1." + f + " = '" + self.get(f).replace("'", "\'") + "'"
cond += " and t1." + f + " = '" + self.get(f).replace("'", "\'") + "'"
return cond
def get_joining_releiving_condition(self):
m = self.get_month_details(self.fiscal_year, self.month)
cond = """
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.date_of_joining, '0000-00-00') <= '%(month_end_date)s'
and ifnull(t1.relieving_date, '2199-12-31') >= '%(month_start_date)s'
""" % m
return cond
def check_mandatory(self):
for f in ['company', 'month', 'fiscal_year']:
if not self.get(f):
msgprint("Please select %s to proceed" % f, raise_exception=1)
frappe.throw(_("Please set {0}").format(f))
def get_month_details(self, year, month):
ysd = frappe.db.get_value("Fiscal Year", year, "year_start_date")
if ysd:
@ -67,22 +66,22 @@ class SalaryManager(Document):
month_days = cint(calendar.monthrange(cint(msd.year) ,cint(month))[1]) # days in month
med = datetime.date(msd.year, cint(month), month_days) # month end date
return {
'year': msd.year,
'month_start_date': msd,
'month_end_date': med,
'year': msd.year,
'month_start_date': msd,
'month_end_date': med,
'month_days': month_days
}
def create_sal_slip(self):
"""
Creates salary slip for selected employees if already not created
"""
emp_list = self.get_emp_list()
ss_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
""", (emp[0], self.month, self.fiscal_year, self.company)):
ss = frappe.get_doc({
@ -95,18 +94,18 @@ class SalaryManager(Document):
})
ss.insert()
ss_list.append(ss.name)
return self.create_log(ss_list)
def create_log(self, ss_list):
log = "<b>No employee for the above selected criteria OR salary slip already created</b>"
if ss_list:
log = "<b>Created Salary Slip has been created: </b>\
<br><br>%s" % '<br>'.join(ss_list)
return log
def get_sal_slip_list(self):
"""
Returns list of salary slips based on selected criteria
@ -114,17 +113,17 @@ class SalaryManager(Document):
"""
cond = self.get_filter_condition()
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
""" % ('%s', '%s', cond), (self.month, self.fiscal_year))
return ss_list
def submit_salary_slip(self):
"""
Submit all salary slips based on selected criteria
"""
ss_list = self.get_sal_slip_list()
ss_list = self.get_sal_slip_list()
not_submitted_ss = []
for ss in ss_list:
ss_obj = frappe.get_doc("Salary Slip",ss[0])
@ -132,31 +131,31 @@ class SalaryManager(Document):
frappe.db.set(ss_obj, 'email_check', cint(self.send_mail))
if cint(self.send_email) == 1:
ss_obj.send_mail_funct()
frappe.db.set(ss_obj, 'docstatus', 1)
except Exception,e:
not_submitted_ss.append(ss[0])
msgprint(e)
frappe.msgprint(e)
continue
return self.create_submit_log(ss_list, not_submitted_ss)
def create_submit_log(self, all_ss, not_submitted_ss):
log = ''
if not all_ss:
log = "No salary slip found to submit for the above selected criteria"
else:
all_ss = [d[0] for d in all_ss]
submitted_ss = list(set(all_ss) - set(not_submitted_ss))
submitted_ss = list(set(all_ss) - set(not_submitted_ss))
if submitted_ss:
mail_sent_msg = self.send_email and " (Mail has been sent to the employee)" or ""
log = """
<b>Submitted Salary Slips%s:</b>\
<br><br> %s <br><br>
""" % (mail_sent_msg, '<br>'.join(submitted_ss))
if not_submitted_ss:
log += """
<b>Not Submitted Salary Slips: </b>\
@ -167,33 +166,33 @@ class SalaryManager(Document):
send mail, uncheck 'Send Email' checkbox. <br>\
Then try to submit Salary Slip again.
"""% ('<br>'.join(not_submitted_ss))
return log
return log
def get_total_salary(self):
"""
Get total salary amount from submitted salary slip based on selected criteria
"""
cond = self.get_filter_condition()
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
""" % ('%s', '%s', cond), (self.month, self.fiscal_year))
return flt(tot[0][0])
def get_acc_details(self):
"""
get default bank account,default salary acount from company
"""
amt = self.get_total_salary()
default_bank_account = frappe.db.get_value("Company", self.company,
default_bank_account = frappe.db.get_value("Company", self.company,
"default_bank_account")
if not default_bank_account:
msgprint("You can set Default Bank Account in Company master.")
frappe.msgprint(_("You can set Default Bank Account in Company master"))
return {
'default_bank_account' : default_bank_account,
'amount' : amt
}
}

View File

@ -10,12 +10,12 @@ from frappe.model.naming import make_autoname
from frappe import msgprint, _
from erpnext.setup.utils import get_company_currency
from erpnext.utilities.transaction_base import TransactionBase
class SalarySlip(TransactionBase):
def autoname(self):
self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
def get_emp_and_leave_details(self):
if self.employee:
@ -25,19 +25,19 @@ class SalarySlip(TransactionBase):
self.pull_sal_struct(struct)
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.employee)
if not struct:
msgprint("Please create Salary Structure for employee '%s'" % self.employee)
msgprint(_("Please create Salary Structure for employee {0}").format(self.employee))
self.employee = None
return struct and struct[0][0] or ''
def pull_sal_struct(self, struct):
from erpnext.hr.doctype.salary_structure.salary_structure import get_mapped_doc
self.update(get_mapped_doc(struct, self))
def pull_emp_details(self):
emp = frappe.db.get_value("Employee", self.employee,
emp = frappe.db.get_value("Employee", self.employee,
["bank_name", "bank_ac_no", "esic_card_no", "pf_number"], as_dict=1)
if emp:
self.bank_name = emp.bank_name
@ -50,39 +50,36 @@ class SalarySlip(TransactionBase):
self.fiscal_year = frappe.get_default("fiscal_year")
if not self.month:
self.month = "%02d" % getdate(nowdate()).month
m = frappe.get_doc('Salary Manager').get_month_details(self.fiscal_year, self.month)
holidays = self.get_holidays_for_employee(m)
if not cint(frappe.db.get_value("HR Settings", "HR Settings",
"include_holidays_in_total_working_days")):
m["month_days"] -= len(holidays)
if m["month_days"] < 0:
msgprint(_("Bummer! There are more holidays than working days this month."),
raise_exception=True)
frappe.throw(_("There are more holidays than working days this month."))
if not lwp:
lwp = self.calculate_lwp(holidays, m)
self.total_days_in_month = m['month_days']
self.leave_without_pay = lwp
payment_days = flt(self.get_payment_days(m)) - flt(lwp)
self.payment_days = payment_days > 0 and payment_days or 0
def get_payment_days(self, m):
payment_days = m['month_days']
emp = frappe.db.sql("select date_of_joining, relieving_date from `tabEmployee` \
where name = %s", self.employee, as_dict=1)[0]
if emp['relieving_date']:
if getdate(emp['relieving_date']) > m['month_start_date'] and \
getdate(emp['relieving_date']) < m['month_end_date']:
payment_days = getdate(emp['relieving_date']).day
elif getdate(emp['relieving_date']) < m['month_start_date']:
frappe.msgprint(_("Relieving Date of employee is ") + cstr(emp['relieving_date']
+ _(". Please set status of the employee as 'Left'")), raise_exception=1)
frappe.throw(_("Employee relieved on {0} must be set as 'Left'").format(emp["relieving_date"]))
if emp['date_of_joining']:
if getdate(emp['date_of_joining']) > m['month_start_date'] and \
getdate(emp['date_of_joining']) < m['month_end_date']:
@ -91,19 +88,19 @@ class SalarySlip(TransactionBase):
payment_days = 0
return payment_days
def get_holidays_for_employee(self, m):
holidays = frappe.db.sql("""select t1.holiday_date
from `tabHoliday` t1, tabEmployee t2
where t1.parent = t2.holiday_list and t2.name = %s
and t1.holiday_date between %s and %s""",
holidays = frappe.db.sql("""select t1.holiday_date
from `tabHoliday` t1, tabEmployee t2
where t1.parent = t2.holiday_list and t2.name = %s
and t1.holiday_date between %s and %s""",
(self.employee, m['month_start_date'], m['month_end_date']))
if not holidays:
holidays = frappe.db.sql("""select t1.holiday_date
from `tabHoliday` t1, `tabHoliday List` t2
where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1
holidays = frappe.db.sql("""select t1.holiday_date
from `tabHoliday` t1, `tabHoliday List` t2
where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1
and t2.fiscal_year = %s
and t1.holiday_date between %s and %s""", (self.fiscal_year,
and t1.holiday_date between %s and %s""", (self.fiscal_year,
m['month_start_date'], m['month_end_date']))
holidays = [cstr(i[0]) for i in holidays]
return holidays
@ -115,10 +112,10 @@ class SalarySlip(TransactionBase):
if dt not in holidays:
leave = frappe.db.sql("""
select t1.name, t1.half_day
from `tabLeave Application` t1, `tabLeave Type` t2
where t2.name = t1.leave_type
and ifnull(t2.is_lwp, 0) = 1
and t1.docstatus = 1
from `tabLeave Application` t1, `tabLeave Type` t2
where t2.name = t1.leave_type
and ifnull(t2.is_lwp, 0) = 1
and t1.docstatus = 1
and t1.employee = %s
and %s between from_date and to_date
""", (self.employee, dt))
@ -127,21 +124,19 @@ class SalarySlip(TransactionBase):
return lwp
def check_existing(self):
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
where month = %s and fiscal_year = %s and docstatus != 2
and employee = %s and name != %s""",
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
where month = %s and fiscal_year = %s and docstatus != 2
and employee = %s and name != %s""",
(self.month, self.fiscal_year, self.employee, self.name))
if ret_exist:
self.employee = ''
msgprint("Salary Slip of employee '%s' already created for this month"
% self.employee, raise_exception=1)
frappe.throw("Salary Slip of employee {0} already created for this month".format(self.employee))
def validate(self):
from frappe.utils import money_in_words
self.check_existing()
if not (len(self.get("earning_details")) or
if not (len(self.get("earning_details")) or
len(self.get("deduction_details"))):
self.get_emp_and_leave_details()
else:
@ -149,7 +144,7 @@ class SalarySlip(TransactionBase):
if not self.net_pay:
self.calculate_net_pay()
company_currency = get_company_currency(self.company)
self.total_in_words = money_in_words(self.rounded_total, company_currency)
@ -164,46 +159,46 @@ class SalarySlip(TransactionBase):
else:
d.e_modified_amount = d.e_amount
self.gross_pay += flt(d.e_modified_amount)
def calculate_ded_total(self):
self.total_deduction = 0
for d in self.get('deduction_details'):
if cint(d.d_depends_on_lwp) == 1:
d.d_modified_amount = _round(flt(d.d_amount) * flt(self.payment_days)
d.d_modified_amount = _round(flt(d.d_amount) * flt(self.payment_days)
/ cint(self.total_days_in_month), 2)
elif not self.payment_days:
d.d_modified_amount = 0
else:
d.d_modified_amount = d.d_amount
self.total_deduction += flt(d.d_modified_amount)
def calculate_net_pay(self):
self.calculate_earning_total()
self.calculate_ded_total()
self.net_pay = flt(self.gross_pay) - flt(self.total_deduction)
self.rounded_total = _round(self.net_pay)
self.rounded_total = _round(self.net_pay)
def on_submit(self):
if(self.email_check == 1):
if(self.email_check == 1):
self.send_mail_funct()
def send_mail_funct(self):
def send_mail_funct(self):
from frappe.utils.email_lib import sendmail
receiver = frappe.db.get_value("Employee", self.employee, "company_email")
if receiver:
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.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.name)
earn_table = ''
ded_table = ''
if earn_ret:
if earn_ret:
earn_table += "<table cellspacing=5px cellpadding=5px width='100%%'>"
for e in earn_ret:
if not e[1]:
earn_table += '<tr><td>%s</td><td align="right">0.00</td></tr>' % cstr(e[0])
@ -211,11 +206,11 @@ class SalarySlip(TransactionBase):
earn_table += '<tr><td>%s</td><td align="right">%s</td></tr>' \
% (cstr(e[0]), cstr(e[1]))
earn_table += '</table>'
if ded_ret:
ded_table += "<table cellspacing=5px cellpadding=5px width='100%%'>"
for d in ded_ret:
if not d[1]:
ded_table +='<tr><td">%s</td><td align="right">0.00</td></tr>' % cstr(d[0])
@ -223,10 +218,10 @@ class SalarySlip(TransactionBase):
ded_table +='<tr><td>%s</td><td align="right">%s</td></tr>' \
% (cstr(d[0]), cstr(d[1]))
ded_table += '</table>'
letter_head = frappe.db.get_value("Letter Head", {"is_default": 1, "disabled": 0},
letter_head = frappe.db.get_value("Letter Head", {"is_default": 1, "disabled": 0},
"content")
msg = '''<div> %s <br>
<table cellspacing= "5" cellpadding="5" width = "100%%">
<tr>
@ -248,15 +243,15 @@ class SalarySlip(TransactionBase):
<td width = "50%%">Designation : %s</td>
<td width = "50%%">Grade : %s</td>
</tr>
<tr>
<tr>
<td width = "50%%">Bank Account No. : %s</td>
<td width = "50%%">Bank Name : %s</td>
</tr>
<tr>
<td width = "50%%">Arrear Amount : <b>%s</b></td>
<td width = "50%%">Payment days : %s</td>
</tr>
</table>
<table border="1px solid #CCC" width="100%%" cellpadding="0px" cellspacing="0px">
@ -287,14 +282,14 @@ class SalarySlip(TransactionBase):
<td width='25%%'><b>Net Pay(in words) : </td>
<td colspan = '3' width = '50%%'>%s</b></td>
</tr>
</table></div>''' % (cstr(letter_head), cstr(self.employee),
cstr(self.employee_name), cstr(self.month), cstr(self.fiscal_year),
cstr(self.department), cstr(self.branch), cstr(self.designation),
cstr(self.grade), cstr(self.bank_account_no), cstr(self.bank_name),
cstr(self.arrear_amount), cstr(self.payment_days), earn_table, ded_table,
cstr(flt(self.gross_pay)), cstr(flt(self.total_deduction)),
</table></div>''' % (cstr(letter_head), cstr(self.employee),
cstr(self.employee_name), cstr(self.month), cstr(self.fiscal_year),
cstr(self.department), cstr(self.branch), cstr(self.designation),
cstr(self.grade), cstr(self.bank_account_no), cstr(self.bank_name),
cstr(self.arrear_amount), cstr(self.payment_days), earn_table, ded_table,
cstr(flt(self.gross_pay)), cstr(flt(self.total_deduction)),
cstr(flt(self.net_pay)), cstr(self.total_in_words))
sendmail([receiver], subject=subj, msg = msg)
else:
msgprint("Company Email ID not found, hence mail not sent")
msgprint(_("Company Email ID not found, hence mail not sent"))

View File

@ -6,7 +6,7 @@ import frappe
from frappe.utils import cstr, flt
from frappe.model.naming import make_autoname
from frappe import msgprint, _
from frappe import _
from frappe.model.document import Document
@ -17,7 +17,7 @@ class SalaryStructure(Document):
def get_employee_details(self):
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.employee)
if det:
ret = {
@ -31,7 +31,7 @@ class SalaryStructure(Document):
return ret
def get_ss_values(self,employee):
basic_info = frappe.db.sql("""select bank_name, bank_ac_no, esic_card_no, pf_number
basic_info = frappe.db.sql("""select bank_name, bank_ac_no, esic_card_no, pf_number
from `tabEmployee` where name =%s""", employee)
ret = {'bank_name': basic_info and basic_info[0][0] or '',
'bank_ac_no': basic_info and basic_info[0][1] or '',
@ -49,33 +49,32 @@ class SalaryStructure(Document):
elif(tab_fname == 'deduction_details'):
child.d_type = cstr(li[0])
child.d_modified_amt = 0
def make_earn_ded_table(self):
def make_earn_ded_table(self):
self.make_table('Earning Type','earning_details','Salary Structure Earning')
self.make_table('Deduction Type','deduction_details', 'Salary Structure Deduction')
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.employee,self.name))
if ret and self.is_active=='Yes':
msgprint(_("""Another Salary Structure '%s' is active for employee '%s'. Please make its status 'Inactive' to proceed.""") %
(cstr(ret), self.employee), raise_exception=1)
frappe.throw(_("Another Salary Structure {0} is active for employee {0}. Please make its status 'Inactive' to proceed.").format(cstr(ret), self.employee))
def validate_amount(self):
if flt(self.net_pay) < 0:
msgprint(_("Net pay can not be negative"), raise_exception=1)
frappe.throw(_("Net pay cannot be negative"))
def validate(self):
def validate(self):
self.check_existing()
self.validate_amount()
@frappe.whitelist()
def make_salary_slip(source_name, target_doc=None):
return get_mapped_doc(source_name, target_doc).as_dict()
def get_mapped_doc(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
def postprocess(source, target):
sal_slip = frappe.get_doc(target)
sal_slip.run_method("pull_emp_details")
@ -84,24 +83,24 @@ def get_mapped_doc(source_name, target_doc=None):
doc = get_mapped_doc("Salary Structure", source_name, {
"Salary Structure": {
"doctype": "Salary Slip",
"doctype": "Salary Slip",
"field_map": {
"total_earning": "gross_pay"
}
},
},
"Salary Structure Deduction": {
"doctype": "Salary Slip Deduction",
"doctype": "Salary Slip Deduction",
"field_map": [
["depend_on_lwp", "d_depends_on_lwp"],
["d_modified_amt", "d_amount"],
["d_modified_amt", "d_modified_amount"]
],
"add_if_empty": True
},
},
"Salary Structure Earning": {
"doctype": "Salary Slip Earning",
"doctype": "Salary Slip Earning",
"field_map": [
["depend_on_lwp", "e_depends_on_lwp"],
["depend_on_lwp", "e_depends_on_lwp"],
["modified_value", "e_modified_amount"],
["modified_value", "e_amount"]
],

View File

@ -6,7 +6,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, add_days, date_diff
from frappe import msgprint, _
from frappe import _
from frappe.utils.datautils import UnicodeWriter
from frappe.model.document import Document
@ -17,32 +17,32 @@ class UploadAttendance(Document):
def get_template():
if not frappe.has_permission("Attendance", "create"):
raise frappe.PermissionError
args = frappe.local.form_dict
w = UnicodeWriter()
w = add_header(w)
w = add_data(w, args)
# write out response as a type csv
frappe.response['result'] = cstr(w.getvalue())
frappe.response['type'] = 'csv'
frappe.response['doctype'] = "Attendance"
def add_header(w):
status = ", ".join((frappe.get_meta("Attendance").get_field("status").options or "").strip().split("\n"))
w.writerow(["Notes:"])
w.writerow(["Please do not change the template headings"])
w.writerow(["Status should be one of these values: " + status])
w.writerow(["If you are overwriting existing attendance records, 'ID' column mandatory"])
w.writerow(["ID", "Employee", "Employee Name", "Date", "Status",
w.writerow(["ID", "Employee", "Employee Name", "Date", "Status",
"Fiscal Year", "Company", "Naming Series"])
return w
def add_data(w, args):
from erpnext.accounts.utils import get_fiscal_year
dates = get_dates(args)
employees = get_active_employees()
existing_attendance_records = get_existing_attendance_records(args)
@ -54,9 +54,9 @@ def add_data(w, args):
existing_attendance = existing_attendance_records[tuple([date, employee.name])]
row = [
existing_attendance and existing_attendance.name or "",
employee.name, employee.employee_name, date,
employee.name, employee.employee_name, date,
existing_attendance and existing_attendance.status or "",
get_fiscal_year(date)[0], employee.company,
get_fiscal_year(date)[0], employee.company,
existing_attendance and existing_attendance.naming_series or get_naming_series(),
]
w.writerow(row)
@ -67,28 +67,27 @@ def get_dates(args):
no_of_days = date_diff(add_days(args["to_date"], 1), args["from_date"])
dates = [add_days(args["from_date"], i) for i in range(0, no_of_days)]
return dates
def get_active_employees():
employees = frappe.db.sql("""select name, employee_name, company
employees = frappe.db.sql("""select name, employee_name, company
from tabEmployee where docstatus < 2 and status = 'Active'""", as_dict=1)
return employees
def get_existing_attendance_records(args):
attendance = frappe.db.sql("""select name, att_date, employee, status, naming_series
from `tabAttendance` where att_date between %s and %s and docstatus < 2""",
attendance = frappe.db.sql("""select name, att_date, employee, status, naming_series
from `tabAttendance` where att_date between %s and %s and docstatus < 2""",
(args["from_date"], args["to_date"]), as_dict=1)
existing_attendance = {}
for att in attendance:
existing_attendance[tuple([att.att_date, att.employee])] = att
return existing_attendance
def get_naming_series():
series = frappe.get_meta("Attendance").get_field("naming_series").options.strip().split("\n")
if not series:
msgprint("""Please create naming series for Attendance \
through Setup -> Numbering Series.""", raise_exception=1)
frappe.throw(_("Please setup numbering series for Attendance via Setup > Numbering Series"))
return series[0]
@ -96,10 +95,10 @@ def get_naming_series():
def upload():
if not frappe.has_permission("Attendance", "create"):
raise frappe.PermissionError
from frappe.utils.datautils import read_csv_content_from_uploaded_file
from frappe.modules import scrub
rows = read_csv_content_from_uploaded_file()
if not rows:
msg = [_("Please select a csv file")]
@ -109,10 +108,9 @@ def upload():
columns[3] = "att_date"
ret = []
error = False
from frappe.utils.datautils import check_record, import_doc
doctype_dl = frappe.get_meta("Attendance")
for i, row in enumerate(rows[5:]):
if not row: continue
row_idx = i + 5
@ -120,18 +118,18 @@ def upload():
d["doctype"] = "Attendance"
if d.name:
d["docstatus"] = frappe.db.get_value("Attendance", d.name, "docstatus")
try:
check_record(d)
ret.append(import_doc(d, "Attendance", 1, row_idx, submit=True))
except Exception, e:
error = True
ret.append('Error for row (#%d) %s : %s' % (row_idx,
ret.append('Error for row (#%d) %s : %s' % (row_idx,
len(row)>1 and row[1] or "", cstr(e)))
frappe.errprint(frappe.get_traceback())
if error:
frappe.db.rollback()
frappe.db.rollback()
else:
frappe.db.commit()
return {"messages": ret, "error": error}

View File

@ -10,8 +10,8 @@ def get_leave_approver_list():
roles = [r[0] for r in frappe.db.sql("""select distinct parent from `tabUserRole`
where role='Leave Approver'""")]
if not roles:
frappe.msgprint(_("No Leave Approvers. Please assign 'Leave Approver' Role to atleast one user."))
frappe.msgprint(_("No Leave Approvers. Please assign 'Leave Approver' Role to atleast one user"))
return roles
@ -20,6 +20,5 @@ def get_expense_approver_list():
roles = [r[0] for r in frappe.db.sql("""select distinct parent from `tabUserRole`
where role='Expense Approver'""")]
if not roles:
frappe.msgprint("No Expense Approvers. Please assign 'Expense Approver' \
Role to atleast one user.")
frappe.msgprint(_("No Expense Approvers. Please assign 'Expense Approver' Role to atleast one user"))
return roles

View File

@ -5,10 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt, now, nowdate
from frappe import msgprint, _
from frappe import _
from frappe.model.document import Document
class BOM(Document):
@ -64,11 +61,7 @@ class BOM(Document):
def validate_rm_item(self, item):
if item[0]['name'] == self.item:
msgprint("Item_code: %s in materials tab cannot be same as FG Item",
item[0]['name'], raise_exception=1)
if not item or item[0]['docstatus'] == 2:
msgprint("Item %s does not exist in system" % item[0]['item_code'], raise_exception = 1)
frappe.throw(_("Raw material cannot be same as main Item"))
def set_bom_material_details(self):
for item in self.get("bom_materials"):
@ -188,12 +181,10 @@ class BOM(Document):
""" Validate main FG item"""
item = self.get_item_det(self.item)
if not item:
msgprint("Item %s does not exists in the system or expired." %
self.item, raise_exception = 1)
frappe.throw(_("Item {0} does not exists in the system or has expired").format(self.item))
elif item[0]['is_manufactured_item'] != 'Yes' \
and item[0]['is_sub_contracted_item'] != 'Yes':
msgprint("""As Item: %s is not a manufactured / sub-contracted item, \
you can not make BOM for it""" % self.item, raise_exception = 1)
frappe.throw(_("Item {0} must be manufactured or sub-contracted").format(self.item))
else:
ret = frappe.db.get_value("Item", self.item, ["description", "stock_uom"])
self.description = ret[0]
@ -204,8 +195,7 @@ class BOM(Document):
self.op = []
for d in self.get('bom_operations'):
if cstr(d.operation_no) in self.op:
msgprint("Operation no: %s is repeated in Operations Table" %
d.operation_no, raise_exception=1)
frappe.throw(_("Operation {0} is repeated in Operations Table").format(d.operation_no))
else:
# add operation in op list
self.op.append(cstr(d.operation_no))
@ -216,26 +206,20 @@ class BOM(Document):
for m in self.get('bom_materials'):
# check if operation no not in op table
if self.with_operations and cstr(m.operation_no) not in self.op:
msgprint("""Operation no: %s against item: %s at row no: %s \
is not present at Operations table""" %
(m.operation_no, m.item_code, m.idx), raise_exception = 1)
frappe.throw(_("Operation {0} not present in Operations Table").format(m.operation_no))
item = self.get_item_det(m.item_code)
if item[0]['is_manufactured_item'] == 'Yes':
if not m.bom_no:
msgprint("Please enter BOM No aginst item: %s at row no: %s" %
(m.item_code, m.idx), raise_exception=1)
frappe.throw(_("BOM number is required for manufactured Item {0} in row {1}").format(m.item, m.idx))
else:
self.validate_bom_no(m.item_code, m.bom_no, m.idx)
elif m.bom_no:
msgprint("""As Item %s is not a manufactured / sub-contracted item, \
you can not enter BOM against it (Row No: %s).""" %
(m.item_code, m.idx), raise_exception = 1)
frappe.throw(_("BOM number not allowed for non-manufactured Item {0} in row {1}").format(m.item_code, m.idx))
if flt(m.qty) <= 0:
msgprint("Please enter qty against raw material: %s at row no: %s" %
(m.item_code, m.idx), raise_exception = 1)
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
self.check_if_item_repeated(m.item_code, m.operation_no, check_list)
@ -245,14 +229,11 @@ class BOM(Document):
and is_active=1 and docstatus=1""",
(bom_no, item), as_dict =1)
if not bom:
msgprint("""Incorrect BOM No: %s against item: %s at row no: %s.
It may be inactive or not submitted or does not belong to this item.""" %
(bom_no, item, idx), raise_exception = 1)
frappe.throw(_("BOM {0} for Item {1} in row {2} is inactive or not submitted").format(bom_no, item, idx))
def check_if_item_repeated(self, item, op, check_list):
if [cstr(item), cstr(op)] in check_list:
msgprint(_("Item") + " %s " % (item,) + _("has been entered atleast twice")
+ (cstr(op) and _(" against same operation") or ""), raise_exception=1)
frappe.throw(_("Item {0} has been entered multiple times against same operation").format(item))
else:
check_list.append([cstr(item), cstr(op)])
@ -268,8 +249,7 @@ class BOM(Document):
count = count + 1
for b in boms:
if b[0] == self.name:
msgprint("""Recursion Occured => '%s' cannot be '%s' of '%s'.
""" % (cstr(b[0]), cstr(d[2]), self.name), raise_exception = 1)
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {2}").format(b[0], self.name))
if b[0]:
bom_list.append(b[0])
@ -389,12 +369,9 @@ class BOM(Document):
and docstatus = 1 and is_active = 1)""", self.name)
if act_pbom and act_pbom[0][0]:
action = self.docstatus < 2 and _("deactivate") or _("cancel")
msgprint(_("Cannot ") + action + _(": It is linked to other active BOM(s)"),
raise_exception=1)
frappe.throw(_("Cannot deactive or cancle BOM as it is linked with other BOMs"))
def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1):
import json
item_dict = {}
query = """select

View File

@ -4,8 +4,8 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt
from frappe import msgprint, _
from frappe import _
from frappe.model.document import Document
class BOMReplaceTool(Document):
@ -17,22 +17,22 @@ class BOMReplaceTool(Document):
for bom in bom_list:
bom_obj = frappe.get_doc("BOM", bom)
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
frappe.msgprint(_("BOM replaced"))
def validate_bom(self):
if cstr(self.current_bom) == cstr(self.new_bom):
msgprint("Current BOM and New BOM can not be same", raise_exception=1)
frappe.throw(_("Current BOM and New BOM can not be same"))
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.current_bom)
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,
rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""",
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""",
(self.new_bom, current_bom_unitcost, current_bom_unitcost, self.current_bom))
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""",
self.new_bom)]
self.new_bom)]

View File

@ -16,31 +16,31 @@ class ProductionOrder(Document):
def validate(self):
if self.docstatus == 0:
self.status = "Draft"
from erpnext.utilities import validate_status
validate_status(self.status, ["Draft", "Submitted", "Stopped",
validate_status(self.status, ["Draft", "Submitted", "Stopped",
"In Process", "Completed", "Cancelled"])
self.validate_bom_no()
self.validate_sales_order()
self.validate_warehouse()
from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
def validate_bom_no(self):
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"""
, (self.bom_no, self.production_item), as_dict =1)
if not bom:
frappe.throw("""Incorrect BOM: %s entered.
May be BOM not exists or inactive or not submitted
frappe.throw("""Incorrect BOM: %s entered.
May be BOM not exists or inactive or not submitted
or for some other item.""" % cstr(self.bom_no))
def validate_sales_order(self):
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.sales_order, as_dict=1)[0]
if not so.name:
@ -48,39 +48,39 @@ class ProductionOrder(Document):
if not self.expected_delivery_date:
self.expected_delivery_date = so.delivery_date
self.validate_production_order_against_so()
def validate_warehouse(self):
from erpnext.stock.utils import validate_warehouse_company
for w in [self.fg_warehouse, self.wip_warehouse]:
validate_warehouse_company(w, self.company)
def validate_production_order_against_so(self):
# already ordered qty
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.production_item, self.sales_order, self.name))[0][0]
total_qty = flt(ordered_qty_against_so) + flt(self.qty)
# get qty from Sales Order Item table
so_item_qty = frappe.db.sql("""select sum(qty) from `tabSales Order Item`
where parent = %s and item_code = %s""",
so_item_qty = frappe.db.sql("""select sum(qty) from `tabSales Order Item`
where parent = %s and item_code = %s""",
(self.sales_order, self.production_item))[0][0]
# get qty from Packing Item table
dnpi_qty = frappe.db.sql("""select sum(qty) from `tabPacked Item`
where parent = %s and parenttype = 'Sales Order' and item_code = %s""",
dnpi_qty = frappe.db.sql("""select sum(qty) from `tabPacked Item`
where parent = %s and parenttype = 'Sales Order' and item_code = %s""",
(self.sales_order, self.production_item))[0][0]
# total qty in SO
so_qty = flt(so_item_qty) + flt(dnpi_qty)
if total_qty > so_qty:
frappe.throw(_("Total production order qty for item") + ": " +
cstr(self.production_item) + _(" against sales order") + ": " +
cstr(self.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
_("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" +
frappe.throw(_("Total production order qty for item") + ": " +
cstr(self.production_item) + _(" against sales order") + ": " +
cstr(self.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
_("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" +
_("Please reduce qty."), exc=OverProductionError)
def stop_unstop(self, status):
@ -88,7 +88,7 @@ class ProductionOrder(Document):
self.update_status(status)
qty = (flt(self.qty)-flt(self.produced_qty)) * ((status == 'Stopped') and -1 or 1)
self.update_planned_qty(qty)
msgprint("Production Order has been %s" % status)
frappe.msgprint(_("Production Order status is {0}").format(status))
def update_status(self, status):
@ -108,14 +108,14 @@ class ProductionOrder(Document):
frappe.throw(_("WIP Warehouse required before Submit"))
frappe.db.set(self,'status', 'Submitted')
self.update_planned_qty(self.qty)
def on_cancel(self):
# 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.name)
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])
frappe.db.set(self,'status', 'Cancelled')
@ -132,27 +132,27 @@ class ProductionOrder(Document):
from erpnext.stock.utils import update_bin
update_bin(args)
@frappe.whitelist()
@frappe.whitelist()
def get_item_details(item):
res = frappe.db.sql("""select stock_uom, description
from `tabItem` where (ifnull(end_of_life, "")="" or end_of_life > now())
and name=%s""", item, as_dict=1)
if not res:
return {}
res = res[0]
bom = frappe.db.sql("""select name from `tabBOM` where item=%s
bom = frappe.db.sql("""select name from `tabBOM` where item=%s
and ifnull(is_default, 0)=1""", item)
if bom:
res.bom_no = bom[0][0]
return res
@frappe.whitelist()
def make_stock_entry(production_order_id, purpose):
production_order = frappe.get_doc("Production Order", production_order_id)
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.purpose = purpose
stock_entry.production_order = production_order_id
@ -160,12 +160,12 @@ def make_stock_entry(production_order_id, purpose):
stock_entry.bom_no = production_order.bom_no
stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
stock_entry.fg_completed_qty = flt(production_order.qty) - flt(production_order.produced_qty)
if purpose=="Material Transfer":
stock_entry.to_warehouse = production_order.wip_warehouse
else:
stock_entry.from_warehouse = production_order.wip_warehouse
stock_entry.to_warehouse = production_order.fg_warehouse
stock_entry.run_method("get_items")
return stock_entry.as_dict()

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt, cint, nowdate, add_days
from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and
from frappe import msgprint, _
@ -16,19 +16,19 @@ class ProductionPlanningTool(Document):
def get_so_details(self, so):
"""Pull other details from so"""
so = frappe.db.sql("""select transaction_date, customer, grand_total
so = frappe.db.sql("""select transaction_date, customer, grand_total
from `tabSales Order` where name = %s""", so, as_dict = 1)
ret = {
'sales_order_date': so and so[0]['transaction_date'] or '',
'customer' : so[0]['customer'] or '',
'grand_total': so[0]['grand_total']
}
return ret
return ret
def get_item_details(self, item_code):
""" Pull other item details from item master"""
item = frappe.db.sql("""select description, stock_uom, default_bom
item = frappe.db.sql("""select description, stock_uom, default_bom
from `tabItem` where name = %s""", item_code, as_dict =1)
ret = {
'description' : item and item[0]['description'],
@ -42,7 +42,7 @@ class ProductionPlanningTool(Document):
def clear_item_table(self):
self.set('pp_details', [])
def validate_company(self):
if not self.company:
frappe.throw(_("Please enter Company"))
@ -56,10 +56,10 @@ class ProductionPlanningTool(Document):
so_filter += ' and so.transaction_date <= "' + self.to_date + '"'
if self.customer:
so_filter += ' and so.customer = "' + self.customer + '"'
if self.fg_item:
item_filter += ' and item.name = "' + self.fg_item + '"'
open_so = frappe.db.sql("""
select distinct so.name, so.transaction_date, so.customer, so.grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
@ -68,15 +68,15 @@ class ProductionPlanningTool(Document):
and so.company = %s
and ifnull(so_item.qty, 0) > ifnull(so_item.delivered_qty, 0) %s
and (exists (select name from `tabItem` item where item.name=so_item.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 exists (select name from `tabPacked Item` pi
where pi.parent = so.name and pi.parent_item = so_item.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)))
""" % ('%s', so_filter, item_filter, item_filter), self.company, as_dict=1)
self.add_so_in_table(open_so)
def add_so_in_table(self, open_so):
@ -94,7 +94,7 @@ class ProductionPlanningTool(Document):
def get_items_from_so(self):
""" Pull items from Sales Order, only proction item
and subcontracted item will be pulled from Packing item
and subcontracted item will be pulled from Packing item
and add items in the table
"""
items = self.get_items()
@ -105,36 +105,36 @@ class ProductionPlanningTool(Document):
if not so_list:
msgprint(_("Please enter sales order in the above table"))
return []
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
(qty - ifnull(delivered_qty, 0)) as pending_qty
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0)
and exists (select * from `tabItem` item where item.name=so_item.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'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as reserved_warhouse,
(((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty)
(((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty)
as pending_qty
from `tabSales Order Item` so_item, `tabPacked Item` pi
where so_item.parent = pi.parent and so_item.docstatus = 1
where so_item.parent = pi.parent and so_item.docstatus = 1
and pi.parent_item = so_item.item_code
and so_item.parent in (%s) and ifnull(so_item.qty, 0) > ifnull(so_item.delivered_qty, 0)
and exists (select * 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'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
return items + packed_items
def add_items(self, items):
self.clear_item_table()
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'])
pi = self.append('pp_details', {})
pi.sales_order = p['parent']
@ -145,27 +145,27 @@ class ProductionPlanningTool(Document):
pi.bom_no = item_details and item_details[0][2] or ''
pi.so_pending_qty = flt(p['pending_qty'])
pi.planned_qty = flt(p['pending_qty'])
def validate_data(self):
self.validate_company()
for d in self.get('pp_details'):
self.validate_bom_no(d)
if not flt(d.planned_qty):
frappe.throw("Please Enter Planned Qty for item: %s at row no: %s" %
frappe.throw("Please Enter Planned Qty for item: %s at row no: %s" %
(d.item_code, d.idx))
def validate_bom_no(self, d):
if not d.bom_no:
frappe.throw("Please enter bom no for item: %s at row no: %s" %
frappe.throw("Please enter bom no for item: %s at row no: %s" %
(d.item_code, d.idx))
else:
bom = frappe.db.sql("""select name from `tabBOM` where name = %s and item = %s
and docstatus = 1 and is_active = 1""",
bom = frappe.db.sql("""select name from `tabBOM` where name = %s and item = %s
and docstatus = 1 and is_active = 1""",
(d.bom_no, d.item_code), as_dict = 1)
if not bom:
frappe.throw("""Incorrect BOM No: %s entered for item: %s at row no: %s
May be BOM is inactive or for other item or does not exists in the system""" %
May be BOM is inactive or for other item or does not exists in the system""" %
(d.bom_no, d.item_doce, d.idx))
def raise_production_order(self):
@ -180,9 +180,9 @@ class ProductionPlanningTool(Document):
if pro:
pro = ["""<a href="#Form/Production Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in pro]
msgprint(_("Production Order(s) created:\n\n") + '\n'.join(pro))
msgprint(_("{0} created").format(comma_and(pro)))
else :
msgprint(_("No Production Order created."))
msgprint(_("No Production Orders created"))
def get_distinct_items_and_boms(self):
""" Club similar BOM and item for processing
@ -191,7 +191,7 @@ class ProductionPlanningTool(Document):
}
"""
item_dict, bom_dict = {}, {}
for d in self.get("pp_details"):
for d in self.get("pp_details"):
bom_dict.setdefault(d.bom_no, []).append([d.sales_order, flt(d.planned_qty)])
item_dict[(d.item_code, d.sales_order, d.warehouse)] = {
"production_item" : d.item_code,
@ -207,7 +207,7 @@ class ProductionPlanningTool(Document):
"status" : "Draft",
}
return bom_dict, item_dict
def create_production_order(self, items):
"""Create production order. Called from Production Planning Tool"""
from erpnext.manufacturing.doctype.production_order.production_order import OverProductionError
@ -216,16 +216,16 @@ class ProductionPlanningTool(Document):
for key in items:
pro = frappe.new_doc("Production Order")
pro.update(items[key])
frappe.flags.mute_messages = True
try:
pro.insert()
pro_list.append(pro.name)
except OverProductionError, e:
except OverProductionError:
pass
frappe.flags.mute_messages = False
return pro_list
def download_raw_materials(self):
@ -236,41 +236,41 @@ class ProductionPlanningTool(Document):
return self.get_csv()
def get_raw_materials(self, bom_dict):
""" Get raw materials considering sub-assembly items
""" Get raw materials considering sub-assembly items
{
"item_code": [qty_required, description, stock_uom, min_order_qty]
}
"""
item_list = []
for bom, so_wise_qty in bom_dict.items():
bom_wise_item_details = {}
if self.use_multi_level_bom:
# get all raw materials with sub assembly childs
for d in frappe.db.sql("""select fb.item_code,
ifnull(sum(fb.qty_consumed_per_unit), 0) as qty,
fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb,`tabItem` it
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
and fb.docstatus<2 and fb.parent=%s
# get all raw materials with sub assembly childs
for d in frappe.db.sql("""select fb.item_code,
ifnull(sum(fb.qty_consumed_per_unit), 0) as qty,
fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb,`tabItem` it
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
and fb.docstatus<2 and fb.parent=%s
group by item_code, stock_uom""", bom, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
else:
# Get all raw materials considering SA items as raw materials,
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
for d in frappe.db.sql("""select bom_item.item_code,
ifnull(sum(bom_item.qty_consumed_per_unit), 0) as qty,
bom_item.description, bom_item.stock_uom, item.min_order_qty
from `tabBOM Item` bom_item, tabItem item
where bom_item.parent = %s and bom_item.docstatus < 2
and bom_item.item_code = item.name
for d in frappe.db.sql("""select bom_item.item_code,
ifnull(sum(bom_item.qty_consumed_per_unit), 0) as qty,
bom_item.description, bom_item.stock_uom, item.min_order_qty
from `tabBOM Item` bom_item, tabItem item
where bom_item.parent = %s and bom_item.docstatus < 2
and bom_item.item_code = item.name
group by item_code""", bom, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
for item, item_details in bom_wise_item_details.items():
for so_qty in so_wise_qty:
item_list.append([item, flt(item_details.qty) * so_qty[1], item_details.description,
item_list.append([item, flt(item_details.qty) * so_qty[1], item_details.description,
item_details.stock_uom, item_details.min_order_qty, so_qty[0]])
self.make_items_dict(item_list)
@ -286,18 +286,18 @@ class ProductionPlanningTool(Document):
total_qty = sum([flt(d[0]) for d in self.item_dict[item]])
for item_details in self.item_dict[item]:
item_list.append([item, item_details[1], item_details[2], item_details[0]])
item_qty = frappe.db.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
item_qty = frappe.db.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
from `tabBin` where item_code = %s""", item, as_dict=1)
i_qty, o_qty, a_qty = 0, 0, 0
for w in item_qty:
i_qty, o_qty, a_qty = i_qty + flt(w.indented_qty), o_qty + flt(w.ordered_qty), a_qty + flt(w.actual_qty)
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
flt(w.ordered_qty), flt(w.actual_qty)])
if item_qty:
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
return item_list
def raise_purchase_request(self):
"""
Raise Material Request if projected qty is less than qty required
@ -306,10 +306,10 @@ class ProductionPlanningTool(Document):
self.validate_data()
if not self.purchase_request_for_warehouse:
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]
self.get_raw_materials(bom_dict)
if self.item_dict:
self.insert_purchase_request()
@ -348,15 +348,15 @@ class ProductionPlanningTool(Document):
items_to_be_requested[item]["No Sales Order"] += requested_qty
return items_to_be_requested
def get_projected_qty(self):
items = self.item_dict.keys()
item_projected_qty = frappe.db.sql("""select item_code, sum(projected_qty)
from `tabBin` where item_code in (%s) group by item_code""" %
item_projected_qty = frappe.db.sql("""select item_code, sum(projected_qty)
from `tabBin` where item_code in (%s) group by item_code""" %
(", ".join(["%s"]*len(items)),), tuple(items))
return dict(item_projected_qty)
def insert_purchase_request(self):
items_to_be_requested = self.get_requested_items()
@ -397,11 +397,10 @@ class ProductionPlanningTool(Document):
pr_doc.ignore_permissions = 1
pr_doc.submit()
purchase_request_list.append(pr_doc.name)
if purchase_request_list:
pur_req = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
(p, p) for p in purchase_request_list]
msgprint("Material Request(s) created: \n%s" %
"\n".join(pur_req))
msgprint(_("Material Requests {0} created").format(comma_and(pur_req)))
else:
msgprint(_("Nothing to request"))

View File

@ -5,13 +5,13 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import flt, getdate
from frappe import msgprint
from frappe import _
from erpnext.utilities.transaction_base import delete_events
from frappe.model.document import Document
class Project(Document):
def get_gross_profit(self):
pft, per_pft =0, 0
pft = flt(self.project_value) - flt(self.est_material_cost)
@ -19,19 +19,18 @@ class Project(Document):
per_pft = (flt(pft) / flt(self.project_value)) * 100
ret = {'gross_margin_value': pft, 'per_gross_margin': per_pft}
return ret
def validate(self):
"""validate start date before end date"""
if self.project_start_date and self.completion_date:
if getdate(self.completion_date) < getdate(self.project_start_date):
msgprint("Expected Completion Date can not be less than Project Start Date")
raise Exception
frappe.throw(_("Expected Completion Date can not be less than Project Start Date"))
def on_update(self):
self.add_calendar_event()
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.name)[0][0]
if total:
completed = frappe.db.sql("""select count(*) from tabTask where
@ -42,7 +41,7 @@ class Project(Document):
def add_calendar_event(self):
# delete any earlier event for this project
delete_events(self.doctype, self.name)
# add events
for milestone in self.get("project_milestones"):
if milestone.milestone_date:
@ -57,6 +56,6 @@ class Project(Document):
"ref_type": self.doctype,
"ref_name": self.name
}).insert()
def on_trash(self):
delete_events(self.doctype, self.name)

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe, json
from frappe.utils import getdate, today
from frappe import msgprint
from frappe import _
from frappe.model.document import Document
@ -15,32 +15,30 @@ class Task(Document):
return {
"project": self.project
}
def get_customer_details(self):
cust = frappe.db.sql("select customer_name from `tabCustomer` where name=%s", self.customer)
if cust:
ret = {'customer_name': cust and cust[0][0] or ''}
return ret
def validate(self):
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'")
raise Exception
frappe.throw(_("'Expected Start Date' can not be greater than 'Expected 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'")
raise Exception
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
self.update_status()
def update_status(self):
status = frappe.db.get_value("Task", self.name, "status")
if self.status=="Working" and status !="Working" and not self.act_start_date:
self.act_start_date = today()
if self.status=="Closed" and status != "Closed" and not self.act_end_date:
self.act_end_date = today()
def on_update(self):
"""update percent complete in project"""
if self.project:
@ -55,14 +53,14 @@ def get_events(start, end, filters=None):
conditions = build_match_conditions("Task")
conditions and (" and " + conditions) or ""
if filters:
filters = json.loads(filters)
for key in filters:
if filters[key]:
conditions += " and " + key + ' = "' + filters[key].replace('"', '\"') + '"'
data = frappe.db.sql("""select name, exp_start_date, exp_end_date,
data = frappe.db.sql("""select name, exp_start_date, exp_end_date,
subject, status, project from `tabTask`
where ((exp_start_date between '%(start)s' and '%(end)s') \
or (exp_end_date between '%(start)s' and '%(end)s'))
@ -79,7 +77,7 @@ def get_project(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(""" select name from `tabProject`
where %(key)s like "%(txt)s"
%(mcond)s
order by name
limit %(start)s, %(page_len)s """ % {'key': searchfield,
order by name
limit %(start)s, %(page_len)s """ % {'key': searchfield,
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),
'start': start, 'page_len': page_len})
'start': start, 'page_len': page_len})

View File

@ -6,7 +6,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr
from frappe.utils import cstr, comma_and
class OverlapError(frappe.ValidationError): pass
@ -14,12 +14,12 @@ class OverlapError(frappe.ValidationError): pass
from frappe.model.document import Document
class TimeLog(Document):
def validate(self):
self.set_status()
self.validate_overlap()
self.calculate_total_hours()
def calculate_total_hours(self):
from frappe.utils import time_diff_in_hours
self.hours = time_diff_in_hours(self.to_time, self.from_time)
@ -30,36 +30,35 @@ class TimeLog(Document):
1: "Submitted",
2: "Cancelled"
}[self.docstatus or 0]
if self.time_log_batch:
self.status="Batched for Billing"
if self.sales_invoice:
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
(
(from_time between %s and %s) or
(to_time between %s and %s) or
(%s between from_time and to_time))
(from_time between %s and %s) or
(to_time between %s and %s) or
(%s between from_time and to_time))
and name!=%s
and ifnull(task, "")=%s
and docstatus < 2""",
(self.owner, self.from_time, self.to_time, self.from_time,
and docstatus < 2""",
(self.owner, self.from_time, self.to_time, self.from_time,
self.to_time, self.from_time, self.name or "No Name",
cstr(self.task)))
if existing:
frappe.msgprint(_("This Time Log conflicts with") + ":" + ', '.join(existing),
raise_exception=OverlapError)
frappe.throw(_("This Time Log conflicts with {0}").format(comma_and(existing)), OverlapError)
def before_cancel(self):
self.set_status()
def before_update_after_submit(self):
self.set_status()
@frappe.whitelist()
def get_events(start, end):
from frappe.widgets.reportview import build_match_conditions
@ -67,7 +66,7 @@ def get_events(start, end):
frappe.msgprint(_("No Permission"), raise_exception=1)
match = build_match_conditions("Time Log")
data = frappe.db.sql("""select name, from_time, to_time,
data = frappe.db.sql("""select name, from_time, to_time,
activity_type, task, project from `tabTime Log`
where from_time between '%(start)s' and '%(end)s' or to_time between '%(start)s' and '%(end)s'
%(match)s""" % {
@ -75,12 +74,12 @@ def get_events(start, end):
"end": end,
"match": match and (" and " + match) or ""
}, as_dict=True, update={"allDay": 0})
for d in data:
d.title = d.name + ": " + (d.activity_type or "[Activity Type not set]")
if d.task:
d.title += " for Task: " + d.task
if d.project:
d.title += " for Project: " + d.project
return data

View File

@ -29,8 +29,7 @@ class TimeLogBatch(Document):
def validate_time_log_is_submitted(self, tl):
if tl.status != "Submitted" and self.docstatus == 0:
frappe.msgprint(_("Time Log must have status 'Submitted'") + \
" :" + tl.name + " (" + _(tl.status) + ")", raise_exception=True)
frappe.throw(_("Time Log {0} must be 'Submitted'").format(tl.name))
def set_status(self):
self.status = {

View File

@ -6,7 +6,7 @@ import frappe
from frappe.utils import cstr, getdate
from frappe import msgprint
from frappe import _
from erpnext.stock.utils import get_valid_serial_nos
from erpnext.utilities.transaction_base import TransactionBase
@ -46,15 +46,14 @@ class InstallationNote(TransactionBase):
def is_serial_no_added(self, item_code, serial_no):
ar_required = frappe.db.get_value("Item", item_code, "has_serial_no")
if ar_required == 'Yes' and not serial_no:
msgprint("Serial No is mandatory for item: " + item_code, raise_exception=1)
frappe.throw(_("Serial No is mandatory for Item {0}").format(item_code))
elif ar_required != 'Yes' and cstr(serial_no).strip():
msgprint("If serial no required, please select 'Yes' in 'Has Serial No' in Item :" +
item_code, raise_exception=1)
frappe.throw(_("Item {0} is not a serialized Item").format(item_code))
def is_serial_no_exist(self, item_code, serial_no):
for x in serial_no:
if not frappe.db.exists("Serial No", x):
msgprint("Serial No " + x + " does not exist in the system", raise_exception=1)
frappe.throw(_("Serial No {0} does not exist").format(x))
def is_serial_no_installed(self,cur_s_no,item_code):
for x in cur_s_no:
@ -62,8 +61,7 @@ class InstallationNote(TransactionBase):
status = status and status[0][0] or ''
if status == 'Installed':
msgprint("Item "+item_code+" with serial no. " + x + " already installed",
raise_exception=1)
frappe.throw(_("Item {0} with Serial No {1} is already installed").format(item_code, x))
def get_prevdoc_serial_no(self, prevdoc_detail_docname):
serial_nos = frappe.db.get_value("Delivery Note Item",
@ -73,8 +71,7 @@ class InstallationNote(TransactionBase):
def is_serial_no_match(self, cur_s_no, prevdoc_s_no, prevdoc_docname):
for sr in cur_s_no:
if sr not in prevdoc_s_no:
msgprint("Serial No. " + sr + " is not matching with the Delivery Note " +
prevdoc_docname, raise_exception = 1)
frappe.throw(_("Serial No {0} does not belong to Delivery Note {1}").format(sr, prevdoc_docname))
def validate_serial_no(self):
cur_s_no, prevdoc_s_no, sr_list = [], [], []
@ -95,12 +92,11 @@ class InstallationNote(TransactionBase):
if d.prevdoc_docname:
d_date = frappe.db.get_value("Delivery Note", d.prevdoc_docname, "posting_date")
if d_date > getdate(self.inst_date):
msgprint("Installation Date can not be before Delivery Date " + cstr(d_date) +
" for item "+d.item_code, raise_exception=1)
frappe.throw(_("Installation date cannot be before delivery date for Item {0}").format(d.item_code))
def check_item_table(self):
if not(self.get('installed_item_details')):
msgprint("Please fetch items from Delivery Note selected", raise_exception=1)
frappe.throw(_("Please pull items from Delivery Note"))
def on_update(self):
frappe.db.set(self, 'status', 'Draft')

View File

@ -4,10 +4,10 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr, validate_email_add, cint
from frappe.utils import cstr, validate_email_add, cint, comma_and
from frappe import session
from erpnext.controllers.selling_controller import SellingController
class Lead(SellingController):
@ -15,7 +15,7 @@ class Lead(SellingController):
customer = frappe.db.get_value("Customer", {"lead_name": self.name})
if customer:
self.set("__is_customer", customer)
def validate(self):
self._prev = frappe._dict({
"contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if \
@ -23,20 +23,20 @@ class Lead(SellingController):
"contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if \
(not cint(self.get("__islocal"))) else None,
})
self.set_status()
if self.source == 'Campaign' and not self.campaign_name and session['user'] != 'Guest':
frappe.throw("Please specify campaign name")
if self.email_id:
if not validate_email_add(self.email_id):
frappe.throw('Please enter valid email id.')
def on_update(self):
self.check_email_id_is_unique()
self.add_calendar_event()
def add_calendar_event(self, opts=None, force=False):
super(Lead, self).add_calendar_event({
"owner": self.lead_owner,
@ -48,22 +48,21 @@ class Lead(SellingController):
def check_email_id_is_unique(self):
if self.email_id:
# 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.email_id)
if len(email_list) > 1:
items = [e[0] for e in email_list if e[0]!=self.name]
frappe.msgprint(_("""Email Id must be unique, already exists for: """) + \
", ".join(items), raise_exception=True)
frappe.throw(_("Email id must be unique, already exists for {0}").format(comma_and(items)))
def on_trash(self):
frappe.db.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
self.name)
self.delete_events()
def has_customer(self):
return frappe.db.get_value("Customer", {"lead_name": self.name})
def has_opportunity(self):
return frappe.db.get_value("Opportunity", {"lead": self.name, "docstatus": 1,
"status": ["!=", "Lost"]})
@ -74,7 +73,7 @@ def make_customer(source_name, target_doc=None):
def _make_customer(source_name, target_doc=None, ignore_permissions=False):
from frappe.model.mapper import get_mapped_doc
def set_missing_values(source, target):
if source.company_name:
target.customer_type = "Company"
@ -82,10 +81,10 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False):
else:
target.customer_type = "Individual"
target.customer_name = source.lead_name
target.customer_group = frappe.db.get_default("customer_group")
doclist = get_mapped_doc("Lead", source_name,
doclist = get_mapped_doc("Lead", source_name,
{"Lead": {
"doctype": "Customer",
"field_map": {
@ -95,14 +94,14 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False):
"fax": "fax_1"
}
}}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
return doclist
@frappe.whitelist()
def make_opportunity(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
doclist = get_mapped_doc("Lead", source_name,
doclist = get_mapped_doc("Lead", source_name,
{"Lead": {
"doctype": "Opportunity",
"field_map": {
@ -115,19 +114,19 @@ def make_opportunity(source_name, target_doc=None):
"mobile_no": "contact_mobile"
}
}}, target_doc)
return doclist
@frappe.whitelist()
def get_lead_details(lead):
if not lead: return {}
from erpnext.accounts.party import set_address_details
out = frappe._dict()
lead_doc = frappe.get_doc("Lead", lead)
lead = lead_doc
out.update({
"territory": lead.territory,
"customer_name": lead.company_name or lead.lead_name,
@ -136,7 +135,7 @@ def get_lead_details(lead):
"contact_mobile": lead.mobile_no,
"contact_phone": lead.phone,
})
set_address_details(out, lead, "Lead")
return out
return out

View File

@ -8,13 +8,13 @@ from frappe.utils import cstr, cint
from frappe import msgprint, _
from erpnext.utilities.transaction_base import TransactionBase
class Opportunity(TransactionBase):
fname = 'enq_details'
tname = 'Opportunity Item'
def get_item_details(self, item_code):
item = frappe.db.sql("""select item_name, stock_uom, description_html, description, item_group, brand
from `tabItem` where name = %s""", item_code, as_dict=1)
@ -28,7 +28,7 @@ class Opportunity(TransactionBase):
return ret
def get_cust_address(self,name):
details = frappe.db.sql("""select customer_name, address, territory, customer_group
details = frappe.db.sql("""select customer_name, address, territory, customer_group
from `tabCustomer` where name = %s and docstatus != 2""", (name), as_dict = 1)
if details:
ret = {
@ -39,28 +39,28 @@ class Opportunity(TransactionBase):
}
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
contact_det = frappe.db.sql("""select contact_name, contact_no, email_id
from `tabContact` where customer = %s and is_customer = 1
contact_det = frappe.db.sql("""select contact_name, contact_no, email_id
from `tabContact` where customer = %s and is_customer = 1
and is_primary_contact = 'Yes' and docstatus != 2""", name, as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
ret['email_id'] = contact_det and contact_det[0]['email_id'] or ''
return ret
else:
msgprint("Customer : %s does not exist in system." % (name))
raise Exception
def on_update(self):
self.add_calendar_event()
def add_calendar_event(self, opts=None, force=False):
if not opts:
opts = frappe._dict()
opts.description = ""
if self.customer:
if self.contact_person:
opts.description = 'Contact '+cstr(self.contact_person)
@ -71,23 +71,22 @@ class Opportunity(TransactionBase):
opts.description = 'Contact '+cstr(self.contact_display)
else:
opts.description = 'Contact lead '+cstr(self.lead)
opts.subject = opts.description
opts.description += '. By : ' + cstr(self.contact_by)
if self.to_discuss:
opts.description += ' To Discuss : ' + cstr(self.to_discuss)
super(Opportunity, self).add_calendar_event(opts, force)
def validate_item_details(self):
if not self.get('enquiry_details'):
msgprint("Please select items for which enquiry needs to be made")
raise Exception
frappe.throw(_("Items required"))
def validate_lead_cust(self):
if self.enquiry_from == 'Lead' and not self.lead:
msgprint("Lead Id is mandatory if 'Opportunity From' is selected as Lead", raise_exception=1)
frappe.throw(_("Lead must be set if Opportunity is made from Lead"))
elif self.enquiry_from == 'Customer' and not self.customer:
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
@ -98,24 +97,24 @@ class Opportunity(TransactionBase):
"contact_by": frappe.db.get_value("Opportunity", self.name, "contact_by") if \
(not cint(self.get("__islocal"))) else None,
})
self.set_status()
self.validate_item_details()
self.validate_uom_is_integer("uom", "qty")
self.validate_lead_cust()
from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.transaction_date, self.fiscal_year, "Opportunity Date")
def on_submit(self):
if self.lead:
frappe.get_doc("Lead", self.lead).set_status(update=True)
def on_cancel(self):
if self.has_quotation():
frappe.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
self.set_status(update=True)
def declare_enquiry_lost(self,arg):
if not self.has_quotation():
frappe.db.set(self, 'status', 'Lost')
@ -125,40 +124,40 @@ class Opportunity(TransactionBase):
def on_trash(self):
self.delete_events()
def has_quotation(self):
return frappe.db.get_value("Quotation Item", {"prevdoc_docname": self.name, "docstatus": 1})
@frappe.whitelist()
def make_quotation(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
def set_missing_values(source, target):
quotation = frappe.get_doc(target)
quotation.run_method("onload_post_render")
quotation.run_method("calculate_taxes_and_totals")
doclist = get_mapped_doc("Opportunity", source_name, {
"Opportunity": {
"doctype": "Quotation",
"doctype": "Quotation",
"field_map": {
"enquiry_from": "quotation_to",
"enquiry_type": "order_type",
"name": "enq_no",
"enquiry_from": "quotation_to",
"enquiry_type": "order_type",
"name": "enq_no",
},
"validation": {
"docstatus": ["=", 1]
}
},
},
"Opportunity Item": {
"doctype": "Quotation Item",
"doctype": "Quotation Item",
"field_map": {
"parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype",
"parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype",
"uom": "stock_uom"
},
"add_if_empty": True
}
}, target_doc, set_missing_values)
return doclist
return doclist

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import cstr
from frappe import _, msgprint
from frappe import _
from erpnext.controllers.selling_controller import SellingController
@ -20,31 +20,28 @@ class Quotation(SellingController):
chk_dupl_itm = []
for d in self.get('quotation_details'):
if [cstr(d.item_code),cstr(d.description)] in chk_dupl_itm:
msgprint("Item %s has been entered twice. Please change description atleast to continue" % d.item_code)
raise Exception
frappe.throw(_("Item {0} with same description entered twice").format(d.item_code))
else:
chk_dupl_itm.append([cstr(d.item_code),cstr(d.description)])
def validate_order_type(self):
super(Quotation, self).validate_order_type()
if self.order_type in ['Maintenance', 'Service']:
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 = is_service_item and is_service_item[0][0] or 'No'
if is_service_item == 'No':
msgprint("You can not select non service item "+d.item_code+" in Maintenance Quotation")
raise Exception
frappe.throw(_("Item {0} must be Service Item").format(d.item_code))
else:
for d in self.get('quotation_details'):
is_sales_item = frappe.db.sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
is_sales_item = is_sales_item and is_sales_item[0][0] or 'No'
if is_sales_item == 'No':
msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation")
raise Exception
frappe.throw(_("Item {0} must be Sales Item").format(d.item_code))
def validate(self):
super(Quotation, self).validate()
self.set_status()
@ -56,7 +53,7 @@ class Quotation(SellingController):
for opportunity in list(set([d.prevdoc_docname for d in self.get("quotation_details")])):
if opportunity:
frappe.get_doc("Opportunity", opportunity).set_status(update=True)
def declare_order_lost(self, arg):
if not self.has_sales_order():
frappe.db.set(self, 'status', 'Lost')
@ -64,26 +61,25 @@ class Quotation(SellingController):
self.update_opportunity()
else:
frappe.throw(_("Cannot set as Lost as Sales Order is made."))
def check_item_table(self):
if not self.get('quotation_details'):
msgprint("Please enter item details")
raise Exception
frappe.throw(_("Please enter item details"))
def on_submit(self):
self.check_item_table()
# Check for Approving Authority
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.grand_total, self)
#update enquiry status
self.update_opportunity()
def on_cancel(self):
#update enquiry status
self.set_status()
self.update_opportunity()
def print_other_charges(self,docname):
print_lst = []
for d in self.get('other_charges'):
@ -92,51 +88,51 @@ class Quotation(SellingController):
lst1.append(d.total)
print_lst.append(lst1)
return print_lst
@frappe.whitelist()
def make_sales_order(source_name, target_doc=None):
return _make_sales_order(source_name, target_doc)
def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
from frappe.model.mapper import get_mapped_doc
customer = _make_customer(source_name, ignore_permissions)
def set_missing_values(source, target):
if customer:
target.customer = customer.name
target.customer_name = customer.customer_name
si = frappe.get_doc(target)
si.ignore_permissions = ignore_permissions
si.run_method("onload_post_render")
doclist = get_mapped_doc("Quotation", source_name, {
"Quotation": {
"doctype": "Sales Order",
"doctype": "Sales Order",
"validation": {
"docstatus": ["=", 1]
}
},
},
"Quotation Item": {
"doctype": "Sales Order Item",
"doctype": "Sales Order Item",
"field_map": {
"parent": "prevdoc_docname"
}
},
},
"Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges",
"add_if_empty": True
},
},
"Sales Team": {
"doctype": "Sales Team",
"add_if_empty": True
}
}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
# postprocess: fetch shipping address, set missing values
return doclist
def _make_customer(source_name, ignore_permissions=False):
@ -152,7 +148,7 @@ def _make_customer(source_name, ignore_permissions=False):
if quotation[1] == "Shopping Cart":
customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None,
"default_customer_group")
try:
customer.insert()
return customer

View File

@ -4,6 +4,8 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
class SalesBOM(Document):
@ -11,7 +13,7 @@ class SalesBOM(Document):
def autoname(self):
self.name = self.new_item_code
def validate(self):
self.validate_main_item()
@ -22,23 +24,22 @@ class SalesBOM(Document):
"""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
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""",
raise_exception=1)
frappe.throw(_("Parent Item {0} must be not Stock Item and must be a Sales Item").format(self.new_item_code))
def get_item_details(self, name):
det = frappe.db.sql("""select description, stock_uom from `tabItem`
det = frappe.db.sql("""select description, stock_uom from `tabItem`
where name = %s""", name)
return {
'description' : det and det[0][0] or '',
'description' : det and det[0][0] or '',
'uom': det and det[0][1] or ''
}
def get_new_item_code(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
return frappe.db.sql("""select name, item_name, description from tabItem
return frappe.db.sql("""select name, item_name, description from tabItem
where is_stock_item="No" and is_sales_item="Yes"
and name not in (select name from `tabSales BOM`) and %s like %s
%s limit %s, %s""" % (searchfield, "%s",
get_match_cond(doctype),"%s", "%s"),
("%%%s%%" % txt, start, page_len))
%s limit %s, %s""" % (searchfield, "%s",
get_match_cond(doctype),"%s", "%s"),
("%%%s%%" % txt, start, page_len))

View File

@ -5,9 +5,9 @@ from __future__ import unicode_literals
import frappe
import frappe.utils
from frappe.utils import cstr, flt, getdate
from frappe.utils import cstr, flt, getdate, comma_and
from frappe import msgprint
from frappe import _
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.selling_controller import SellingController
@ -23,22 +23,19 @@ class SalesOrder(SellingController):
# validate transaction date v/s delivery date
if self.delivery_date:
if getdate(self.transaction_date) > getdate(self.delivery_date):
msgprint("Expected Delivery Date cannot be before Sales Order Date")
raise Exception
frappe.throw(_("Expected Delivery Date cannot be before Sales Order Date"))
def validate_po(self):
# validate p.o date v/s 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")
raise Exception
frappe.throw(_("Expected Delivery Date cannot be before Purchase Order Date"))
if self.po_no and self.customer:
so = frappe.db.sql("select name from `tabSales Order` \
where ifnull(po_no, '') = %s and name != %s and docstatus < 2\
and customer = %s", (self.po_no, self.name, self.customer))
if so and so[0][0]:
msgprint("""Another Sales Order (%s) exists against same PO No and Customer.
Please be sure, you are not making duplicate entry.""" % so[0][0])
frappe.msgprint(_("Warning: Sales Order {0} already exists against same Purchase Order number").format(so[0][0]))
def validate_for_items(self):
check_list, flag = [], 0
@ -49,16 +46,15 @@ class SalesOrder(SellingController):
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes':
if not d.warehouse:
msgprint("""Please enter Reserved Warehouse for item %s
as it is stock Item""" % d.item_code, raise_exception=1)
frappe.throw(_("Reserved warehouse required for stock item {0}").format(d.item_code))
if e in check_list:
msgprint("Item %s has been entered twice." % d.item_code)
frappe.throw(_("Item {0} has been entered twice").format(d.item_code))
else:
check_list.append(e)
else:
if f in chk_dupl_itm:
msgprint("Item %s has been entered twice." % d.item_code)
frappe.throw(_("Item {0} has been entered twice").format(d.item_code))
else:
chk_dupl_itm.append(f)
@ -74,16 +70,14 @@ class SalesOrder(SellingController):
if d.prevdoc_docname:
res = frappe.db.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.order_type))
if not res:
msgprint("""Order Type (%s) should be same in Quotation: %s \
and current Sales Order""" % (self.order_type, d.prevdoc_docname))
frappe.msgprint(_("Quotation {0} not of type {1}").format(d.prevdoc_docname, self.order_type))
def validate_order_type(self):
super(SalesOrder, self).validate_order_type()
def validate_delivery_date(self):
if self.order_type == 'Sales' and not self.delivery_date:
msgprint("Please enter 'Expected Delivery Date'")
raise Exception
frappe.throw(_("Please enter 'Expected Delivery Date'"))
self.validate_sales_mntc_quotation()
@ -93,8 +87,7 @@ class SalesOrder(SellingController):
and (customer = %s or ifnull(customer,'')='')""",
(self.project_name, self.customer))
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.customer,self.project_name,self.project_name))
raise Exception
frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project_name))
def validate(self):
super(SalesOrder, self).validate()
@ -169,8 +162,8 @@ class SalesOrder(SellingController):
def on_cancel(self):
# Cannot cancel stopped SO
if self.status == 'Stopped':
msgprint("Sales Order : '%s' cannot be cancelled as it is Stopped. Unstop it for any further transactions" %(self.name))
raise Exception
frappe.throw(_("Stopped order cannot be cancelled. Unstop to cancel."))
self.check_nextdoc_docstatus()
self.update_stock_ledger(update_stock = -1)
@ -180,55 +173,56 @@ class SalesOrder(SellingController):
def check_nextdoc_docstatus(self):
# 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.name)
submit_dn = frappe.db.sql_list("""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:
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)
frappe.throw(_("Delivery Notes {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_dn)))
# Checks Sales Invoice
submit_rv = frappe.db.sql("""select t1.name
submit_rv = frappe.db.sql_list("""select t1.name
from `tabSales Invoice` t1,`tabSales Invoice Item` t2
where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus = 1""",
self.name)
if submit_rv:
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)
frappe.throw(_("Sales Invoice {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_rv)))
#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.name)
submit_ms = frappe.db.sql_list("""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:
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)
frappe.throw(_("Maintenance Schedule {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_ms)))
# 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.name)
submit_mv = frappe.db.sql_list("""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:
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)
frappe.throw(_("Maintenance Visit {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_mv)))
# check production order
pro_order = frappe.db.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.name)
pro_order = frappe.db.sql_list("""select name from `tabProduction Order`
where sales_order = %s and docstatus = 1""", self.name)
if pro_order:
msgprint("""Production Order: %s exists against this sales order.
Please cancel production order first and then cancel this sales order""" %
pro_order[0][0], raise_exception=1)
frappe.throw(_("Production Order {0} must be cancelled before cancelling this Sales Order").format(comma_and(pro_order)))
def check_modified_date(self):
mod_db = frappe.db.get_value("Sales Order", self.name, "modified")
date_diff = frappe.db.sql("select TIMEDIFF('%s', '%s')" %
( mod_db, cstr(self.modified)))
if date_diff and date_diff[0][0]:
msgprint("%s: %s has been modified after you have opened. Please Refresh"
% (self.doctype, self.name), raise_exception=1)
frappe.throw(_("{0} {1} has been modified. Please Refresh").format(self.doctype, self.name))
def stop_sales_order(self):
self.check_modified_date()
self.update_stock_ledger(-1)
frappe.db.set(self, 'status', 'Stopped')
msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order
you need to Unstop it.""" % (self.doctype, self.name))
frappe.msgprint(_("{0} {1} status is Stopped").format(self.doctype, self.name))
def unstop_sales_order(self):
self.check_modified_date()
self.update_stock_ledger(1)
frappe.db.set(self, 'status', 'Submitted')
msgprint("%s: %s has been Unstopped" % (self.doctype, self.name))
frappe.msgprint(_("{0} {1} status is Unstopped").format(self.doctype, self.name))
def update_stock_ledger(self, update_stock):

View File

@ -4,15 +4,16 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint
from frappe import _
def execute(filters=None):
if not filters: filters ={}
days_since_last_order = filters.get("days_since_last_order")
if cint(days_since_last_order) <= 0:
frappe.msgprint("Please mention positive value in 'Days Since Last Order' field",raise_exception=1)
frappe.throw(_("'Days Since Last Order' must be greater than or equal to zero"))
columns = get_columns()
columns = get_columns()
customers = get_so_details()
data = []
@ -20,43 +21,43 @@ def execute(filters=None):
if cint(cust[8]) >= cint(days_since_last_order):
cust.insert(7,get_last_so_amt(cust[0]))
data.append(cust)
return columns, data
return columns, data
def get_so_details():
return frappe.db.sql("""select
cust.name,
cust.customer_name,
cust.territory,
cust.customer_group,
count(distinct(so.name)) as 'num_of_order',
return frappe.db.sql("""select
cust.name,
cust.customer_name,
cust.territory,
cust.customer_group,
count(distinct(so.name)) as 'num_of_order',
sum(net_total) as 'total_order_value',
sum(if(so.status = "Stopped",
so.net_total * so.per_delivered/100,
sum(if(so.status = "Stopped",
so.net_total * so.per_delivered/100,
so.net_total)) as 'total_order_considered',
max(so.transaction_date) as 'last_sales_order_date',
DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order'
from `tabCustomer` cust, `tabSales Order` so
max(so.transaction_date) as 'last_sales_order_date',
DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order'
from `tabCustomer` cust, `tabSales Order` so
where cust.name = so.customer and so.docstatus = 1
group by cust.name
order by 'days_since_last_order' desc """,as_list=1)
def get_last_so_amt(customer):
res = frappe.db.sql("""select net_total from `tabSales Order`
where customer ='%(customer)s' and docstatus = 1 order by transaction_date desc
where customer ='%(customer)s' and docstatus = 1 order by transaction_date desc
limit 1""" % {'customer':customer})
return res and res[0][0] or 0
def get_columns():
return [
"Customer:Link/Customer:120",
"Customer Name:Data:120",
"Territory::120",
"Customer:Link/Customer:120",
"Customer Name:Data:120",
"Territory::120",
"Customer Group::120",
"Number of Order::120",
"Total Order Value:Currency:120",
"Total Order Considered:Currency:160",
"Number of Order::120",
"Total Order Value:Currency:120",
"Total Order Considered:Currency:160",
"Last Order Amount:Currency:160",
"Last Sales Order Date:Date:160",
"Last Sales Order Date:Date:160",
"Days Since Last Order::160"
]
]

View File

@ -5,14 +5,12 @@ from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe.utils import flt
import time
from erpnext.accounts.utils import get_fiscal_year
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
from frappe.model.meta import get_field_precision
def execute(filters=None):
if not filters: filters = {}
columns = get_columns(filters)
period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"])
sim_map = get_salesperson_item_month_map(filters)
@ -37,7 +35,7 @@ def execute(filters=None):
data.append(row)
return columns, sorted(data, key=lambda x: (x[0], x[1]))
def get_columns(filters):
for fieldname in ["fiscal_year", "period", "target_on"]:
if not filters.get(fieldname):
@ -55,26 +53,26 @@ def get_columns(filters):
label = label % (from_date.strftime("%b") + " - " + to_date.strftime("%b"))
else:
label = label % from_date.strftime("%b")
columns.append(label+":Float:120")
return columns + ["Total Target:Float:120", "Total Achieved:Float:120",
return columns + ["Total Target:Float:120", "Total Achieved:Float:120",
"Total Variance:Float:120"]
#Get sales person & item group details
def get_salesperson_details(filters):
return frappe.db.sql("""select sp.name, td.item_group, td.target_qty,
td.target_amount, sp.distribution_id
from `tabSales Person` sp, `tabTarget Detail` td
where td.parent=sp.name and td.fiscal_year=%s order by sp.name""",
return frappe.db.sql("""select sp.name, td.item_group, td.target_qty,
td.target_amount, sp.distribution_id
from `tabSales Person` sp, `tabTarget Detail` td
where td.parent=sp.name and td.fiscal_year=%s order by sp.name""",
(filters["fiscal_year"]), as_dict=1)
#Get target distribution details of item group
def get_target_distribution_details(filters):
target_details = {}
for d in frappe.db.sql("""select bd.name, bdd.month, bdd.percentage_allocation
from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd
for d in frappe.db.sql("""select bd.name, bdd.month, bdd.percentage_allocation
from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd
where bdd.parent=bd.name and bd.fiscal_year=%s""", (filters["fiscal_year"]), as_dict=1):
target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
@ -83,13 +81,13 @@ def get_target_distribution_details(filters):
#Get achieved details from sales order
def get_achieved_details(filters):
start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:]
item_details = frappe.db.sql("""select soi.item_code, soi.qty, soi.base_amount, so.transaction_date,
st.sales_person, MONTHNAME(so.transaction_date) as month_name
from `tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st
where soi.parent=so.name and so.docstatus=1 and
st.parent=so.name and so.transaction_date>=%s and
so.transaction_date<=%s""" % ('%s', '%s'),
item_details = frappe.db.sql("""select soi.item_code, soi.qty, soi.base_amount, so.transaction_date,
st.sales_person, MONTHNAME(so.transaction_date) as month_name
from `tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st
where soi.parent=so.name and so.docstatus=1 and
st.parent=so.name and so.transaction_date>=%s and
so.transaction_date<=%s""" % ('%s', '%s'),
(start_date, end_date), as_dict=1)
item_actual_details = {}
@ -117,7 +115,7 @@ def get_salesperson_item_month_map(filters):
tav_dict = sim_map[sd.name][sd.item_group][month]
month_percentage = tdd.get(sd.distribution_id, {}).get(month, 0) \
if sd.distribution_id else 100.0/12
for ad in achieved_details.get(sd.name, {}).get(sd.item_group, []):
if (filters["target_on"] == "Quantity"):
tav_dict.target = flt(sd.target_qty) * month_percentage / 100
@ -132,4 +130,4 @@ def get_salesperson_item_month_map(filters):
return sim_map
def get_item_group(item_name):
return frappe.db.get_value("Item", item_name, "item_group")
return frappe.db.get_value("Item", item_name, "item_group")

View File

@ -4,12 +4,11 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt, has_common, make_esc
from frappe.utils import cstr, flt, has_common, make_esc, comma_or
from frappe import session, _
from frappe import session, msgprint
from erpnext.setup.utils import get_company_currency
from erpnext.utilities.transaction_base import TransactionBase
class AuthorizationControl(TransactionBase):
@ -24,27 +23,18 @@ class AuthorizationControl(TransactionBase):
for x in det:
amt_list.append(flt(x[0]))
max_amount = max(amt_list)
app_dtl = frappe.db.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company))
if not app_dtl:
app_dtl = frappe.db.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on))
app_dtl = frappe.db.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on))
for d in app_dtl:
if(d[0]): appr_users.append(d[0])
if(d[1]): appr_roles.append(d[1])
if not has_common(appr_roles, frappe.user.get_roles()) and not has_common(appr_users, [session['user']]):
msg, add_msg = '',''
if max_amount:
dcc = get_company_currency(self.company)
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 == 'Average Discount' or based_on == 'Customerwise Discount': msg = "since Discount exceeds %s" % (cstr(max_amount)+'%')
if appr_users: add_msg = "Users : "+cstr(appr_users)
if appr_roles: add_msg = "Roles : "+cstr(appr_roles)
if appr_users and appr_roles: add_msg = "Users : "+cstr(appr_users)+" or "+"Roles : "+cstr(appr_roles)
msgprint("You are not authorize to submit this %s %s. Please send for approval to %s" % (doctype_name, msg, add_msg))
frappe.msgprint(_("Not authroized since {0} exceeds limits").format(_(based_on)))
frappe.throw(_("Can be approved by {0}").format(comma_or(appr_roles + appr_users)))
raise Exception
@ -64,12 +54,12 @@ class AuthorizationControl(TransactionBase):
if chk == 1:
if based_on == 'Itemwise Discount': add_cond2 += " and ifnull(master_name,'') = ''"
appr = frappe.db.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company))
if not appr:
appr = frappe.db.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on))
self.get_appr_user_role(appr, doctype_name, total, based_on, cond+add_cond2, item, company)
# Bifurcate Authorization based on type
# --------------------------------------
def bifurcate_based_on_type(self, doctype_name, total, av_dis, based_on, doc_obj, val, company):
@ -108,39 +98,39 @@ class AuthorizationControl(TransactionBase):
# Individual User
# ================
# Check for authorization set for individual user
based_on = [x[0] for x in frappe.db.sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))]
for d in based_on:
self.bifurcate_based_on_type(doctype_name, total, av_dis, d, doc_obj, 1, company)
# Remove user specific rules from global authorization rules
for r in based_on:
if r in final_based_on and r != 'Itemwise Discount': final_based_on.remove(r)
# Specific Role
# ===============
# Check for authorization set on particular roles
based_on = [x[0] for x in frappe.db.sql("""select based_on
from `tabAuthorization Rule`
where transaction = %s and system_role IN (%s) and based_on IN (%s)
and (company = %s or ifnull(company,'')='')
based_on = [x[0] for x in frappe.db.sql("""select based_on
from `tabAuthorization Rule`
where transaction = %s and system_role IN (%s) and based_on IN (%s)
and (company = %s or ifnull(company,'')='')
and docstatus != 2
""" % ('%s', "'"+"','".join(frappe.user.get_roles())+"'", "'"+"','".join(final_based_on)+"'", '%s'), (doctype_name, company))]
for d in based_on:
self.bifurcate_based_on_type(doctype_name, total, av_dis, d, doc_obj, 2, company)
# Remove role specific rules from global authorization rules
for r in based_on:
if r in final_based_on and r != 'Itemwise Discount': final_based_on.remove(r)
# Global Rule
# =============
# Check for global authorization
for g in final_based_on:
self.bifurcate_based_on_type(doctype_name, total, av_dis, g, doc_obj, 0, company)
#========================================================================================================================
# payroll related check
def get_value_based_rule(self,doctype_name,employee,total_claimed_amount,company):
@ -153,29 +143,29 @@ class AuthorizationControl(TransactionBase):
val_lst = [y[0] for y in val]
else:
val_lst.append(0)
max_val = max(val_lst)
rule = frappe.db.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1)
if not rule:
rule = frappe.db.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1)
return rule
#---------------------------------------------------------------------------------------------------------------------
# related to payroll module only
def get_approver_name(self, doctype_name, total, doc_obj=''):
app_user=[]
app_specific_user =[]
rule ={}
if doc_obj:
if doctype_name == 'Expense Claim':
rule = self.get_value_based_rule(doctype_name,doc_obj.employee,doc_obj.total_claimed_amount, doc_obj.company)
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.employee, doc_obj.employee, doc_obj.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:
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)
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:
for m in rule:
if m['to_emp'] or m['to_designation']:
@ -186,7 +176,7 @@ class AuthorizationControl(TransactionBase):
for x in user_lst:
if not x in app_user:
app_user.append(x)
if len(app_specific_user) >0:
return app_specific_user
else:

View File

@ -4,8 +4,8 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt, has_common
from frappe import msgprint
from frappe.utils import cstr, flt
from frappe import _, msgprint
from frappe.model.document import Document
@ -13,75 +13,41 @@ class AuthorizationRule(Document):
def check_duplicate_entry(self):
exists = frappe.db.sql("""select name, docstatus from `tabAuthorization Rule`
where transaction = %s and based_on = %s and system_user = %s
and system_role = %s and approving_user = %s and approving_role = %s
and to_emp =%s and to_designation=%s and name != %s""",
(self.transaction, self.based_on, cstr(self.system_user),
cstr(self.system_role), cstr(self.approving_user),
cstr(self.approving_role), cstr(self.to_emp),
exists = frappe.db.sql("""select name, docstatus from `tabAuthorization Rule`
where transaction = %s and based_on = %s and system_user = %s
and system_role = %s and approving_user = %s and approving_role = %s
and to_emp =%s and to_designation=%s and name != %s""",
(self.transaction, self.based_on, cstr(self.system_user),
cstr(self.system_role), cstr(self.approving_user),
cstr(self.approving_role), cstr(self.to_emp),
cstr(self.to_designation), self.name))
auth_exists = exists and exists[0][0] or ''
if auth_exists:
if cint(exists[0][1]) == 2:
msgprint("""Duplicate Entry. Please untrash Authorization Rule : %s \
from Recycle Bin""" % (auth_exists), raise_exception=1)
else:
msgprint("Duplicate Entry. Please check Authorization Rule : %s" %
(auth_exists), raise_exception=1)
def validate_master_name(self):
if self.based_on == 'Customerwise Discount' and \
not frappe.db.sql("""select name from tabCustomer
where name = %s and docstatus != 2""", (self.master_name)):
msgprint("Please select valid Customer Name for Customerwise Discount",
raise_exception=1)
elif self.based_on == 'Itemwise Discount' and \
not frappe.db.sql("select name from tabItem where name = %s and docstatus != 2",
(self.master_name)):
msgprint("Please select valid Item Name for Itemwise Discount", raise_exception=1)
elif (self.based_on == 'Grand Total' or \
self.based_on == 'Average Discount') and self.master_name:
msgprint("Please remove Customer/Item Name for %s." %
self.based_on, raise_exception=1)
frappe.throw(_("Duplicate Entry. Please check Authorization Rule {0}").format(auth_exists))
def validate_rule(self):
if self.transaction != 'Appraisal':
if not self.approving_role and not self.approving_user:
msgprint("Please enter Approving Role or Approving User", raise_exception=1)
frappe.throw(_("Please enter Approving Role or 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)",
raise_exception=1)
frappe.throw(_("Approving User cannot be same as user the rule is Applicable To"))
elif self.system_role and self.system_role == self.approving_role:
msgprint("Approving Role cannot be same as user the rule is \
Applicable To (Role).", raise_exception=1)
elif self.system_user and self.approving_role and \
has_common([self.approving_role], [x[0] for x in \
frappe.db.sql("select role from `tabUserRole` where parent = %s", \
(self.system_user))]):
msgprint("System User : %s is assigned role : %s. So rule does not make sense" %
(self.system_user,self.approving_role), raise_exception=1)
frappe.throw(_("Approving Role cannot be same as role the rule is Applicable To"))
elif self.transaction in ['Purchase Order', 'Purchase Receipt', \
'Purchase Invoice', 'Stock Entry'] and self.based_on \
in ['Average Discount', 'Customerwise Discount', 'Itemwise Discount']:
msgprint("You cannot set authorization on basis of Discount for %s" %
self.transaction, raise_exception=1)
frappe.throw(_("Cannot set authorization on basis of Discount for {0}").format(self.transaction))
elif self.based_on == 'Average Discount' and flt(self.value) > 100.00:
msgprint("Discount cannot given for more than 100%", raise_exception=1)
frappe.throw(_("Discount must be less than 100"))
elif self.based_on == 'Customerwise Discount' and not self.master_name:
msgprint("Please enter Customer Name for 'Customerwise Discount'",
raise_exception=1)
frappe.throw(_("Customer required for 'Customerwise Discount'"))
else:
if self.transaction == 'Appraisal' and self.based_on != 'Not Applicable':
msgprint("Based on should be 'Not Applicable' while setting authorization rule\
for 'Appraisal'", raise_exception=1)
if self.transaction == 'Appraisal':
self.based_on = "Not Applicable"
def validate(self):
self.check_duplicate_entry()
self.validate_rule()
self.validate_master_name()
if not self.value: self.value = 0.0
if not self.value: self.value = 0.0

View File

@ -20,7 +20,7 @@ import mimetypes
import frappe
import oauth2client.client
from frappe.utils import cstr
from frappe import _, msgprint
from frappe import _
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
@ -71,17 +71,17 @@ def backup_to_gdrive():
backup = new_backup()
path = os.path.join(frappe.local.site_path, "public", "backups")
filename = os.path.join(path, os.path.basename(backup.backup_path_db))
# upload files to database folder
upload_files(filename, 'application/x-gzip', drive_service,
upload_files(filename, 'application/x-gzip', drive_service,
frappe.db.get_value("Backup Manager", None, "database_folder_id"))
# upload files to files folder
did_not_upload = []
error_log = []
files_folder_id = frappe.db.get_value("Backup Manager", None, "files_folder_id")
frappe.db.close()
path = os.path.join(frappe.local.site_path, "public", "files")
for filename in os.listdir(path):
@ -94,7 +94,7 @@ def backup_to_gdrive():
mimetype = 'application/x-gzip'
else:
mimetype = mimetypes.types_map.get("." + ext) or "application/octet-stream"
#Compare Local File with Server File
children = drive_service.children().list(folderId=files_folder_id).execute()
for child in children.get('items', []):
@ -108,29 +108,28 @@ def backup_to_gdrive():
except Exception, e:
did_not_upload.append(filename)
error_log.append(cstr(e))
frappe.connect()
return did_not_upload, list(set(error_log))
def get_gdrive_flow():
from oauth2client.client import OAuth2WebServerFlow
from frappe import conf
if not "gdrive_client_id" in conf:
frappe.msgprint(_("Please set Google Drive access keys in") + " conf.py",
raise_exception=True)
flow = OAuth2WebServerFlow(conf.gdrive_client_id, conf.gdrive_client_secret,
if not "gdrive_client_id" in conf:
frappe.throw(_("Please set Google Drive access keys in {0}"),format("site_config.json"))
flow = OAuth2WebServerFlow(conf.gdrive_client_id, conf.gdrive_client_secret,
"https://www.googleapis.com/auth/drive", 'urn:ietf:wg:oauth:2.0:oob')
return flow
@frappe.whitelist()
def gdrive_callback(verification_code = None):
flow = get_gdrive_flow()
if verification_code:
credentials = flow.step2_exchange(verification_code)
allowed = 1
# make folders to save id
http = httplib2.Http()
http = credentials.authorize(http)
@ -145,7 +144,7 @@ def gdrive_callback(verification_code = None):
final_credentials = credentials.to_json()
frappe.db.set_value("Backup Manager", "Backup Manager", "gdrive_credentials", final_credentials)
frappe.msgprint("Updated")
frappe.msgprint(_("Updated"))
def create_erpnext_folder(service):
if not frappe.db:

View File

@ -3,9 +3,9 @@
from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe import _
from frappe.utils import cstr, cint
from frappe.utils import cint
import frappe.defaults
@ -13,10 +13,10 @@ from frappe.model.document import Document
class Company(Document):
def onload(self):
self.set("__transactions_exist", self.check_if_transactions_exist())
def check_if_transactions_exist(self):
exists = False
for doctype in ["Sales Invoice", "Delivery Note", "Sales Order", "Quotation",
@ -25,31 +25,30 @@ class Company(Document):
limit 1""" % (doctype, "%s"), self.name):
exists = True
break
return exists
def validate(self):
if self.get('__islocal') and len(self.abbr) > 5:
frappe.msgprint("Abbreviation cannot have more than 5 characters",
raise_exception=1)
frappe.throw(_("Abbreviation cannot have more than 5 characters"))
self.previous_default_currency = frappe.db.get_value("Company", self.name, "default_currency")
if self.default_currency and self.previous_default_currency and \
self.default_currency != self.previous_default_currency and \
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)
frappe.throw(_("Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency."))
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.name):
self.create_default_accounts()
self.create_default_warehouses()
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.name}):
self.create_default_cost_center()
self.set_default_accounts()
if self.default_currency:
@ -58,7 +57,7 @@ class Company(Document):
def create_default_warehouses(self):
for whname in ("Stores", "Work In Progress", "Finished Goods"):
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"})
if stock_group:
frappe.get_doc({
@ -67,7 +66,7 @@ class Company(Document):
"company": self.name,
"create_account_under": stock_group
}).insert()
def create_default_web_page(self):
if not frappe.db.get_value("Website Settings", None, "home_page") and \
not frappe.db.sql("select name from tabCompany where name!=%s", self.name):
@ -80,7 +79,7 @@ class Company(Document):
"description": "Standard Home Page for " + self.name,
"main_section": webfile.read() % self.as_dict()
}).insert()
# update in home page in settings
website_settings = frappe.get_doc("Website Settings", "Website Settings")
website_settings.home_page = webpage.name
@ -109,7 +108,7 @@ class Company(Document):
self.create_standard_accounts()
frappe.db.set(self, "receivables_group", "Accounts Receivable - " + self.abbr)
frappe.db.set(self, "payables_group", "Accounts Payable - " + self.abbr)
def import_chart_of_account(self):
chart = frappe.get_doc("Chart of Accounts", self.chart_of_accounts)
chart.create_accounts(self.name)
@ -120,7 +119,7 @@ class Company(Document):
"freeze_account": "No",
"master_type": "",
})
for d in self.fld_dict.keys():
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()
@ -128,17 +127,17 @@ class Company(Document):
def set_default_accounts(self):
def _set_default_accounts(accounts):
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.name})
if account and not self.get(field):
frappe.db.set(self, field, account)
_set_default_accounts({
"default_cash_account": "Cash",
"default_bank_account": "Bank"
})
if cint(frappe.db.get_value("Accounts Settings", None, "auto_accounting_for_stock")):
_set_default_accounts({
"stock_received_but_not_billed": "Stock Received But Not Billed",
@ -153,9 +152,9 @@ class Company(Document):
'company':self.name,
'group_or_ledger':'Group',
'parent_cost_center':''
},
},
{
'cost_center_name':'Main',
'cost_center_name':'Main',
'company':self.name,
'group_or_ledger':'Ledger',
'parent_cost_center':self.name + ' - ' + self.abbr
@ -165,11 +164,11 @@ class Company(Document):
cc.update({"doctype": "Cost Center"})
cc_doc = frappe.get_doc(cc)
cc_doc.ignore_permissions = True
if cc.get("cost_center_name") == self.name:
cc_doc.ignore_mandatory = True
cc_doc.insert()
frappe.db.set(self, "cost_center", "Main - " + self.abbr)
def on_trash(self):
@ -180,33 +179,33 @@ class Company(Document):
if not rec:
#delete tabAccount
frappe.db.sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.name)
#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.name)
#delete cost center
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.name}):
frappe.db.sql("""delete from `tabWarehouse` where company=%s""", self.name)
frappe.defaults.clear_default("company", value=self.name)
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.name)
def before_rename(self, olddn, newdn, merge=False):
if merge:
frappe.throw(_("Sorry, companies cannot be merged"))
def after_rename(self, olddn, newdn, merge=False):
frappe.db.set(self, "company_name", newdn)
frappe.db.sql("""update `tabDefaultValue` set defvalue=%s
frappe.db.sql("""update `tabDefaultValue` set defvalue=%s
where defkey='Company' and defvalue=%s""", (newdn, olddn))
frappe.defaults.clear_cache()
def create_standard_accounts(self):
self.fld_dict = {
'account_name': 0,
@ -217,7 +216,7 @@ class Company(Document):
'company': 5,
'tax_rate': 6
}
acc_list_common = [
['Application of Funds (Assets)','','Group','','Balance Sheet',self.name,''],
['Current Assets','Application of Funds (Assets)','Group','','Balance Sheet',self.name,''],
@ -282,7 +281,7 @@ class Company(Document):
['Current Liabilities','Source of Funds (Liabilities)','Group','','Balance Sheet',self.name,''],
['Accounts Payable','Current Liabilities','Group','','Balance Sheet',self.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.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.name,''],
['Loans (Liabilities)','Current Liabilities','Group','','Balance Sheet',self.name,''],
['Secured Loans','Loans (Liabilities)','Group','','Balance Sheet',self.name,''],
@ -291,7 +290,7 @@ class Company(Document):
['Temporary Accounts (Liabilities)','Source of Funds (Liabilities)','Group','','Balance Sheet',self.name,''],
['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','','Balance Sheet',self.name,'']
]
acc_list_india = [
['CENVAT Capital Goods','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
['CENVAT','Tax Assets','Ledger','Chargeable','Balance Sheet',self.name,''],
@ -342,23 +341,23 @@ class Company(Document):
@frappe.whitelist()
def replace_abbr(company, old, new):
frappe.db.set_value("Company", company, "abbr", new)
def _rename_record(dt):
for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company):
parts = d[0].split(" - ")
if parts[-1].lower() == old.lower():
name_without_abbr = " - ".join(parts[:-1])
frappe.rename_doc(dt, d[0], name_without_abbr + " - " + new)
for dt in ["Account", "Cost Center", "Warehouse"]:
_rename_record(dt)
frappe.db.commit()
def get_name_with_abbr(name, company):
company_abbr = frappe.db.get_value("Company", company, "abbr")
company_abbr = frappe.db.get_value("Company", company, "abbr")
parts = name.split(" - ")
if parts[-1].lower() != company_abbr.lower():
parts.append(company_abbr)
return " - ".join(parts)

View File

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

View File

@ -3,45 +3,20 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint
from frappe import _
from frappe.utils.nestedset import NestedSet
class CustomerGroup(NestedSet):
nsm_parent_field = 'parent_customer_group';
def validate(self):
if frappe.db.sql("select name from `tabCustomer Group` where name = %s and docstatus = 2",
(self.customer_group_name)):
msgprint("""Another %s record is trashed.
To untrash please go to Setup -> Recycle Bin.""" %
(self.customer_group_name), raise_exception = 1)
def on_update(self):
self.validate_name_with_customer()
super(CustomerGroup, self).on_update()
self.validate_one_root()
def validate_name_with_customer(self):
if frappe.db.exists("Customer", self.name):
frappe.msgprint("An Customer exists with same name (%s), \
please change the Customer Group name or rename the Customer" %
frappe.msgprint(_("An Customer exists with same name (%s), \
please change the Customer Group name or rename the Customer") %
self.name, raise_exception=1)
def on_trash(self):
cust = frappe.db.sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s",
self.name)
cust = [d[0] for d in cust]
if cust:
msgprint("""Customer Group: %s can not be trashed/deleted \
because it is used in customer: %s.
To trash/delete this, remove/change customer group in customer master""" %
(self.name, cust or ''), raise_exception=1)
if frappe.db.sql("select name from `tabCustomer Group` where parent_customer_group = %s \
and docstatus != 2", self.name):
msgprint("Child customer group exists for this customer group. \
You can not trash/cancel/delete this customer group.", raise_exception=1)
# rebuild tree
super(CustomerGroup, self).on_trash()

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
"""Global Defaults"""
import frappe
from frappe import _
import frappe.defaults
from frappe.utils import cint
@ -25,17 +26,17 @@ keydict = {
from frappe.model.document import Document
class GlobalDefaults(Document):
def on_update(self):
"""update defaults"""
self.validate_session_expiry()
self.set_country_and_timezone()
for key in keydict:
frappe.db.set_default(key, self.get(keydict[key], ''))
# 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.current_fiscal_year)
ysd = year_start_end_date[0][0] or ''
@ -44,20 +45,19 @@ class GlobalDefaults(Document):
if ysd and yed:
frappe.db.set_default('year_start_date', ysd.strftime('%Y-%m-%d'))
frappe.db.set_default('year_end_date', yed.strftime('%Y-%m-%d'))
# enable default currency
if self.default_currency:
frappe.db.set_value("Currency", self.default_currency, "enabled", 1)
# clear cache
frappe.clear_cache()
def validate_session_expiry(self):
if self.session_expiry:
parts = self.session_expiry.split(":")
if len(parts)!=2 or not (cint(parts[0]) or cint(parts[1])):
frappe.msgprint("""Session Expiry must be in format hh:mm""",
raise_exception=1)
frappe.throw(_("Session Expiry must be in format {0}").format("hh:mm"))
def set_country_and_timezone(self):
frappe.db.set_default("country", self.country)

View File

@ -34,5 +34,4 @@ class ItemGroup(NestedSet, WebsiteGenerator):
def validate_name_with_item(self):
if frappe.db.exists("Item", self.name):
frappe.msgprint("An item exists with same name (%s), please change the \
item group name or rename the item" % self.name, raise_exception=1)
frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name))

View File

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

View File

@ -4,8 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint
from frappe import _
from frappe.model.document import Document
@ -18,5 +17,5 @@ class NotificationControl(Document):
def set_message(self, arg = ''):
fn = self.select_transaction.lower().replace(' ', '_') + '_message'
frappe.db.set(self, fn, self.custom_message)
msgprint("Custom Message for %s updated!" % self.select_transaction)
frappe.msgprint(_("Message updated"))

View File

@ -6,17 +6,17 @@ import frappe
from frappe.utils import flt
from frappe import _
from frappe.utils.nestedset import NestedSet
class Territory(NestedSet):
nsm_parent_field = 'parent_territory'
def validate(self):
def validate(self):
for d in self.get('target_details'):
if not flt(d.target_qty) and not flt(d.target_amount):
msgprint("Either target qty or target amount is mandatory.")
raise Exception
frappe.throw(_("Either target qty or target amount is mandatory"))
def on_update(self):
super(Territory, self).on_update()

View File

@ -13,33 +13,29 @@ def get_company_currency(company):
if not currency:
throw(_('Please specify Default Currency in Company Master \
and Global Defaults'))
return currency
def get_root_of(doctype):
"""Get root element of a DocType with a tree structure"""
result = frappe.db.sql_list("""select name from `tab%s`
where lft=1 and rgt=(select max(rgt) from `tab%s` where docstatus < 2)""" %
result = frappe.db.sql_list("""select name from `tab%s`
where lft=1 and rgt=(select max(rgt) from `tab%s` where docstatus < 2)""" %
(doctype, doctype))
return result[0] if result else None
def get_ancestors_of(doctype, name):
"""Get ancestor elements of a DocType with a tree structure"""
lft, rgt = frappe.db.get_value(doctype, name, ["lft", "rgt"])
result = frappe.db.sql_list("""select name from `tab%s`
result = frappe.db.sql_list("""select name from `tab%s`
where lft<%s and rgt>%s order by lft desc""" % (doctype, "%s", "%s"), (lft, rgt))
return result or []
@frappe.whitelist()
def get_price_list_currency(price_list):
price_list_currency = frappe.db.get_value("Price List", {"name": price_list,
price_list_currency = frappe.db.get_value("Price List", {"name": price_list,
"enabled": 1}, "currency")
if not price_list_currency:
throw("{message}: {price_list} {disabled}".format(**{
"message": _("Price List"),
"price_list": price_list,
"disabled": _("is disabled.")
}))
throw(_("Price List {0} is disabled").format(price_list))
else:
return {"price_list_currency": price_list_currency}
return {"price_list_currency": price_list_currency}

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt, cint
from frappe.utils import flt, cint
from frappe import msgprint, _
import frappe.defaults
@ -54,9 +54,7 @@ class DeliveryNote(SellingController):
if frappe.db.get_value("Selling Settings", None, 'so_required') == 'Yes':
for d in self.get('delivery_note_details'):
if not d.against_sales_order:
msgprint("Sales Order No. required against item %s"%d.item_code)
raise Exception
frappe.throw(_("Sales Order required for Item {0}").format(d.item_code))
def validate(self):
super(DeliveryNote, self).validate()
@ -108,8 +106,7 @@ class DeliveryNote(SellingController):
where name = %s and (customer = %s or
ifnull(customer,'')='')""", (self.project_name, self.customer))
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.customer,self.project_name,self.project_name))
raise Exception
frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project_name))
def validate_for_items(self):
check_list, chk_dupl_itm = [], []
@ -119,14 +116,12 @@ class DeliveryNote(SellingController):
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes':
if e in check_list:
msgprint("Please check whether item %s has been entered twice wrongly."
% d.item_code)
msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
else:
check_list.append(e)
else:
if f in chk_dupl_itm:
msgprint("Please check whether item %s has been entered twice wrongly."
% d.item_code)
msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
else:
chk_dupl_itm.append(f)
@ -134,8 +129,7 @@ class DeliveryNote(SellingController):
for d in self.get_item_list():
if frappe.db.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['warehouse']:
msgprint("Please enter Warehouse for item %s as it is stock item"
% d['item_code'], raise_exception=1)
frappe.throw(_("Warehouse required for stock Item {0}").format(d["item_code"]))
def update_current_stock(self):
@ -187,18 +181,13 @@ class DeliveryNote(SellingController):
"""
if not any([flt(d.get('packed_qty')) for d in self.get(self.fname)]):
return
packing_error_list = []
has_error = False
for d in self.get(self.fname):
if flt(d.get('qty')) != flt(d.get('packed_qty')):
packing_error_list.append([
d.get('item_code', ''),
d.get('qty', 0),
d.get('packed_qty', 0)
])
if packing_error_list:
err_msg = "\n".join([("Item: " + d[0] + ", Qty: " + cstr(d[1]) \
+ ", Packed: " + cstr(d[2])) for d in packing_error_list])
frappe.msgprint("Packing Error:\n" + err_msg, raise_exception=1)
frappe.msgprint(_("Packed quantity must equal quantity for Item {0} in row {1}").format(d.item_code, d.idx))
has_error = True
if has_error:
raise frappe.ValidationError
def check_next_docstatus(self):
submit_rv = frappe.db.sql("""select t1.name
@ -206,16 +195,14 @@ class DeliveryNote(SellingController):
where t1.name = t2.parent and t2.delivery_note = %s and t1.docstatus = 1""",
(self.name))
if submit_rv:
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted !")
raise Exception , "Validation Error."
frappe.throw(_("Sales Invoice {0} has already been submitted").format(submit_rv[0][0]))
submit_in = frappe.db.sql("""select t1.name
from `tabInstallation Note` t1, `tabInstallation Note Item` t2
where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1""",
(self.name))
if submit_in:
msgprint("Installation Note : "+cstr(submit_in[0][0]) +" has already been submitted !")
raise Exception , "Validation Error."
frappe.throw(_("Installation Note {0} has already been submitted").format(submit_in[0][0]))
def cancel_packing_slips(self):
"""
@ -228,7 +215,7 @@ class DeliveryNote(SellingController):
for r in res:
ps = frappe.get_doc('Packing Slip', r[0])
ps.cancel()
frappe.msgprint(_("Packing Slip(s) Cancelled"))
frappe.msgprint(_("Packing Slip(s) cancelled"))
def update_stock_ledger(self):
@ -293,8 +280,7 @@ def make_sales_invoice(source_name, target_doc=None):
si.run_method("onload_post_render")
if len(si.get("entries")) == 0:
frappe.msgprint(_("All these items have already been invoiced."),
raise_exception=True)
frappe.throw(_("All these items have already been invoiced"))
def update_item(source_doc, target_doc, source_parent):
target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)

View File

@ -18,13 +18,13 @@ class Item(WebsiteGenerator):
from frappe.model.naming import make_autoname
self.item_code = make_autoname(self.naming_series+'.#####')
elif not self.item_code:
msgprint(_("Item Code (item_code) is mandatory because Item naming is not sequential."), raise_exception=1)
msgprint(_("Item Code is mandatory because Item is not automatically numbered"), raise_exception=1)
self.name = self.item_code
def validate(self):
if not self.stock_uom:
msgprint(_("Please enter Default Unit of Measure"), raise_exception=1)
msgprint(_("Please enter default Unit of Measure"), raise_exception=1)
self.check_warehouse_is_set_for_stock_item()
self.check_stock_uom_with_bin()
@ -51,7 +51,7 @@ class Item(WebsiteGenerator):
def check_warehouse_is_set_for_stock_item(self):
if self.is_stock_item=="Yes" and not self.default_warehouse:
frappe.msgprint(_("Default Warehouse is mandatory for Stock Item."),
frappe.msgprint(_("Default Warehouse is mandatory for stock Item."),
raise_exception=WarehouseNotSet)
def add_default_uom_in_conversion_factor_table(self):
@ -97,17 +97,12 @@ class Item(WebsiteGenerator):
check_list = []
for d in self.get('uom_conversion_details'):
if cstr(d.uom) in check_list:
msgprint(_("UOM %s has been entered more than once in Conversion Factor Table." %
cstr(d.uom)), raise_exception=1)
frappe.throw(_("Unit of Measure {0} has been entered more than once in Conversion Factor Table").format(d.uom))
else:
check_list.append(cstr(d.uom))
if d.uom and cstr(d.uom) == cstr(self.stock_uom) and flt(d.conversion_factor) != 1:
msgprint(_("""Conversion Factor of UOM: %s should be equal to 1. As UOM: %s is Stock UOM of Item: %s.""" %
(d.uom, d.uom, self.name)), raise_exception=1)
elif d.uom and cstr(d.uom)!= self.stock_uom and flt(d.conversion_factor) == 1:
msgprint(_("""Conversion Factor of UOM: %s should not be equal to 1. As UOM: %s is not Stock UOM of Item: %s""" %
(d.uom, d.uom, self.name)), raise_exception=1)
frappe.throw(_("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx))
def validate_item_type(self):
if cstr(self.is_manufactured_item) == "No":
@ -118,7 +113,7 @@ class Item(WebsiteGenerator):
it must be a stock item."))
if self.has_serial_no == 'Yes' and self.is_stock_item == 'No':
msgprint("'Has Serial No' can not be 'Yes' for non-stock item", raise_exception=1)
msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1)
def check_for_active_boms(self):
if self.is_purchase_item != "Yes":
@ -153,10 +148,10 @@ class Item(WebsiteGenerator):
account_type = frappe.db.get_value("Account", d.tax_type, "account_type")
if account_type not in ['Tax', 'Chargeable', 'Income Account', 'Expense Account']:
msgprint("'%s' is not Tax / Chargeable / Income / Expense Account" % d.tax_type, raise_exception=1)
frappe.throw(_("Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable").format(d.idx))
else:
if d.tax_type in check_list:
msgprint("Rate is entered twice for: '%s'" % d.tax_type, raise_exception=1)
frappe.throw(_("{0} entered twice in Item Tax").format(d.tax_type))
else:
check_list.append(d.tax_type)
@ -165,8 +160,7 @@ class Item(WebsiteGenerator):
duplicate = frappe.db.sql("""select name from tabItem where barcode = %s
and name != %s""", (self.barcode, self.name))
if duplicate:
msgprint("Barcode: %s already used in item: %s" %
(self.barcode, cstr(duplicate[0][0])), raise_exception = 1)
frappe.throw(_("Barcode {0} already used in Item {1}").format(self.barcode, duplicate[0][0]))
def cant_change(self):
if not self.get("__islocal"):
@ -182,8 +176,7 @@ class Item(WebsiteGenerator):
def validate_item_type_for_reorder(self):
if self.re_order_level or len(self.get("item_reorder", {"material_request_type": "Purchase"})):
if not self.is_purchase_item:
frappe.msgprint(_("""To set reorder level, item must be Purchase Item"""),
raise_exception=1)
frappe.throw(_("""To set reorder level, item must be Purchase Item"""))
def check_if_sle_exists(self):
sle = frappe.db.sql("""select name from `tabStock Ledger Entry`
@ -193,9 +186,7 @@ class Item(WebsiteGenerator):
def validate_name_with_item_group(self):
# causes problem with tree build
if frappe.db.exists("Item Group", self.name):
frappe.msgprint("An item group exists with same name (%s), \
please change the item name or rename the item group" %
self.name, raise_exception=1)
frappe.throw(_("An Item Group exists with same name, please change the item name or rename the item group"))
def update_item_price(self):
frappe.db.sql("""update `tabItem Price` set item_name=%s,
@ -269,14 +260,7 @@ def validate_end_of_life(item_code, end_of_life=None, verbose=1):
end_of_life = frappe.db.get_value("Item", item_code, "end_of_life")
if end_of_life and getdate(end_of_life) <= now_datetime().date():
msg = (_("Item") + " %(item_code)s: " + _("reached its end of life on") + \
" %(date)s. " + _("Please check") + ": %(end_of_life_label)s " + \
"in Item master") % {
"item_code": item_code,
"date": formatdate(end_of_life),
"end_of_life_label": frappe.get_meta("Item").get_label("end_of_life")
}
msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life))
_msgprint(msg, verbose)
def validate_is_stock_item(item_code, is_stock_item=None, verbose=1):
@ -284,9 +268,7 @@ def validate_is_stock_item(item_code, is_stock_item=None, verbose=1):
is_stock_item = frappe.db.get_value("Item", item_code, "is_stock_item")
if is_stock_item != "Yes":
msg = (_("Item") + " %(item_code)s: " + _("is not a Stock Item")) % {
"item_code": item_code,
}
msg = _("Item {0} is not a stock Item").format(item_code)
_msgprint(msg, verbose)
@ -295,10 +277,7 @@ def validate_cancelled_item(item_code, docstatus=None, verbose=1):
docstatus = frappe.db.get_value("Item", item_code, "docstatus")
if docstatus == 2:
msg = (_("Item") + " %(item_code)s: " + _("is a cancelled Item")) % {
"item_code": item_code,
}
msg = _("Item {0} is cancelled").format(item_code)
_msgprint(msg, verbose)
def _msgprint(msg, verbose):

View File

@ -9,20 +9,20 @@ from frappe import msgprint, _
from frappe.model.document import Document
class LandedCostWizard(Document):
def update_landed_cost(self):
"""
Add extra cost and recalculate all values in pr,
Add extra cost and recalculate all values in pr,
Recalculate valuation rate in all sle after pr posting date
"""
purchase_receipts = [row.purchase_receipt for row in
purchase_receipts = [row.purchase_receipt for row in
self.get("lc_pr_details")]
self.validate_purchase_receipts(purchase_receipts)
self.cancel_pr(purchase_receipts)
self.add_charges_in_pr(purchase_receipts)
self.submit_pr(purchase_receipts)
msgprint("Landed Cost updated successfully")
msgprint(_("Landed Cost updated successfully"))
def validate_purchase_receipts(self, purchase_receipts):
for pr in purchase_receipts:
@ -32,21 +32,21 @@ class LandedCostWizard(Document):
def add_charges_in_pr(self, purchase_receipts):
""" Add additional charges in selected pr proportionately"""
total_amt = self.get_total_pr_amt(purchase_receipts)
for pr in purchase_receipts:
pr_doc = frappe.get_doc('Purchase Receipt', pr)
pr_items = pr_doc.get("purchase_tax_details")
for lc in self.get("landed_cost_details"):
amt = flt(lc.amount) * flt(pr_doc.net_total)/ flt(total_amt)
matched_row = pr_doc.get("other_charges", {
"category": "Valuation",
"add_deduct_tax": "Add",
"charge_type": "Actual",
"account_head": lc.account_head
})
if not matched_row: # add if not exists
ch = pr_doc.append("other_charges")
ch.category = 'Valuation'
@ -63,30 +63,30 @@ class LandedCostWizard(Document):
matched_row[0].rate = amt
matched_row[0].tax_amount = amt
matched_row[0].cost_center = lc.cost_center
pr_doc.run_method("validate")
for d in pr_doc.get_all_children():
d.db_update()
def get_total_pr_amt(self, purchase_receipts):
return frappe.db.sql("""SELECT SUM(net_total) FROM `tabPurchase Receipt`
WHERE name in (%s)""" % ', '.join(['%s']*len(purchase_receipts)),
return frappe.db.sql("""SELECT SUM(net_total) FROM `tabPurchase Receipt`
WHERE name in (%s)""" % ', '.join(['%s']*len(purchase_receipts)),
tuple(purchase_receipts))[0][0]
def cancel_pr(self, purchase_receipts):
for pr in purchase_receipts:
pr_doc = frappe.get_doc("Purchase Receipt", pr)
pr_doc.run_method("update_ordered_qty")
frappe.db.sql("""delete from `tabStock Ledger Entry`
frappe.db.sql("""delete from `tabStock Ledger Entry`
where voucher_type='Purchase Receipt' and voucher_no=%s""", pr)
frappe.db.sql("""delete from `tabGL Entry` where voucher_type='Purchase Receipt'
frappe.db.sql("""delete from `tabGL Entry` where voucher_type='Purchase Receipt'
and voucher_no=%s""", pr)
def submit_pr(self, purchase_receipts):
for pr in purchase_receipts:
pr_doc = frappe.get_doc("Purchase Receipt", pr)
pr_doc.run_method("update_ordered_qty")
pr_doc.run_method("update_stock")
pr_doc.run_method("make_gl_entries")
pr_doc.run_method("make_gl_entries")

View File

@ -114,7 +114,7 @@ class MaterialRequest(BuyingController):
self.check_modified_date()
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
frappe.db.set(self, 'status', cstr(status))
msgprint(self.doctype + ": " + self.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
frappe.msgprint(_("Status updated to {0}").format(_(status)))
def on_cancel(self):
# Step 1:=> Get Purchase Common Obj

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cint
from frappe import msgprint, _
from frappe import _
from frappe.model.document import Document
@ -32,12 +32,12 @@ class PackingSlip(Document):
Validates if delivery note has status as draft
"""
if cint(frappe.db.get_value("Delivery Note", self.delivery_note, "docstatus")) != 0:
msgprint(_("""Invalid Delivery Note. Delivery Note should exist and should be in draft state. Please rectify and try again."""), raise_exception=1)
frappe.throw(_("Delivery Note {0} must not be submitted").format(self.delivery_note))
def validate_items_mandatory(self):
rows = [d.item_code for d in self.get("item_details")]
if not rows:
frappe.msgprint(_("No Items to Pack"), raise_exception=1)
frappe.msgprint(_("No Items to pack"), raise_exception=1)
def validate_case_nos(self):
"""
@ -50,8 +50,8 @@ class PackingSlip(Document):
elif self.from_case_no > self.to_case_no:
frappe.msgprint(_("'To Case No.' cannot be less than 'From Case No.'"),
raise_exception=1)
res = frappe.db.sql("""SELECT name FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
(from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s
@ -60,9 +60,7 @@ class PackingSlip(Document):
""", self.as_dict())
if res:
frappe.msgprint(_("""Case No(s) already in use. Please rectify and try again.
Recommended <b>From Case No. = %s</b>""") % self.get_recommended_case_no(),
raise_exception=1)
frappe.throw(_("""Case No(s) already in use. Try from Case No {0}""").format(self.get_recommended_case_no()))
def validate_qty(self):
"""
@ -85,13 +83,13 @@ class PackingSlip(Document):
* Item Quantity dict of current packing slip doc
* No. of Cases of this packing slip
"""
rows = [d.item_code for d in self.get("item_details")]
condition = ""
if rows:
condition = " and item_code in (%s)" % (", ".join(["%s"]*len(rows)))
# gets item code, qty per item code, latest packed qty per item code and stock uom
res = frappe.db.sql("""select item_code, ifnull(sum(qty), 0) as qty,
(select sum(ifnull(psi.qty, 0) * (abs(ps.to_case_no - ps.from_case_no) + 1))
@ -100,7 +98,7 @@ class PackingSlip(Document):
and ps.delivery_note = dni.parent and psi.item_code=dni.item_code) as packed_qty,
stock_uom, item_name
from `tabDelivery Note Item` dni
where parent=%s %s
where parent=%s %s
group by item_code""" % ("%s", condition),
tuple([self.delivery_note] + rows), as_dict=1)
@ -117,12 +115,8 @@ class PackingSlip(Document):
item['recommended_qty'] = (flt(item['qty']) - flt(item['packed_qty'])) / no_of_cases
item['specified_qty'] = flt(ps_item_qty[item['item_code']])
if not item['packed_qty']: item['packed_qty'] = 0
frappe.msgprint("""
Invalid Quantity specified (%(specified_qty)s %(stock_uom)s).
%(packed_qty)s out of %(qty)s %(stock_uom)s already packed for %(item_code)s.
<b>Recommended quantity for %(item_code)s = %(recommended_qty)s
%(stock_uom)s</b>""" % item, raise_exception=1)
frappe.throw(_("Quantity for Item {0} must be less than {1}").format(item.get("item_code"), item.get("recommended_qty")))
def update_item_details(self):
"""
@ -132,9 +126,9 @@ class PackingSlip(Document):
self.from_case_no = self.get_recommended_case_no()
for d in self.get("item_details"):
res = frappe.db.get_value("Item", d.item_code,
res = frappe.db.get_value("Item", d.item_code,
["net_weight", "weight_uom"], as_dict=True)
if res and len(res)>0:
d.net_weight = res["net_weight"]
d.weight_uom = res["weight_uom"]
@ -146,12 +140,12 @@ class PackingSlip(Document):
"""
recommended_case_no = frappe.db.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.as_dict())
return cint(recommended_case_no[0][0]) + 1
def get_items(self):
self.set("item_details", [])
dn_details = self.get_details_for_packing()[0]
for item in dn_details:
if flt(item.qty) > flt(item.packed_qty):
@ -164,11 +158,11 @@ class PackingSlip(Document):
def item_details(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
return frappe.db.sql("""select name, item_name, description from `tabItem`
where name in ( select item_code FROM `tabDelivery Note Item`
where parent= %s
and ifnull(qty, 0) > ifnull(packed_qty, 0))
and %s like "%s" %s
limit %s, %s """ % ("%s", searchfield, "%s",
get_match_cond(doctype), "%s", "%s"),
(filters["delivery_note"], "%%%s%%" % txt, start, page_len))
return frappe.db.sql("""select name, item_name, description from `tabItem`
where name in ( select item_code FROM `tabDelivery Note Item`
where parent= %s
and ifnull(qty, 0) > ifnull(packed_qty, 0))
and %s like "%s" %s
limit %s, %s """ % ("%s", searchfield, "%s",
get_match_cond(doctype), "%s", "%s"),
(filters["delivery_note"], "%%%s%%" % txt, start, page_len))

View File

@ -6,7 +6,7 @@ import frappe
from frappe.utils import cstr, flt, cint
from frappe import msgprint, _
from frappe import _
import frappe.defaults
from erpnext.stock.utils import update_bin
@ -86,21 +86,18 @@ class PurchaseReceipt(BuyingController):
# Check Received Qty = Accepted Qty + Rejected Qty
if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)):
msgprint("Sum of Accepted Qty and Rejected Qty must be equal to Received quantity. Error for Item: " + cstr(d.item_code))
raise Exception
frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code))
def validate_challan_no(self):
"Validate if same challan no exists for same supplier in a submitted purchase receipt"
if self.challan_no:
exists = frappe.db.sql("""
exists = frappe.db.sql_list("""
SELECT name FROM `tabPurchase Receipt`
WHERE name!=%s AND supplier=%s AND challan_no=%s
AND docstatus=1""", (self.name, self.supplier, self.challan_no))
if exists:
frappe.msgprint("Another Purchase Receipt using the same Challan No. already exists.\
Please enter a valid Challan No.", raise_exception=1)
frappe.throw(_("Supplier delivery number duplicate in {0}").format(exists))
def validate_with_previous_doc(self):
super(PurchaseReceipt, self).validate_with_previous_doc(self.tname, {
@ -129,8 +126,7 @@ class PurchaseReceipt(BuyingController):
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
for d in self.get('purchase_receipt_details'):
if not d.prevdoc_docname:
msgprint("Purchse Order No. required against item %s"%d.item_code)
raise Exception
frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code))
def update_stock(self):
sl_entries = []
@ -212,7 +208,7 @@ class PurchaseReceipt(BuyingController):
(d.item_code,), as_dict = 1)
ins_reqd = ins_reqd and ins_reqd[0]['inspection_required'] or 'No'
if ins_reqd == 'Yes' and not d.qa_no:
msgprint("Item: " + d.item_code + " requires QA Inspection. Please enter QA No or report to authorized person to create Quality Inspection")
frappe.throw(_("Quality Inspection required for Item {0}").format(d.item_code))
# Check for Stopped status
def check_for_stopped_status(self, pc_obj):
@ -251,9 +247,7 @@ class PurchaseReceipt(BuyingController):
where t1.name = t2.parent and t2.purchase_receipt = %s and t1.docstatus = 1""",
(self.name))
if submit_rv:
msgprint("Purchase Invoice : " + cstr(self.submit_rv[0][0]) + " has already been submitted !")
raise Exception , "Validation Error."
frappe.throw(_("Purchase Invoice {0} is already submitted").format(self.submit_rv[0][0]))
def on_cancel(self):
pc_obj = frappe.get_doc('Purchase Common')

View File

@ -29,7 +29,7 @@ class SerialNo(StockController):
if self.get("__islocal") and self.warehouse:
frappe.throw(_("New Serial No cannot have Warehouse. Warehouse must be \
set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError)
self.set_maintenance_status()
self.validate_warehouse()
self.validate_item()
@ -38,28 +38,28 @@ class SerialNo(StockController):
def set_maintenance_status(self):
if not self.warranty_expiry_date and not self.amc_expiry_date:
self.maintenance_status = None
if self.warranty_expiry_date and self.warranty_expiry_date < nowdate():
self.maintenance_status = "Out of Warranty"
if self.amc_expiry_date and self.amc_expiry_date < nowdate():
self.maintenance_status = "Out of AMC"
if self.amc_expiry_date and self.amc_expiry_date >= nowdate():
self.maintenance_status = "Under AMC"
if self.warranty_expiry_date and self.warranty_expiry_date >= nowdate():
self.maintenance_status = "Under Warranty"
def validate_warehouse(self):
if not self.get("__islocal"):
item_code, warehouse = frappe.db.get_value("Serial No",
item_code, warehouse = frappe.db.get_value("Serial No",
self.name, ["item_code", "warehouse"])
if item_code != self.item_code:
frappe.throw(_("Item Code cannot be changed for Serial No."),
frappe.throw(_("Item Code cannot be changed for Serial No."),
SerialNoCannotCannotChangeError)
if not self.via_stock_ledger and warehouse != self.warehouse:
frappe.throw(_("Warehouse cannot be changed for Serial No."),
frappe.throw(_("Warehouse cannot be changed for Serial No."),
SerialNoCannotCannotChangeError)
def validate_item(self):
@ -69,17 +69,17 @@ class SerialNo(StockController):
item = frappe.get_doc("Item", self.item_code)
if item.has_serial_no!="Yes":
frappe.throw(_("Item must have 'Has Serial No' as 'Yes'") + ": " + self.item_code)
self.item_group = item.item_group
self.description = item.description
self.item_name = item.item_name
self.brand = item.brand
self.warranty_period = item.warranty_period
def set_status(self, last_sle):
if last_sle:
if last_sle.voucher_type == "Stock Entry":
document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no,
document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no,
"purpose")
else:
document_type = last_sle.voucher_type
@ -98,7 +98,7 @@ class SerialNo(StockController):
self.status = "Not Available"
else:
self.status = "Not Available"
def set_purchase_details(self, purchase_sle):
if purchase_sle:
self.purchase_document_type = purchase_sle.voucher_type
@ -108,13 +108,13 @@ class SerialNo(StockController):
self.purchase_rate = purchase_sle.incoming_rate
if purchase_sle.voucher_type == "Purchase Receipt":
self.supplier, self.supplier_name = \
frappe.db.get_value("Purchase Receipt", purchase_sle.voucher_no,
frappe.db.get_value("Purchase Receipt", purchase_sle.voucher_no,
["supplier", "supplier_name"])
else:
for fieldname in ("purchase_document_type", "purchase_document_no",
for fieldname in ("purchase_document_type", "purchase_document_no",
"purchase_date", "purchase_time", "purchase_rate", "supplier", "supplier_name"):
self.set(fieldname, None)
def set_sales_details(self, delivery_sle):
if delivery_sle:
self.delivery_document_type = delivery_sle.voucher_type
@ -122,70 +122,70 @@ class SerialNo(StockController):
self.delivery_date = delivery_sle.posting_date
self.delivery_time = delivery_sle.posting_time
self.customer, self.customer_name = \
frappe.db.get_value(delivery_sle.voucher_type, delivery_sle.voucher_no,
frappe.db.get_value(delivery_sle.voucher_type, delivery_sle.voucher_no,
["customer", "customer_name"])
if self.warranty_period:
self.warranty_expiry_date = add_days(cstr(delivery_sle.posting_date),
self.warranty_expiry_date = add_days(cstr(delivery_sle.posting_date),
cint(self.warranty_period))
else:
for fieldname in ("delivery_document_type", "delivery_document_no",
"delivery_date", "delivery_time", "customer", "customer_name",
for fieldname in ("delivery_document_type", "delivery_document_no",
"delivery_date", "delivery_time", "customer", "customer_name",
"warranty_expiry_date"):
self.set(fieldname, None)
def get_last_sle(self):
entries = {}
sle_dict = self.get_stock_ledger_entries()
if sle_dict:
if sle_dict.get("incoming", []):
entries["purchase_sle"] = sle_dict["incoming"][0]
if len(sle_dict.get("incoming", [])) - len(sle_dict.get("outgoing", [])) > 0:
entries["last_sle"] = sle_dict["incoming"][0]
else:
entries["last_sle"] = sle_dict["outgoing"][0]
entries["delivery_sle"] = sle_dict["outgoing"][0]
return entries
def get_stock_ledger_entries(self):
sle_dict = {}
for sle in frappe.db.sql("""select * from `tabStock Ledger Entry`
where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No'
order by posting_date desc, posting_time desc, name desc""",
for sle in frappe.db.sql("""select * from `tabStock Ledger Entry`
where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No'
order by posting_date desc, posting_time desc, name desc""",
("%%%s%%" % self.name, self.item_code), as_dict=1):
if self.name.upper() in get_serial_nos(sle.serial_no):
if sle.actual_qty > 0:
sle_dict.setdefault("incoming", []).append(sle)
else:
sle_dict.setdefault("outgoing", []).append(sle)
return sle_dict
def on_trash(self):
if self.status == 'Delivered':
frappe.throw(_("Delivered Serial No ") + self.name + _(" can not be deleted"))
if self.warehouse:
frappe.throw(_("Cannot delete Serial No in warehouse. \
First remove from warehouse, then delete.") + ": " + self.name)
def before_rename(self, old, new, merge=False):
if merge:
frappe.throw(_("Sorry, Serial Nos cannot be merged"))
def after_rename(self, old, new, merge=False):
"""rename serial_no text fields"""
for dt in frappe.db.sql("""select parent from tabDocField
for dt in frappe.db.sql("""select parent from tabDocField
where fieldname='serial_no' and fieldtype='Text'"""):
for item in frappe.db.sql("""select name, serial_no from `tab%s`
for item in frappe.db.sql("""select name, serial_no from `tab%s`
where serial_no like '%%%s%%'""" % (dt[0], old)):
serial_nos = map(lambda i: i==old and new or i, item[1].split('\n'))
frappe.db.sql("""update `tab%s` set serial_no = %s
frappe.db.sql("""update `tab%s` set serial_no = %s
where name=%s""" % (dt[0], '%s', '%s'),
('\n'.join(serial_nos), item[0]))
def on_stock_ledger_entry(self):
if self.via_stock_ledger and not self.get("__islocal"):
last_sle = self.get_last_sle()
@ -193,7 +193,7 @@ class SerialNo(StockController):
self.set_purchase_details(last_sle.get("purchase_sle"))
self.set_sales_details(last_sle.get("delivery_sle"))
self.set_maintenance_status()
def on_communication(self):
return
@ -201,11 +201,11 @@ def process_serial_no(sle):
item_det = get_item_details(sle.item_code)
validate_serial_no(sle, item_det)
update_serial_nos(sle, item_det)
def validate_serial_no(sle, item_det):
if item_det.has_serial_no=="No":
if sle.serial_no:
frappe.throw(_("Serial Number should be blank for Non Serialized Item" + ": "
frappe.throw(_("Serial Number should be blank for Non Serialized Item" + ": "
+ sle.item_code), SerialNoNotRequiredError)
else:
if sle.serial_no:
@ -216,41 +216,41 @@ def validate_serial_no(sle, item_det):
if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)):
frappe.throw(_("Serial Nos do not match with qty") + \
(": %s (%s)" % (sle.item_code, sle.actual_qty)), SerialNoQtyError)
if len(serial_nos) != len(set(serial_nos)):
frappe.throw(_("Duplicate Serial No entered against item") +
frappe.throw(_("Duplicate Serial No entered against item") +
(": %s" % sle.item_code), SerialNoDuplicateError)
for serial_no in serial_nos:
if frappe.db.exists("Serial No", serial_no):
sr = frappe.get_doc("Serial No", serial_no)
if sr.item_code!=sle.item_code:
frappe.throw(_("Serial No does not belong to Item") +
frappe.throw(_("Serial No does not belong to Item") +
(": %s (%s)" % (sle.item_code, serial_no)), SerialNoItemError)
if sr.warehouse and sle.actual_qty > 0:
frappe.throw(_("Same Serial No") + ": " + sr.name +
frappe.throw(_("Same Serial No") + ": " + sr.name +
_(" can not be received twice"), SerialNoDuplicateError)
if sle.actual_qty < 0:
if sr.warehouse!=sle.warehouse:
frappe.throw(_("Serial No") + ": " + serial_no +
_(" does not belong to Warehouse") + ": " + sle.warehouse,
frappe.throw(_("Serial No") + ": " + serial_no +
_(" does not belong to Warehouse") + ": " + sle.warehouse,
SerialNoWarehouseError)
if sle.voucher_type in ("Delivery Note", "Sales Invoice") \
and sr.status != "Available":
frappe.throw(_("Serial No status must be 'Available' to Deliver")
frappe.throw(_("Serial No status must be 'Available' to Deliver")
+ ": " + serial_no, SerialNoStatusError)
elif sle.actual_qty < 0:
# transfer out
frappe.throw(_("Serial No must exist to transfer out.") + \
": " + serial_no, SerialNoNotExistsError)
elif sle.actual_qty < 0 or not item_det.serial_no_series:
frappe.throw(_("Serial Number Required for Serialized Item" + ": "
frappe.throw(_("Serial Number Required for Serialized Item" + ": "
+ sle.item_code), SerialNoRequiredError)
def update_serial_nos(sle, item_det):
if sle.is_cancelled == "No" and not sle.serial_no and sle.actual_qty > 0 and item_det.serial_no_series:
from frappe.model.naming import make_autoname
@ -258,7 +258,7 @@ def update_serial_nos(sle, item_det):
for i in xrange(cint(sle.actual_qty)):
serial_nos.append(make_autoname(item_det.serial_no_series))
frappe.db.set(sle, "serial_no", "\n".join(serial_nos))
if sle.serial_no:
serial_nos = get_serial_nos(sle.serial_no)
for serial_no in serial_nos:
@ -271,12 +271,12 @@ def update_serial_nos(sle, item_det):
make_serial_no(serial_no, sle)
def get_item_details(item_code):
return frappe.db.sql("""select name, has_batch_no, docstatus,
is_stock_item, has_serial_no, serial_no_series
return frappe.db.sql("""select name, has_batch_no, docstatus,
is_stock_item, has_serial_no, serial_no_series
from tabItem where name=%s""", item_code, as_dict=True)[0]
def get_serial_nos(serial_no):
return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n')
return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n')
if s.strip()]
def make_serial_no(serial_no, sle):
@ -290,14 +290,14 @@ def make_serial_no(serial_no, sle):
sr.warehouse = sle.warehouse
sr.status = "Available"
sr.save()
frappe.msgprint(_("Serial No created") + ": " + sr.name)
frappe.msgprint(_("Serial No {0} created").format(sr.name))
return sr.name
def update_serial_nos_after_submit(controller, parentfield):
stock_ledger_entries = frappe.db.sql("""select voucher_detail_no, serial_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""",
(controller.doctype, controller.name), as_dict=True)
if not stock_ledger_entries: return
for d in controller.get(parentfield):

View File

@ -7,7 +7,7 @@ import frappe.defaults
from frappe.utils import cstr, cint, flt, comma_or, nowdate
from frappe import msgprint, _
from frappe import _
from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.controllers.queries import get_match_cond
@ -67,15 +67,13 @@ class StockEntry(StockController):
valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer",
"Manufacture/Repack", "Subcontract", "Sales Return", "Purchase Return"]
if self.purpose not in valid_purposes:
msgprint(_("Purpose must be one of ") + comma_or(valid_purposes),
raise_exception=True)
frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
def validate_item(self):
stock_items = self.get_stock_items()
for item in self.get("mtn_details"):
if item.item_code not in stock_items:
msgprint(_("""Only Stock Items are allowed for Stock Entry"""),
raise_exception=True)
frappe.throw(_("""Only Stock Items are allowed for Stock Entry"""))
def validate_warehouse(self, pro_obj):
"""perform various (sometimes conditional) validations on warehouse"""
@ -100,15 +98,13 @@ class StockEntry(StockController):
d.t_warehouse = self.to_warehouse
if not (d.s_warehouse or d.t_warehouse):
msgprint(_("Atleast one warehouse is mandatory"), raise_exception=1)
frappe.throw(_("Atleast one warehouse is mandatory"))
if self.purpose in source_mandatory and not d.s_warehouse:
msgprint(_("Row # ") + "%s: " % cint(d.idx)
+ _("Source Warehouse") + _(" is mandatory"), raise_exception=1)
frappe.throw(_("Source warehouse is mandatory for row {0}").format(d.idx))
if self.purpose in target_mandatory and not d.t_warehouse:
msgprint(_("Row # ") + "%s: " % cint(d.idx)
+ _("Target Warehouse") + _(" is mandatory"), raise_exception=1)
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
if self.purpose == "Manufacture/Repack":
if validate_for_manufacture_repack:
@ -116,23 +112,18 @@ class StockEntry(StockController):
d.s_warehouse = None
if not d.t_warehouse:
msgprint(_("Row # ") + "%s: " % cint(d.idx)
+ _("Target Warehouse") + _(" is mandatory"), raise_exception=1)
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
elif pro_obj and cstr(d.t_warehouse) != pro_obj.fg_warehouse:
msgprint(_("Row # ") + "%s: " % cint(d.idx)
+ _("Target Warehouse") + _(" should be same as that in ")
+ _("Production Order"), raise_exception=1)
frappe.throw(_("Target warehouse in row {0} must be same as Production Order").format(d.idx))
else:
d.t_warehouse = None
if not d.s_warehouse:
msgprint(_("Row # ") + "%s: " % cint(d.idx)
+ _("Source Warehouse") + _(" is mandatory"), raise_exception=1)
frappe.throw(_("Source warehouse is mandatory for row {0}").format(d.idx))
if cstr(d.s_warehouse) == cstr(d.t_warehouse):
msgprint(_("Source and Target Warehouse cannot be same"),
raise_exception=1)
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
def validate_production_order(self, pro_obj=None):
if not pro_obj:
@ -228,17 +219,13 @@ class StockEntry(StockController):
if d.bom_no and not frappe.db.sql("""select name from `tabBOM`
where item = %s and name = %s and docstatus = 1 and is_active = 1""",
(d.item_code, d.bom_no)):
msgprint(_("Item") + " %s: " % cstr(d.item_code)
+ _("does not belong to BOM: ") + cstr(d.bom_no)
+ _(" or the BOM is cancelled or inactive"), raise_exception=1)
frappe.throw(_("BOM {0} is not submitted or inactive BOM for Item {1}").format(d.bom_no, d.item_code))
def validate_finished_goods(self):
"""validation: finished good quantity should be same as manufacturing quantity"""
import json
for d in self.get('mtn_details'):
if d.bom_no and flt(d.transfer_qty) != flt(self.fg_completed_qty):
msgprint(_("Row #") + " %s: " % d.idx
+ _("Quantity should be equal to Manufacturing Quantity. To fetch items again, click on 'Get Items' button or update the Quantity manually."), raise_exception=1)
frappe.throw(_("Quantity in row {0} must be same as manufactured quantity").format(d.idx))
def validate_return_reference_doc(self):
"""validate item with reference doc"""
@ -247,14 +234,12 @@ class StockEntry(StockController):
if ref.doc:
# validate docstatus
if ref.doc.docstatus != 1:
frappe.msgprint(_(ref.doc.doctype) + ' "' + ref.doc.name + '": '
+ _("Status should be Submitted"), raise_exception=frappe.InvalidStatusError)
frappe.throw(_("{0} {1} must be submitted").format(ref.doc.doctype, ref.doc.name),
frappe.InvalidStatusError)
# update stock check
if ref.doc.doctype == "Sales Invoice" and cint(ref.doc.update_stock) != 1:
frappe.msgprint(_(ref.doc.doctype) + ' "' + ref.doc.name + '": '
+ _("Update Stock should be checked."),
raise_exception=NotUpdateStockError)
frappe.throw(_("'Update Stock' for Sales Invoice {0} must be set").format(ref.doc.name), NotUpdateStockError)
# posting date check
ref_posting_datetime = "%s %s" % (cstr(ref.doc.posting_date),
@ -263,9 +248,7 @@ class StockEntry(StockController):
cstr(self.posting_time))
if this_posting_datetime < ref_posting_datetime:
from frappe.utils.dateutils import datetime_in_user_format
frappe.msgprint(_("Posting Date Time cannot be before")
+ ": " + datetime_in_user_format(ref_posting_datetime),
raise_exception=True)
frappe.throw(_("Posting timestamp must be after {0}").format(datetime_in_user_format(ref_posting_datetime)))
stock_items = get_stock_items_for_return(ref.doc, ref.parentfields)
already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname)
@ -273,9 +256,8 @@ class StockEntry(StockController):
for item in self.get("mtn_details"):
# validate if item exists in the ref doc and that it is a stock item
if item.item_code not in stock_items:
msgprint(_("Item") + ': "' + item.item_code + _("\" does not exist in ") +
ref.doc.doctype + ": " + ref.doc.name,
raise_exception=frappe.DoesNotExistError)
frappe.throw(_("Item {0} does not exist in {1} {2}").format(item.item_code, ref.doc.doctype, ref.doc.name),
frappe.DoesNotExistError)
# validate quantity <= ref item's qty - qty already returned
ref_item = ref.doc.getone({"item_code": item.item_code})
@ -328,12 +310,10 @@ class StockEntry(StockController):
def update_production_order(self):
def _validate_production_order(pro_doc):
if flt(pro_doc.docstatus) != 1:
frappe.throw(_("Production Order must be submitted") + ": " +
self.production_order)
frappe.throw(_("Production Order {0} must be submitted").format(self.production_order))
if pro_doc.status == 'Stopped':
msgprint(_("Transaction not allowed against stopped Production Order") + ": " +
self.production_order)
frappe.throw(_("Transaction not allowed against stopped Production Order {0}").format(self.production_order))
if self.production_order:
pro_doc = frappe.get_doc("Production Order", self.production_order)
@ -372,7 +352,7 @@ class StockEntry(StockController):
where name = %s and (ifnull(end_of_life,'')='' or end_of_life > now())""",
(arg.get('item_code')), as_dict = 1)
if not item:
msgprint("Item is not active", raise_exception=1)
frappe.throw(_("Item {0} is not active or end of life has been reached").format(arg.get("item_code")))
ret = {
'uom' : item and item[0]['stock_uom'] or '',
@ -398,8 +378,7 @@ class StockEntry(StockController):
uom = frappe.db.sql("""select conversion_factor from `tabUOM Conversion Detail`
where parent = %s and uom = %s""", (arg['item_code'], arg['uom']), as_dict = 1)
if not uom or not flt(uom[0].conversion_factor):
msgprint("There is no Conversion Factor for UOM '%s' in Item '%s'" % (arg['uom'],
arg['item_code']))
frappe.msgprint(_("UOM coversion factor required for UOM {0} in Item {1}").format(arg["uom"], arg["item_code"]))
ret = {'uom' : ''}
else:
ret = {
@ -531,12 +510,10 @@ class StockEntry(StockController):
# show some message
if not len(item_dict):
frappe.msgprint(_("""All items have already been transferred \
for this Production Order."""))
frappe.msgprint(_("""All items have already been transferred for this Production Order."""))
elif only_pending_fetched:
frappe.msgprint(_("""Only quantities pending to be transferred \
were fetched for the following items:\n""" + "\n".join(only_pending_fetched)))
frappe.msgprint(_("Pending Items {0} updated").format(only_pending_fetched))
return item_dict
@ -589,10 +566,8 @@ class StockEntry(StockController):
{"name": item.material_request_item, "parent": item.material_request},
["item_code", "warehouse", "idx"], as_dict=True)
if mreq_item.item_code != item.item_code or mreq_item.warehouse != item.t_warehouse:
msgprint(_("Row #") + (" %d: " % item.idx) + _("does not match")
+ " " + _("Row #") + (" %d %s " % (mreq_item.idx, _("of")))
+ _("Material Request") + (" - %s" % item.material_request),
raise_exception=frappe.MappingMismatchError)
frappe.throw(_("Item or Warehouse for row {0} does not match Material Request").format(item.idx),
frappe.MappingMismatchError)
@frappe.whitelist()
def get_party_details(ref_dt, ref_dn):

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint
from frappe import _
from frappe.utils import cint, flt, cstr, now
from erpnext.stock.utils import get_valuation_method
import json
@ -309,17 +309,11 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue):
def _raise_exceptions(args, verbose=1):
deficiency = min(e["diff"] for e in _exceptions)
msg = """Negative stock error:
Cannot complete this transaction because stock will start
becoming negative (%s) for Item <b>%s</b> in Warehouse
<b>%s</b> on <b>%s %s</b> in Transaction %s %s.
Total Quantity Deficiency: <b>%s</b>""" % \
(_exceptions[0]["diff"], args.get("item_code"), args.get("warehouse"),
_exceptions[0]["posting_date"], _exceptions[0]["posting_time"],
_exceptions[0]["voucher_type"], _exceptions[0]["voucher_no"],
abs(deficiency))
msg = _("Negative Stock Error ({6}) for Item {0} in Warehouse {1} on {2} {3} in {4} {5}").format(args["item_code"],
args.get("warehouse"), _exceptions[0]["posting_date"], _exceptions[0]["posting_time"],
_(_exceptions[0]["voucher_type"]), _exceptions[0]["voucher_no"], deficiency)
if verbose:
msgprint(msg, raise_exception=NegativeStockError)
frappe.throw(msg, NegativeStockError)
else:
raise NegativeStockError, msg

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe import msgprint, _
from frappe import _
import json
from frappe.utils import flt, cstr, nowdate, add_days, cint
from frappe.defaults import get_global_default
@ -58,8 +58,7 @@ def update_bin(args):
bin.update_stock(args)
return bin
else:
msgprint("[Stock Update] Ignored %s since it is not a stock item"
% args.get("item_code"))
frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code")))
def get_incoming_rate(args):
"""Get Incoming Rate based on valuation method"""
@ -134,22 +133,20 @@ def get_valid_serial_nos(sr_nos, qty=0, item_code=''):
if val:
val = val.strip()
if val in valid_serial_nos:
msgprint("You have entered duplicate serial no: '%s'" % val, raise_exception=1)
frappe.throw(_("Serial number {0} entered more than once").format(val))
else:
valid_serial_nos.append(val)
if qty and len(valid_serial_nos) != abs(qty):
msgprint("Please enter serial nos for "
+ cstr(abs(qty)) + " quantity against item code: " + item_code,
raise_exception=1)
frappe.throw(_("{0} valid serial nos for Item {1}").format(abs(qty), item_code))
return valid_serial_nos
def validate_warehouse_company(warehouse, company):
warehouse_company = frappe.db.get_value("Warehouse", warehouse, "company")
if warehouse_company and warehouse_company != company:
frappe.msgprint(_("Warehouse does not belong to company.") + " (" + \
warehouse + ", " + company +")", raise_exception=InvalidWarehouseCompany)
frappe.throw(_("Warehouse {0} does not belong to company {1}").format(warehouse, company),
InvalidWarehouseCompany)
def get_sales_bom_buying_amount(item_code, warehouse, voucher_type, voucher_no, voucher_detail_no,
stock_ledger_entries, item_sales_bom):