Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into gst_sales_register_fix
This commit is contained in:
commit
0011585415
15
.github/helper/semgrep_rules/security.yml
vendored
15
.github/helper/semgrep_rules/security.yml
vendored
@ -8,18 +8,3 @@ rules:
|
|||||||
dynamic content. Avoid it or use safe_eval().
|
dynamic content. Avoid it or use safe_eval().
|
||||||
languages: [python]
|
languages: [python]
|
||||||
severity: ERROR
|
severity: ERROR
|
||||||
|
|
||||||
- id: frappe-sqli-format-strings
|
|
||||||
patterns:
|
|
||||||
- pattern-inside: |
|
|
||||||
@frappe.whitelist()
|
|
||||||
def $FUNC(...):
|
|
||||||
...
|
|
||||||
- pattern-either:
|
|
||||||
- pattern: frappe.db.sql("..." % ...)
|
|
||||||
- pattern: frappe.db.sql(f"...", ...)
|
|
||||||
- pattern: frappe.db.sql("...".format(...), ...)
|
|
||||||
message: |
|
|
||||||
Detected use of raw string formatting for SQL queries. This can lead to sql injection vulnerabilities. Refer security guidelines - https://github.com/frappe/erpnext/wiki/Code-Security-Guidelines
|
|
||||||
languages: [python]
|
|
||||||
severity: WARNING
|
|
||||||
|
@ -99,7 +99,6 @@ class ReceivablePayableReport(object):
|
|||||||
voucher_no = gle.voucher_no,
|
voucher_no = gle.voucher_no,
|
||||||
party = gle.party,
|
party = gle.party,
|
||||||
posting_date = gle.posting_date,
|
posting_date = gle.posting_date,
|
||||||
remarks = gle.remarks,
|
|
||||||
account_currency = gle.account_currency,
|
account_currency = gle.account_currency,
|
||||||
invoiced = 0.0,
|
invoiced = 0.0,
|
||||||
paid = 0.0,
|
paid = 0.0,
|
||||||
@ -579,7 +578,7 @@ class ReceivablePayableReport(object):
|
|||||||
self.gl_entries = frappe.db.sql("""
|
self.gl_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
|
name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
|
||||||
against_voucher_type, against_voucher, account_currency, remarks, {0}
|
against_voucher_type, against_voucher, account_currency, {0}
|
||||||
from
|
from
|
||||||
`tabGL Entry`
|
`tabGL Entry`
|
||||||
where
|
where
|
||||||
@ -792,8 +791,6 @@ class ReceivablePayableReport(object):
|
|||||||
self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
|
self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
|
||||||
options='Supplier Group')
|
options='Supplier Group')
|
||||||
|
|
||||||
self.add_column(label=_('Remarks'), fieldname='remarks', fieldtype='Text', width=200)
|
|
||||||
|
|
||||||
def add_column(self, label, fieldname=None, fieldtype='Currency', options=None, width=120):
|
def add_column(self, label, fieldname=None, fieldtype='Currency', options=None, width=120):
|
||||||
if not fieldname: fieldname = scrub(label)
|
if not fieldname: fieldname = scrub(label)
|
||||||
if fieldtype=='Currency': options='currency'
|
if fieldtype=='Currency': options='currency'
|
||||||
|
@ -241,6 +241,7 @@ class GrossProfitGenerator(object):
|
|||||||
sle.voucher_detail_no == row.item_row:
|
sle.voucher_detail_no == row.item_row:
|
||||||
previous_stock_value = len(my_sle) > i+1 and \
|
previous_stock_value = len(my_sle) > i+1 and \
|
||||||
flt(my_sle[i+1].stock_value) or 0.0
|
flt(my_sle[i+1].stock_value) or 0.0
|
||||||
|
|
||||||
if previous_stock_value:
|
if previous_stock_value:
|
||||||
return (previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty))
|
return (previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty))
|
||||||
else:
|
else:
|
||||||
@ -335,7 +336,7 @@ class GrossProfitGenerator(object):
|
|||||||
res = frappe.db.sql("""select item_code, voucher_type, voucher_no,
|
res = frappe.db.sql("""select item_code, voucher_type, voucher_no,
|
||||||
voucher_detail_no, stock_value, warehouse, actual_qty as qty
|
voucher_detail_no, stock_value, warehouse, actual_qty as qty
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where company=%(company)s
|
where company=%(company)s and is_cancelled = 0
|
||||||
order by
|
order by
|
||||||
item_code desc, warehouse desc, posting_date desc,
|
item_code desc, warehouse desc, posting_date desc,
|
||||||
posting_time desc, creation desc""", self.filters, as_dict=True)
|
posting_time desc, creation desc""", self.filters, as_dict=True)
|
||||||
|
@ -1112,8 +1112,11 @@ class AccountsController(TransactionBase):
|
|||||||
for d in self.get("payment_schedule"):
|
for d in self.get("payment_schedule"):
|
||||||
if d.invoice_portion:
|
if d.invoice_portion:
|
||||||
d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
|
d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
|
||||||
d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
|
d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('base_payment_amount'))
|
||||||
d.outstanding = d.payment_amount
|
d.outstanding = d.payment_amount
|
||||||
|
elif not d.invoice_portion:
|
||||||
|
d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_payment_amount'))
|
||||||
|
|
||||||
|
|
||||||
def set_due_date(self):
|
def set_due_date(self):
|
||||||
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
||||||
|
@ -407,6 +407,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
|
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
|
||||||
where
|
where
|
||||||
batch.disabled = 0
|
batch.disabled = 0
|
||||||
|
and sle.is_cancelled = 0
|
||||||
and sle.item_code = %(item_code)s
|
and sle.item_code = %(item_code)s
|
||||||
and sle.warehouse = %(warehouse)s
|
and sle.warehouse = %(warehouse)s
|
||||||
and (sle.batch_no like %(txt)s
|
and (sle.batch_no like %(txt)s
|
||||||
|
@ -53,12 +53,17 @@ class StockController(AccountsController):
|
|||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if hasattr(d, 'serial_no') and hasattr(d, 'batch_no') and d.serial_no and d.batch_no:
|
if hasattr(d, 'serial_no') and hasattr(d, 'batch_no') and d.serial_no and d.batch_no:
|
||||||
serial_nos = get_serial_nos(d.serial_no)
|
serial_nos = frappe.get_all("Serial No",
|
||||||
for serial_no_data in frappe.get_all("Serial No",
|
fields=["batch_no", "name", "warehouse"],
|
||||||
filters={"name": ("in", serial_nos)}, fields=["batch_no", "name"]):
|
filters={
|
||||||
if serial_no_data.batch_no != d.batch_no:
|
"name": ("in", get_serial_nos(d.serial_no))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in serial_nos:
|
||||||
|
if row.warehouse and row.batch_no != d.batch_no:
|
||||||
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
|
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
|
||||||
.format(d.idx, serial_no_data.name, d.batch_no))
|
.format(d.idx, row.name, d.batch_no))
|
||||||
|
|
||||||
if flt(d.qty) > 0.0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
|
if flt(d.qty) > 0.0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
|
||||||
expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
|
expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
|
||||||
|
@ -24,7 +24,8 @@ doctype_js = {
|
|||||||
"Address": "public/js/address.js",
|
"Address": "public/js/address.js",
|
||||||
"Communication": "public/js/communication.js",
|
"Communication": "public/js/communication.js",
|
||||||
"Event": "public/js/event.js",
|
"Event": "public/js/event.js",
|
||||||
"Newsletter": "public/js/newsletter.js"
|
"Newsletter": "public/js/newsletter.js",
|
||||||
|
"Contact": "public/js/contact.js"
|
||||||
}
|
}
|
||||||
|
|
||||||
override_doctype_class = {
|
override_doctype_class = {
|
||||||
|
@ -9,7 +9,7 @@ from frappe.utils import flt, getdate
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.hr.utils import set_employee_name
|
from erpnext.hr.utils import set_employee_name, validate_active_employee
|
||||||
|
|
||||||
class Appraisal(Document):
|
class Appraisal(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -19,6 +19,7 @@ class Appraisal(Document):
|
|||||||
if not self.goals:
|
if not self.goals:
|
||||||
frappe.throw(_("Goals cannot be empty"))
|
frappe.throw(_("Goals cannot be empty"))
|
||||||
|
|
||||||
|
validate_active_employee(self.employee)
|
||||||
set_employee_name(self)
|
set_employee_name(self)
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.validate_existing_appraisal()
|
self.validate_existing_appraisal()
|
||||||
|
@ -8,11 +8,13 @@ from frappe.utils import getdate, nowdate
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cstr, get_datetime, formatdate
|
from frappe.utils import cstr, get_datetime, formatdate
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class Attendance(Document):
|
class Attendance(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
from erpnext.controllers.status_updater import validate_status
|
from erpnext.controllers.status_updater import validate_status
|
||||||
validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
|
validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_attendance_date()
|
self.validate_attendance_date()
|
||||||
self.validate_duplicate_record()
|
self.validate_duplicate_record()
|
||||||
self.validate_employee_status()
|
self.validate_employee_status()
|
||||||
|
@ -8,10 +8,11 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import date_diff, add_days, getdate
|
from frappe.utils import date_diff, add_days, getdate
|
||||||
from erpnext.hr.doctype.employee.employee import is_holiday
|
from erpnext.hr.doctype.employee.employee import is_holiday
|
||||||
from erpnext.hr.utils import validate_dates
|
from erpnext.hr.utils import validate_dates, validate_active_employee
|
||||||
|
|
||||||
class AttendanceRequest(Document):
|
class AttendanceRequest(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
validate_dates(self, self.from_date, self.to_date)
|
validate_dates(self, self.from_date, self.to_date)
|
||||||
if self.half_day:
|
if self.half_day:
|
||||||
if not getdate(self.from_date)<=getdate(self.half_day_date)<=getdate(self.to_date):
|
if not getdate(self.from_date)<=getdate(self.half_day_date)<=getdate(self.to_date):
|
||||||
|
@ -7,12 +7,13 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import date_diff, add_days, getdate, cint, format_date
|
from frappe.utils import date_diff, add_days, getdate, cint, format_date
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, \
|
from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, validate_active_employee, \
|
||||||
get_holidays_for_employee, create_additional_leave_ledger_entry
|
get_holidays_for_employee, create_additional_leave_ledger_entry
|
||||||
|
|
||||||
class CompensatoryLeaveRequest(Document):
|
class CompensatoryLeaveRequest(Document):
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
validate_dates(self, self.work_from_date, self.work_end_date)
|
validate_dates(self, self.work_from_date, self.work_end_date)
|
||||||
if self.half_day:
|
if self.half_day:
|
||||||
if not self.half_day_date:
|
if not self.half_day_date:
|
||||||
|
@ -13,8 +13,10 @@ from frappe.model.document import Document
|
|||||||
from erpnext.utilities.transaction_base import delete_events
|
from erpnext.utilities.transaction_base import delete_events
|
||||||
from frappe.utils.nestedset import NestedSet
|
from frappe.utils.nestedset import NestedSet
|
||||||
|
|
||||||
class EmployeeUserDisabledError(frappe.ValidationError): pass
|
class EmployeeUserDisabledError(frappe.ValidationError):
|
||||||
class EmployeeLeftValidationError(frappe.ValidationError): pass
|
pass
|
||||||
|
class InactiveEmployeeStatusError(frappe.ValidationError):
|
||||||
|
pass
|
||||||
|
|
||||||
class Employee(NestedSet):
|
class Employee(NestedSet):
|
||||||
nsm_parent_field = 'reports_to'
|
nsm_parent_field = 'reports_to'
|
||||||
@ -196,7 +198,7 @@ class Employee(NestedSet):
|
|||||||
message += "<br><br><ul><li>" + "</li><li>".join(link_to_employees)
|
message += "<br><br><ul><li>" + "</li><li>".join(link_to_employees)
|
||||||
message += "</li></ul><br>"
|
message += "</li></ul><br>"
|
||||||
message += _("Please make sure the employees above report to another Active employee.")
|
message += _("Please make sure the employees above report to another Active employee.")
|
||||||
throw(message, EmployeeLeftValidationError, _("Cannot Relieve Employee"))
|
throw(message, InactiveEmployeeStatusError, _("Cannot Relieve Employee"))
|
||||||
if not self.relieving_date:
|
if not self.relieving_date:
|
||||||
throw(_("Please enter relieving date."))
|
throw(_("Please enter relieving date."))
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import frappe
|
|||||||
import erpnext
|
import erpnext
|
||||||
import unittest
|
import unittest
|
||||||
import frappe.utils
|
import frappe.utils
|
||||||
from erpnext.hr.doctype.employee.employee import EmployeeLeftValidationError
|
from erpnext.hr.doctype.employee.employee import InactiveEmployeeStatusError
|
||||||
|
|
||||||
test_records = frappe.get_test_records('Employee')
|
test_records = frappe.get_test_records('Employee')
|
||||||
|
|
||||||
@ -45,10 +45,33 @@ class TestEmployee(unittest.TestCase):
|
|||||||
employee2_doc.save()
|
employee2_doc.save()
|
||||||
employee1_doc.reload()
|
employee1_doc.reload()
|
||||||
employee1_doc.status = 'Left'
|
employee1_doc.status = 'Left'
|
||||||
self.assertRaises(EmployeeLeftValidationError, employee1_doc.save)
|
self.assertRaises(InactiveEmployeeStatusError, employee1_doc.save)
|
||||||
|
|
||||||
|
def test_employee_status_inactive(self):
|
||||||
|
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
|
||||||
|
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
|
||||||
|
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
|
||||||
|
|
||||||
|
employee = make_employee("test_employee_status@company.com")
|
||||||
|
employee_doc = frappe.get_doc("Employee", employee)
|
||||||
|
employee_doc.status = "Inactive"
|
||||||
|
employee_doc.save()
|
||||||
|
employee_doc.reload()
|
||||||
|
|
||||||
|
make_holiday_list()
|
||||||
|
frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List")
|
||||||
|
|
||||||
|
frappe.db.sql("""delete from `tabSalary Structure` where name='Test Inactive Employee Salary Slip'""")
|
||||||
|
salary_structure = make_salary_structure("Test Inactive Employee Salary Slip", "Monthly",
|
||||||
|
employee=employee_doc.name, company=employee_doc.company)
|
||||||
|
salary_slip = make_salary_slip(salary_structure.name, employee=employee_doc.name)
|
||||||
|
|
||||||
|
self.assertRaises(InactiveEmployeeStatusError, salary_slip.save)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
frappe.db.rollback()
|
||||||
|
|
||||||
def make_employee(user, company=None, **kwargs):
|
def make_employee(user, company=None, **kwargs):
|
||||||
""
|
|
||||||
if not frappe.db.get_value("User", user):
|
if not frappe.db.get_value("User", user):
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
"doctype": "User",
|
"doctype": "User",
|
||||||
@ -80,4 +103,5 @@ def make_employee(user, company=None, **kwargs):
|
|||||||
employee.insert()
|
employee.insert()
|
||||||
return employee.name
|
return employee.name
|
||||||
else:
|
else:
|
||||||
|
frappe.db.set_value("Employee", {"employee_name":user}, "status", "Active")
|
||||||
return frappe.get_value("Employee", {"employee_name":user}, "name")
|
return frappe.get_value("Employee", {"employee_name":user}, "name")
|
||||||
|
@ -8,6 +8,7 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import flt, nowdate
|
from frappe.utils import flt, nowdate
|
||||||
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class EmployeeAdvanceOverPayment(frappe.ValidationError):
|
class EmployeeAdvanceOverPayment(frappe.ValidationError):
|
||||||
pass
|
pass
|
||||||
@ -18,6 +19,7 @@ class EmployeeAdvance(Document):
|
|||||||
'make_payment_via_journal_entry')
|
'make_payment_via_journal_entry')
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.set_status()
|
self.set_status()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
@ -9,9 +9,11 @@ from frappe.model.document import Document
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift
|
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class EmployeeCheckin(Document):
|
class EmployeeCheckin(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_duplicate_log()
|
self.validate_duplicate_log()
|
||||||
self.fetch_shift()
|
self.fetch_shift()
|
||||||
|
|
||||||
|
@ -7,12 +7,11 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
from erpnext.hr.utils import update_employee
|
from erpnext.hr.utils import update_employee, validate_active_employee
|
||||||
|
|
||||||
class EmployeePromotion(Document):
|
class EmployeePromotion(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if frappe.get_value("Employee", self.employee, "status") != "Active":
|
validate_active_employee(self.employee)
|
||||||
frappe.throw(_("Cannot promote Employee with status Left or Inactive"))
|
|
||||||
|
|
||||||
def before_submit(self):
|
def before_submit(self):
|
||||||
if getdate(self.promotion_date) > getdate():
|
if getdate(self.promotion_date) > getdate():
|
||||||
|
@ -7,9 +7,11 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import get_link_to_form
|
from frappe.utils import get_link_to_form
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class EmployeeReferral(Document):
|
class EmployeeReferral(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.referrer)
|
||||||
self.set_full_name()
|
self.set_full_name()
|
||||||
self.set_referral_bonus_payment_status()
|
self.set_referral_bonus_payment_status()
|
||||||
|
|
||||||
|
@ -10,10 +10,6 @@ from frappe.utils import getdate
|
|||||||
from erpnext.hr.utils import update_employee
|
from erpnext.hr.utils import update_employee
|
||||||
|
|
||||||
class EmployeeTransfer(Document):
|
class EmployeeTransfer(Document):
|
||||||
def validate(self):
|
|
||||||
if frappe.get_value("Employee", self.employee, "status") != "Active":
|
|
||||||
frappe.throw(_("Cannot transfer Employee with status Left or Inactive"))
|
|
||||||
|
|
||||||
def before_submit(self):
|
def before_submit(self):
|
||||||
if getdate(self.transfer_date) > getdate():
|
if getdate(self.transfer_date) > getdate():
|
||||||
frappe.throw(_("Employee Transfer cannot be submitted before Transfer Date"),
|
frappe.throw(_("Employee Transfer cannot be submitted before Transfer Date"),
|
||||||
|
@ -6,7 +6,7 @@ import frappe, erpnext
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import get_fullname, flt, cstr, get_link_to_form
|
from frappe.utils import get_fullname, flt, cstr, get_link_to_form
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.hr.utils import set_employee_name, share_doc_with_approver
|
from erpnext.hr.utils import set_employee_name, share_doc_with_approver, validate_active_employee
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
|
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
|
||||||
@ -23,6 +23,7 @@ class ExpenseClaim(AccountsController):
|
|||||||
'make_payment_via_journal_entry')
|
'make_payment_via_journal_entry')
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_advances()
|
self.validate_advances()
|
||||||
self.validate_sanctioned_amount()
|
self.validate_sanctioned_amount()
|
||||||
self.calculate_total_amount()
|
self.calculate_total_amount()
|
||||||
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, get_fullname, add_days, nowdate
|
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, get_fullname, add_days, nowdate
|
||||||
from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver
|
from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver, validate_active_employee
|
||||||
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
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
|
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
|
||||||
@ -22,6 +22,7 @@ class LeaveApplication(Document):
|
|||||||
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
|
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
set_employee_name(self)
|
set_employee_name(self)
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.validate_balance_leaves()
|
self.validate_balance_leaves()
|
||||||
|
@ -7,7 +7,7 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import getdate, nowdate, flt
|
from frappe.utils import getdate, nowdate, flt
|
||||||
from erpnext.hr.utils import set_employee_name
|
from erpnext.hr.utils import set_employee_name, validate_active_employee
|
||||||
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
||||||
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
|
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
|
||||||
from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves
|
from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves
|
||||||
@ -15,6 +15,7 @@ from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leav
|
|||||||
class LeaveEncashment(Document):
|
class LeaveEncashment(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
set_employee_name(self)
|
set_employee_name(self)
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.get_leave_details_for_encashment()
|
self.get_leave_details_for_encashment()
|
||||||
self.validate_salary_structure()
|
self.validate_salary_structure()
|
||||||
|
|
||||||
|
@ -9,10 +9,12 @@ from frappe.model.document import Document
|
|||||||
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, now_datetime, nowdate
|
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, now_datetime, nowdate
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
class ShiftAssignment(Document):
|
class ShiftAssignment(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_overlapping_dates()
|
self.validate_overlapping_dates()
|
||||||
|
|
||||||
if self.end_date and self.end_date <= self.start_date:
|
if self.end_date and self.end_date <= self.start_date:
|
||||||
|
@ -7,12 +7,13 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import formatdate, getdate
|
from frappe.utils import formatdate, getdate
|
||||||
from erpnext.hr.utils import share_doc_with_approver
|
from erpnext.hr.utils import share_doc_with_approver, validate_active_employee
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
class OverlapError(frappe.ValidationError): pass
|
||||||
|
|
||||||
class ShiftRequest(Document):
|
class ShiftRequest(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.validate_shift_request_overlap_dates()
|
self.validate_shift_request_overlap_dates()
|
||||||
self.validate_approver()
|
self.validate_approver()
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class TravelRequest(Document):
|
class TravelRequest(Document):
|
||||||
pass
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
import frappe
|
import frappe
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee, InactiveEmployeeStatusError
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.desk.form import assign_to
|
from frappe.desk.form import assign_to
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import (add_days, cstr, flt, format_datetime, formatdate,
|
from frappe.utils import (add_days, cstr, flt, format_datetime, formatdate,
|
||||||
get_datetime, getdate, nowdate, today, unique)
|
get_datetime, getdate, nowdate, today, unique, get_link_to_form)
|
||||||
|
|
||||||
|
|
||||||
class DuplicateDeclarationError(frappe.ValidationError): pass
|
class DuplicateDeclarationError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@ -20,6 +19,7 @@ class EmployeeBoardingController(Document):
|
|||||||
Assign to the concerned person and roles as per the onboarding/separation template
|
Assign to the concerned person and roles as per the onboarding/separation template
|
||||||
'''
|
'''
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
# remove the task if linked before submitting the form
|
# remove the task if linked before submitting the form
|
||||||
if self.amended_from:
|
if self.amended_from:
|
||||||
for activity in self.activities:
|
for activity in self.activities:
|
||||||
@ -522,3 +522,8 @@ def share_doc_with_approver(doc, user):
|
|||||||
approver = approvers.get(doc.doctype)
|
approver = approvers.get(doc.doctype)
|
||||||
if doc_before_save.get(approver) != doc.get(approver):
|
if doc_before_save.get(approver) != doc.get(approver):
|
||||||
frappe.share.remove(doc.doctype, doc.name, doc_before_save.get(approver))
|
frappe.share.remove(doc.doctype, doc.name, doc_before_save.get(approver))
|
||||||
|
|
||||||
|
def validate_active_employee(employee):
|
||||||
|
if frappe.db.get_value("Employee", employee, "status") == "Inactive":
|
||||||
|
frappe.throw(_("Transactions cannot be created for an Inactive Employee {0}.").format(
|
||||||
|
get_link_to_form("Employee", employee)), InactiveEmployeeStatusError)
|
@ -83,7 +83,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
|
|
||||||
if (!frm.doc.__islocal && frm.doc.docstatus<2) {
|
if (!frm.doc.__islocal && frm.doc.docstatus<2) {
|
||||||
frm.add_custom_button(__("Update Cost"), function() {
|
frm.add_custom_button(__("Update Cost"), function() {
|
||||||
frm.events.update_cost(frm);
|
frm.events.update_cost(frm, true);
|
||||||
});
|
});
|
||||||
frm.add_custom_button(__("Browse BOM"), function() {
|
frm.add_custom_button(__("Browse BOM"), function() {
|
||||||
frappe.route_options = {
|
frappe.route_options = {
|
||||||
@ -318,14 +318,15 @@ frappe.ui.form.on("BOM", {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
update_cost: function(frm) {
|
update_cost: function(frm, save_doc=false) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
method: "update_cost",
|
method: "update_cost",
|
||||||
freeze: true,
|
freeze: true,
|
||||||
args: {
|
args: {
|
||||||
update_parent: true,
|
update_parent: true,
|
||||||
from_child_bom:false
|
save: save_doc,
|
||||||
|
from_child_bom: false
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
refresh_field("items");
|
refresh_field("items");
|
||||||
|
@ -330,7 +330,7 @@ class BOM(WebsiteGenerator):
|
|||||||
frappe.get_doc("BOM", bom).update_cost(from_child_bom=True)
|
frappe.get_doc("BOM", bom).update_cost(from_child_bom=True)
|
||||||
|
|
||||||
if not from_child_bom:
|
if not from_child_bom:
|
||||||
frappe.msgprint(_("Cost Updated"))
|
frappe.msgprint(_("Cost Updated"), alert=True)
|
||||||
|
|
||||||
def update_parent_cost(self):
|
def update_parent_cost(self):
|
||||||
if self.total_cost:
|
if self.total_cost:
|
||||||
@ -748,7 +748,7 @@ def get_valuation_rate(args):
|
|||||||
if valuation_rate <= 0:
|
if valuation_rate <= 0:
|
||||||
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where item_code = %s and valuation_rate > 0
|
where item_code = %s and valuation_rate > 0 and is_cancelled = 0
|
||||||
order by posting_date desc, posting_time desc, creation desc limit 1""", args['item_code'])
|
order by posting_date desc, posting_time desc, creation desc limit 1""", args['item_code'])
|
||||||
|
|
||||||
valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0
|
valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0
|
||||||
|
@ -747,9 +747,8 @@ def get_bin_details(row, company, for_warehouse=None, all_warehouse=False):
|
|||||||
group by item_code, warehouse
|
group by item_code, warehouse
|
||||||
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
|
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
|
||||||
|
|
||||||
def get_warehouse_list(warehouses, warehouse_list=None):
|
def get_warehouse_list(warehouses):
|
||||||
if not warehouse_list:
|
warehouse_list = []
|
||||||
warehouse_list = []
|
|
||||||
|
|
||||||
if isinstance(warehouses, str):
|
if isinstance(warehouses, str):
|
||||||
warehouses = json.loads(warehouses)
|
warehouses = json.loads(warehouses)
|
||||||
@ -761,23 +760,19 @@ def get_warehouse_list(warehouses, warehouse_list=None):
|
|||||||
else:
|
else:
|
||||||
warehouse_list.append(row.get("warehouse"))
|
warehouse_list.append(row.get("warehouse"))
|
||||||
|
|
||||||
|
return warehouse_list
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_data=None):
|
def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_data=None):
|
||||||
if isinstance(doc, str):
|
if isinstance(doc, str):
|
||||||
doc = frappe._dict(json.loads(doc))
|
doc = frappe._dict(json.loads(doc))
|
||||||
|
|
||||||
warehouse_list = []
|
|
||||||
if warehouses:
|
if warehouses:
|
||||||
get_warehouse_list(warehouses, warehouse_list)
|
warehouses = list(set(get_warehouse_list(warehouses)))
|
||||||
|
|
||||||
if warehouse_list:
|
|
||||||
warehouses = list(set(warehouse_list))
|
|
||||||
|
|
||||||
if doc.get("for_warehouse") and not get_parent_warehouse_data and doc.get("for_warehouse") in warehouses:
|
if doc.get("for_warehouse") and not get_parent_warehouse_data and doc.get("for_warehouse") in warehouses:
|
||||||
warehouses.remove(doc.get("for_warehouse"))
|
warehouses.remove(doc.get("for_warehouse"))
|
||||||
|
|
||||||
warehouse_list = None
|
|
||||||
|
|
||||||
doc['mr_items'] = []
|
doc['mr_items'] = []
|
||||||
|
|
||||||
po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
|
po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
|
||||||
|
@ -10,7 +10,7 @@ from erpnext.stock.doctype.item.test_item import create_item
|
|||||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
|
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
|
||||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
|
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests, get_warehouse_list
|
||||||
|
|
||||||
class TestProductionPlan(unittest.TestCase):
|
class TestProductionPlan(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -251,6 +251,27 @@ class TestProductionPlan(unittest.TestCase):
|
|||||||
pln.cancel()
|
pln.cancel()
|
||||||
frappe.delete_doc("Production Plan", pln.name)
|
frappe.delete_doc("Production Plan", pln.name)
|
||||||
|
|
||||||
|
def test_get_warehouse_list_group(self):
|
||||||
|
"""Check if required warehouses are returned"""
|
||||||
|
warehouse_json = '[{\"warehouse\":\"_Test Warehouse Group - _TC\"}]'
|
||||||
|
|
||||||
|
warehouses = set(get_warehouse_list(warehouse_json))
|
||||||
|
expected_warehouses = {"_Test Warehouse Group-C1 - _TC", "_Test Warehouse Group-C2 - _TC"}
|
||||||
|
|
||||||
|
missing_warehouse = expected_warehouses - warehouses
|
||||||
|
|
||||||
|
self.assertTrue(len(missing_warehouse) == 0,
|
||||||
|
msg=f"Following warehouses were expected {', '.join(missing_warehouse)}")
|
||||||
|
|
||||||
|
def test_get_warehouse_list_single(self):
|
||||||
|
warehouse_json = '[{\"warehouse\":\"_Test Scrap Warehouse - _TC\"}]'
|
||||||
|
|
||||||
|
warehouses = set(get_warehouse_list(warehouse_json))
|
||||||
|
expected_warehouses = {"_Test Scrap Warehouse - _TC", }
|
||||||
|
|
||||||
|
self.assertEqual(warehouses, expected_warehouses)
|
||||||
|
|
||||||
|
|
||||||
def create_production_plan(**args):
|
def create_production_plan(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
@ -487,21 +487,20 @@ class WorkOrder(Document):
|
|||||||
return
|
return
|
||||||
|
|
||||||
operations = []
|
operations = []
|
||||||
if not self.use_multi_level_bom:
|
|
||||||
bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
|
if self.use_multi_level_bom:
|
||||||
operations.extend(_get_operations(self.bom_no, qty=1.0/bom_qty))
|
|
||||||
else:
|
|
||||||
bom_tree = frappe.get_doc("BOM", self.bom_no).get_tree_representation()
|
bom_tree = frappe.get_doc("BOM", self.bom_no).get_tree_representation()
|
||||||
bom_traversal = list(reversed(bom_tree.level_order_traversal()))
|
bom_traversal = reversed(bom_tree.level_order_traversal())
|
||||||
bom_traversal.append(bom_tree) # add operation on top level item last
|
|
||||||
|
|
||||||
for d in bom_traversal:
|
for node in bom_traversal:
|
||||||
if d.is_bom:
|
if node.is_bom:
|
||||||
operations.extend(_get_operations(d.name, qty=d.exploded_qty))
|
operations.extend(_get_operations(node.name, qty=node.exploded_qty))
|
||||||
|
|
||||||
for correct_index, operation in enumerate(operations, start=1):
|
bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
|
||||||
operation.idx = correct_index
|
operations.extend(_get_operations(self.bom_no, qty=1.0/bom_qty))
|
||||||
|
|
||||||
|
for correct_index, operation in enumerate(operations, start=1):
|
||||||
|
operation.idx = correct_index
|
||||||
|
|
||||||
self.set('operations', operations)
|
self.set('operations', operations)
|
||||||
self.calculate_time()
|
self.calculate_time()
|
||||||
|
@ -7,6 +7,7 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _, bold
|
from frappe import _, bold
|
||||||
from frappe.utils import getdate, date_diff, comma_and, formatdate
|
from frappe.utils import getdate, date_diff, comma_and, formatdate
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class AdditionalSalary(Document):
|
class AdditionalSalary(Document):
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
@ -19,6 +20,7 @@ class AdditionalSalary(Document):
|
|||||||
self.update_employee_referral(cancel=True)
|
self.update_employee_referral(cancel=True)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.validate_salary_structure()
|
self.validate_salary_structure()
|
||||||
self.validate_recurring_additional_salary_overlap()
|
self.validate_recurring_additional_salary_overlap()
|
||||||
|
@ -9,10 +9,11 @@ from frappe.utils import date_diff, getdate, rounded, add_days, cstr, cint, flt
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.payroll.doctype.payroll_period.payroll_period import get_payroll_period_days, get_period_factor
|
from erpnext.payroll.doctype.payroll_period.payroll_period import get_payroll_period_days, get_period_factor
|
||||||
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
||||||
from erpnext.hr.utils import get_sal_slip_total_benefit_given, get_holidays_for_employee, get_previous_claimed_amount
|
from erpnext.hr.utils import get_sal_slip_total_benefit_given, get_holidays_for_employee, get_previous_claimed_amount, validate_active_employee
|
||||||
|
|
||||||
class EmployeeBenefitApplication(Document):
|
class EmployeeBenefitApplication(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_duplicate_on_payroll_period()
|
self.validate_duplicate_on_payroll_period()
|
||||||
if not self.max_benefits:
|
if not self.max_benefits:
|
||||||
self.max_benefits = get_max_benefits_remaining(self.employee, self.date, self.payroll_period)
|
self.max_benefits = get_max_benefits_remaining(self.employee, self.date, self.payroll_period)
|
||||||
|
@ -8,12 +8,13 @@ from frappe import _
|
|||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_max_benefits
|
from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_max_benefits
|
||||||
from erpnext.hr.utils import get_previous_claimed_amount
|
from erpnext.hr.utils import get_previous_claimed_amount, validate_active_employee
|
||||||
from erpnext.payroll.doctype.payroll_period.payroll_period import get_payroll_period
|
from erpnext.payroll.doctype.payroll_period.payroll_period import get_payroll_period
|
||||||
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
||||||
|
|
||||||
class EmployeeBenefitClaim(Document):
|
class EmployeeBenefitClaim(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
max_benefits = get_max_benefits(self.employee, self.claim_date)
|
max_benefits = get_max_benefits(self.employee, self.claim_date)
|
||||||
if not max_benefits or max_benefits <= 0:
|
if not max_benefits or max_benefits <= 0:
|
||||||
frappe.throw(_("Employee {0} has no maximum benefit amount").format(self.employee))
|
frappe.throw(_("Employee {0} has no maximum benefit amount").format(self.employee))
|
||||||
|
@ -6,9 +6,11 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class EmployeeIncentive(Document):
|
class EmployeeIncentive(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_salary_structure()
|
self.validate_salary_structure()
|
||||||
|
|
||||||
def validate_salary_structure(self):
|
def validate_salary_structure(self):
|
||||||
|
@ -8,11 +8,12 @@ from frappe.model.document import Document
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
|
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, validate_active_employee, \
|
||||||
calculate_annual_eligible_hra_exemption, validate_duplicate_exemption_for_payroll_period
|
calculate_annual_eligible_hra_exemption, validate_duplicate_exemption_for_payroll_period
|
||||||
|
|
||||||
class EmployeeTaxExemptionDeclaration(Document):
|
class EmployeeTaxExemptionDeclaration(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
validate_tax_declaration(self.declarations)
|
validate_tax_declaration(self.declarations)
|
||||||
validate_duplicate_exemption_for_payroll_period(self.doctype, self.name, self.payroll_period, self.employee)
|
validate_duplicate_exemption_for_payroll_period(self.doctype, self.name, self.payroll_period, self.employee)
|
||||||
self.set_total_declared_amount()
|
self.set_total_declared_amount()
|
||||||
|
@ -7,11 +7,12 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
|
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, validate_active_employee, \
|
||||||
calculate_hra_exemption_for_period, validate_duplicate_exemption_for_payroll_period
|
calculate_hra_exemption_for_period, validate_duplicate_exemption_for_payroll_period
|
||||||
|
|
||||||
class EmployeeTaxExemptionProofSubmission(Document):
|
class EmployeeTaxExemptionProofSubmission(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
validate_active_employee(self.employee)
|
||||||
validate_tax_declaration(self.tax_exemption_proofs)
|
validate_tax_declaration(self.tax_exemption_proofs)
|
||||||
self.set_total_actual_amount()
|
self.set_total_actual_amount()
|
||||||
self.set_total_exemption_amount()
|
self.set_total_exemption_amount()
|
||||||
|
@ -7,11 +7,10 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
class RetentionBonus(Document):
|
class RetentionBonus(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if frappe.get_value('Employee', self.employee, 'status') != 'Active':
|
validate_active_employee(self.employee)
|
||||||
frappe.throw(_('Cannot create Retention Bonus for Left or Inactive Employees'))
|
|
||||||
if getdate(self.bonus_payment_date) < getdate():
|
if getdate(self.bonus_payment_date) < getdate():
|
||||||
frappe.throw(_('Bonus Payment Date cannot be a past date'))
|
frappe.throw(_('Bonus Payment Date cannot be a past date'))
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_appli
|
|||||||
from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
|
from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
|
||||||
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts, create_repayment_entry
|
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts, create_repayment_entry
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
class SalarySlip(TransactionBase):
|
class SalarySlip(TransactionBase):
|
||||||
@ -39,6 +40,7 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.status = self.get_status()
|
self.status = self.get_status()
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.check_existing()
|
self.check_existing()
|
||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
|
@ -15,12 +15,15 @@ from erpnext.manufacturing.doctype.workstation.workstation import (check_if_with
|
|||||||
WorkstationHolidayError)
|
WorkstationHolidayError)
|
||||||
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
||||||
from erpnext.setup.utils import get_exchange_rate
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
|
from erpnext.hr.utils import validate_active_employee
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
class OverlapError(frappe.ValidationError): pass
|
||||||
class OverWorkLoggedError(frappe.ValidationError): pass
|
class OverWorkLoggedError(frappe.ValidationError): pass
|
||||||
|
|
||||||
class Timesheet(Document):
|
class Timesheet(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
if self.employee:
|
||||||
|
validate_active_employee(self.employee)
|
||||||
self.set_employee_name()
|
self.set_employee_name()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
|
16
erpnext/public/js/contact.js
Normal file
16
erpnext/public/js/contact.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
frappe.ui.form.on("Contact", {
|
||||||
|
refresh(frm) {
|
||||||
|
frm.set_query('link_doctype', "links", function() {
|
||||||
|
return {
|
||||||
|
query: "frappe.contacts.address_and_contact.filter_dynamic_link_doctypes",
|
||||||
|
filters: {
|
||||||
|
fieldtype: ["in", ["HTML", "Text Editor"]],
|
||||||
|
fieldname: ["in", ["contact_html", "company_description"]],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
frm.refresh_field("links");
|
||||||
|
}
|
||||||
|
});
|
@ -162,19 +162,19 @@ def get_batch_qty(batch_no=None, warehouse=None, item_code=None, posting_date=No
|
|||||||
|
|
||||||
out = float(frappe.db.sql("""select sum(actual_qty)
|
out = float(frappe.db.sql("""select sum(actual_qty)
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where warehouse=%s and batch_no=%s {0}""".format(cond),
|
where is_cancelled = 0 and warehouse=%s and batch_no=%s {0}""".format(cond),
|
||||||
(warehouse, batch_no))[0][0] or 0)
|
(warehouse, batch_no))[0][0] or 0)
|
||||||
|
|
||||||
if batch_no and not warehouse:
|
if batch_no and not warehouse:
|
||||||
out = frappe.db.sql('''select warehouse, sum(actual_qty) as qty
|
out = frappe.db.sql('''select warehouse, sum(actual_qty) as qty
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where batch_no=%s
|
where is_cancelled = 0 and batch_no=%s
|
||||||
group by warehouse''', batch_no, as_dict=1)
|
group by warehouse''', batch_no, as_dict=1)
|
||||||
|
|
||||||
if not batch_no and item_code and warehouse:
|
if not batch_no and item_code and warehouse:
|
||||||
out = frappe.db.sql('''select batch_no, sum(actual_qty) as qty
|
out = frappe.db.sql('''select batch_no, sum(actual_qty) as qty
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where item_code = %s and warehouse=%s
|
where is_cancelled = 0 and item_code = %s and warehouse=%s
|
||||||
group by batch_no''', (item_code, warehouse), as_dict=1)
|
group by batch_no''', (item_code, warehouse), as_dict=1)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
@ -239,6 +239,7 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
|
|||||||
and sle.`item_code`=%(item_code)s
|
and sle.`item_code`=%(item_code)s
|
||||||
and sle.`company` = %(company)s
|
and sle.`company` = %(company)s
|
||||||
and batch.disabled = 0
|
and batch.disabled = 0
|
||||||
|
and sle.is_cancelled=0
|
||||||
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
||||||
{warehouse_condition}
|
{warehouse_condition}
|
||||||
GROUP BY
|
GROUP BY
|
||||||
|
@ -1789,7 +1789,7 @@ def get_expired_batch_items():
|
|||||||
from `tabBatch` b, `tabStock Ledger Entry` sle
|
from `tabBatch` b, `tabStock Ledger Entry` sle
|
||||||
where b.expiry_date <= %s
|
where b.expiry_date <= %s
|
||||||
and b.expiry_date is not NULL
|
and b.expiry_date is not NULL
|
||||||
and b.batch_id = sle.batch_no
|
and b.batch_id = sle.batch_no and sle.is_cancelled = 0
|
||||||
group by sle.warehouse, sle.item_code, sle.batch_no""",(nowdate()), as_dict=1)
|
group by sle.warehouse, sle.item_code, sle.batch_no""",(nowdate()), as_dict=1)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -60,7 +60,7 @@ class StockLedgerEntry(Document):
|
|||||||
if self.batch_no and not self.get("allow_negative_stock"):
|
if self.batch_no and not self.get("allow_negative_stock"):
|
||||||
batch_bal_after_transaction = flt(frappe.db.sql("""select sum(actual_qty)
|
batch_bal_after_transaction = flt(frappe.db.sql("""select sum(actual_qty)
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where warehouse=%s and item_code=%s and batch_no=%s""",
|
where is_cancelled =0 and warehouse=%s and item_code=%s and batch_no=%s""",
|
||||||
(self.warehouse, self.item_code, self.batch_no))[0][0])
|
(self.warehouse, self.item_code, self.batch_no))[0][0])
|
||||||
|
|
||||||
if batch_bal_after_transaction < 0:
|
if batch_bal_after_transaction < 0:
|
||||||
@ -152,7 +152,7 @@ class StockLedgerEntry(Document):
|
|||||||
last_transaction_time = frappe.db.sql("""
|
last_transaction_time = frappe.db.sql("""
|
||||||
select MAX(timestamp(posting_date, posting_time)) as posting_time
|
select MAX(timestamp(posting_date, posting_time)) as posting_time
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where docstatus = 1 and item_code = %s
|
where docstatus = 1 and is_cancelled = 0 and item_code = %s
|
||||||
and warehouse = %s""", (self.item_code, self.warehouse))[0][0]
|
and warehouse = %s""", (self.item_code, self.warehouse))[0][0]
|
||||||
|
|
||||||
cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
|
cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
|
||||||
|
@ -69,7 +69,7 @@ def get_consumed_details(filters):
|
|||||||
i.stock_uom, sle.actual_qty, sle.stock_value_difference,
|
i.stock_uom, sle.actual_qty, sle.stock_value_difference,
|
||||||
sle.voucher_no, sle.voucher_type
|
sle.voucher_no, sle.voucher_type
|
||||||
from `tabStock Ledger Entry` sle, `tabItem` i
|
from `tabStock Ledger Entry` sle, `tabItem` i
|
||||||
where sle.item_code=i.name and sle.actual_qty < 0 %s""" % conditions, values, as_dict=1):
|
where sle.is_cancelled = 0 and sle.item_code=i.name and sle.actual_qty < 0 %s""" % conditions, values, as_dict=1):
|
||||||
consumed_details.setdefault(d.item_code, []).append(d)
|
consumed_details.setdefault(d.item_code, []).append(d)
|
||||||
|
|
||||||
return consumed_details
|
return consumed_details
|
||||||
|
Loading…
x
Reference in New Issue
Block a user