update translation strings #1403
This commit is contained in:
parent
7da01d6007
commit
9f0d625300
@ -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"))
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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)
|
||||
|
@ -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'):
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
|
@ -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"]:
|
||||
|
@ -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""" %
|
||||
|
@ -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"))
|
||||
|
@ -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,
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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 = {
|
||||
|
@ -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 []
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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"))
|
||||
|
@ -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,))
|
||||
|
@ -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]))
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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)))
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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"))
|
||||
|
@ -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"]
|
||||
],
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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()
|
||||
|
@ -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"))
|
||||
|
@ -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)
|
||||
|
@ -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})
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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):
|
||||
|
@ -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"
|
||||
]
|
||||
]
|
||||
|
@ -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")
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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"))
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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"""))
|
||||
|
@ -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"))
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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}
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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')
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user