Merge branch 'hotfix'
This commit is contained in:
commit
94704beba3
@ -4,7 +4,7 @@ import inspect
|
||||
import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
|
||||
__version__ = '9.2.12'
|
||||
__version__ = '9.2.13'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
@ -200,9 +200,6 @@ def get_party_account(party_type, party, company):
|
||||
if (account and account_currency != existing_gle_currency) or not account:
|
||||
account = get_party_gle_account(party_type, party, company)
|
||||
|
||||
if not account:
|
||||
frappe.throw(_("Party account not specified, please setup default party account in company"))
|
||||
|
||||
return account
|
||||
|
||||
def get_party_account_currency(party_type, party, company):
|
||||
|
@ -8,12 +8,12 @@ from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import getdate
|
||||
import json
|
||||
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account,get_income_account
|
||||
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
|
||||
|
||||
class Consultation(Document):
|
||||
def on_update(self):
|
||||
if(self.appointment):
|
||||
frappe.db.set_value("Patient Appointment",self.appointment,"status","Closed")
|
||||
frappe.db.set_value("Patient Appointment", self.appointment, "status", "Closed")
|
||||
update_consultation_to_medical_record(self)
|
||||
|
||||
def after_insert(self):
|
||||
@ -23,9 +23,10 @@ class Consultation(Document):
|
||||
if not self.diagnosis or not self.symptoms:
|
||||
frappe.throw("Diagnosis and Complaints cannot be left blank")
|
||||
|
||||
physician = frappe.get_doc("Physician",self.physician)
|
||||
if(frappe.session.user != physician.user_id):
|
||||
frappe.throw(_("You don't have permission to submit"))
|
||||
def on_cancel(self):
|
||||
if(self.appointment):
|
||||
frappe.db.set_value("Patient Appointment", self.appointment, "status", "Open")
|
||||
delete_medical_record(self)
|
||||
|
||||
def set_sales_invoice_fields(company, patient):
|
||||
sales_invoice = frappe.new_doc("Sales Invoice")
|
||||
@ -91,8 +92,8 @@ def create_invoice_items(physician, invoice, company):
|
||||
item_line.qty = 1
|
||||
item_line.uom = "Nos"
|
||||
item_line.conversion_factor = 1
|
||||
item_line.income_account = get_income_account(physician,company)
|
||||
op_consulting_charge = frappe.get_value("Physician",physician,"op_consulting_charge")
|
||||
item_line.income_account = get_income_account(physician, company)
|
||||
op_consulting_charge = frappe.get_value("Physician", physician, "op_consulting_charge")
|
||||
if op_consulting_charge:
|
||||
item_line.rate = op_consulting_charge
|
||||
item_line.amount = op_consulting_charge
|
||||
@ -111,10 +112,13 @@ def insert_consultation_to_medical_record(doc):
|
||||
medical_record.save(ignore_permissions=True)
|
||||
|
||||
def update_consultation_to_medical_record(consultation):
|
||||
medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s",(consultation.name))
|
||||
medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s", (consultation.name))
|
||||
if(medical_record_id[0][0]):
|
||||
subject = set_subject_field(consultation)
|
||||
frappe.db.set_value("Patient Medical Record",medical_record_id[0][0],"subject",subject)
|
||||
frappe.db.set_value("Patient Medical Record", medical_record_id[0][0], "subject", subject)
|
||||
|
||||
def delete_medical_record(consultation):
|
||||
frappe.db.sql("""delete from `tabPatient Medical Record` where reference_name = %s""", (consultation.name))
|
||||
|
||||
def set_subject_field(consultation):
|
||||
subject = "No Diagnosis "
|
||||
|
@ -9,6 +9,7 @@ frappe.ui.form.on('Healthcare Settings', {
|
||||
filters: {
|
||||
'account_type': 'Receivable',
|
||||
'company': d.company,
|
||||
'is_group': 0
|
||||
}
|
||||
};
|
||||
});
|
||||
@ -18,6 +19,7 @@ frappe.ui.form.on('Healthcare Settings', {
|
||||
filters: {
|
||||
'root_type': 'Income',
|
||||
'company': d.company,
|
||||
'is_group': 0
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -11,8 +11,8 @@ def get_data():
|
||||
'items': ['Patient Appointment', 'Consultation']
|
||||
},
|
||||
{
|
||||
'label': _('Lab Tests'),
|
||||
'items': ['Lab Test']
|
||||
'label': _('Lab Tests and Vital Signs'),
|
||||
'items': ['Lab Test', 'Vital Signs']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -25,6 +25,14 @@ frappe.ui.form.on('Patient Appointment', {
|
||||
frm.add_custom_button(__('Cancel'), function() {
|
||||
btn_update_status(frm, "Cancelled");
|
||||
});
|
||||
|
||||
frm.add_custom_button(__("Consultation"),function(){
|
||||
btn_create_consultation(frm);
|
||||
},"Create");
|
||||
|
||||
frm.add_custom_button(__('Vital Signs'), function() {
|
||||
btn_create_vital_signs(frm);
|
||||
},"Create");
|
||||
}
|
||||
if(frm.doc.status == "Scheduled" && !frm.doc.__islocal){
|
||||
frm.add_custom_button(__('Cancel'), function() {
|
||||
|
@ -56,7 +56,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Patient",
|
||||
"length": 0,
|
||||
@ -174,7 +174,7 @@
|
||||
"ignore_xss_filter": 1,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Subject",
|
||||
"length": 0,
|
||||
@ -236,7 +236,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Datetime",
|
||||
"length": 0,
|
||||
@ -266,7 +266,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference DocType",
|
||||
"length": 0,
|
||||
@ -297,7 +297,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference Name",
|
||||
"length": 0,
|
||||
@ -389,7 +389,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-10-04 16:09:55.597866",
|
||||
"modified": "2017-11-15 12:48:59.945615",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Patient Medical Record",
|
||||
@ -425,6 +425,7 @@
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "patient",
|
||||
"track_changes": 1,
|
||||
"track_seen": 1
|
||||
}
|
@ -9,6 +9,7 @@ frappe.ui.form.on('Physician', {
|
||||
filters: {
|
||||
'root_type': 'Income',
|
||||
'company': d.company,
|
||||
'is_group': 0
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ frappe.ui.form.on('Physician Schedule', {
|
||||
|
||||
while(cur_time < end_time) {
|
||||
let to_time = cur_time.clone().add(values.duration, 'minutes');
|
||||
if(to_time < end_time) {
|
||||
if(to_time <= end_time) {
|
||||
|
||||
// add a new timeslot
|
||||
frm.add_child('time_slots', {
|
||||
|
@ -38,9 +38,8 @@ class TestEmployeeLoan(unittest.TestCase):
|
||||
self.assertEquals(employee_loan.total_interest_payable, 22712)
|
||||
self.assertEquals(employee_loan.total_payment, 302712)
|
||||
|
||||
|
||||
def create_loan_type(loan_name, maximum_loan_amount, rate_of_interest):
|
||||
if not frappe.db.get_value("Loan Type", loan_name):
|
||||
if not frappe.db.exists("Loan Type", loan_name):
|
||||
frappe.get_doc({
|
||||
"doctype": "Loan Type",
|
||||
"loan_name": loan_name,
|
||||
@ -49,6 +48,7 @@ def create_loan_type(loan_name, maximum_loan_amount, rate_of_interest):
|
||||
}).insert()
|
||||
|
||||
def create_employee_loan(employee, loan_type, loan_amount, repayment_method, repayment_periods):
|
||||
create_loan_type(loan_type, 500000, 8.4)
|
||||
if not frappe.db.get_value("Employee Loan", {"employee":employee}):
|
||||
employee_loan = frappe.new_doc("Employee Loan")
|
||||
employee_loan.update({
|
||||
|
@ -190,23 +190,28 @@ class ProcessPayroll(Document):
|
||||
def format_as_links(self, salary_slip):
|
||||
return ['<a href="#Form/Salary Slip/{0}">{0}</a>'.format(salary_slip)]
|
||||
|
||||
def get_total_salary_and_loan_amounts(self):
|
||||
def get_loan_details(self):
|
||||
"""
|
||||
Get total loan principal, loan interest and salary amount from submitted salary slip based on selected criteria
|
||||
Get loan details from submitted salary slip based on selected criteria
|
||||
"""
|
||||
cond = self.get_filter_condition()
|
||||
totals = frappe.db.sql("""
|
||||
select sum(principal_amount) as total_principal_amount, sum(interest_amount) as total_interest_amount,
|
||||
sum(total_loan_repayment) as total_loan_repayment, sum(rounded_total) as rounded_total from `tabSalary Slip` t1
|
||||
return frappe.db.sql(""" select eld.employee_loan_account,
|
||||
eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment
|
||||
from
|
||||
`tabSalary Slip` t1, `tabSalary Slip Loan` eld
|
||||
where
|
||||
t1.docstatus = 1 and t1.name = eld.parent and start_date >= %s and end_date <= %s %s
|
||||
""" % ('%s', '%s', cond), (self.start_date, self.end_date), as_dict=True) or []
|
||||
|
||||
def get_total_salary_amount(self):
|
||||
"""
|
||||
Get total salary amount from submitted salary slip based on selected criteria
|
||||
"""
|
||||
cond = self.get_filter_condition()
|
||||
totals = frappe.db.sql(""" select sum(rounded_total) as rounded_total from `tabSalary Slip` t1
|
||||
where t1.docstatus = 1 and start_date >= %s and end_date <= %s %s
|
||||
""" % ('%s', '%s', cond), (self.start_date, self.end_date), as_dict=True)
|
||||
return totals[0]
|
||||
|
||||
def get_loan_accounts(self):
|
||||
loan_accounts = frappe.get_all("Employee Loan", fields=["employee_loan_account", "interest_income_account"],
|
||||
filters = {"company": self.company, "docstatus":1})
|
||||
if loan_accounts:
|
||||
return loan_accounts[0]
|
||||
return totals and totals[0] or None
|
||||
|
||||
def get_salary_component_account(self, salary_component):
|
||||
account = frappe.db.get_value("Salary Component Account",
|
||||
@ -257,8 +262,7 @@ class ProcessPayroll(Document):
|
||||
earnings = self.get_salary_component_total(component_type = "earnings") or {}
|
||||
deductions = self.get_salary_component_total(component_type = "deductions") or {}
|
||||
default_payroll_payable_account = self.get_default_payroll_payable_account()
|
||||
loan_amounts = self.get_total_salary_and_loan_amounts()
|
||||
loan_accounts = self.get_loan_accounts()
|
||||
loan_details = self.get_loan_details()
|
||||
jv_name = ""
|
||||
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
|
||||
|
||||
@ -294,18 +298,18 @@ class ProcessPayroll(Document):
|
||||
})
|
||||
|
||||
# Employee loan
|
||||
if loan_amounts.total_loan_repayment:
|
||||
for data in loan_details:
|
||||
accounts.append({
|
||||
"account": loan_accounts.employee_loan_account,
|
||||
"credit_in_account_currency": loan_amounts.total_principal_amount
|
||||
"account": data.employee_loan_account,
|
||||
"credit_in_account_currency": data.principal_amount
|
||||
})
|
||||
accounts.append({
|
||||
"account": loan_accounts.interest_income_account,
|
||||
"credit_in_account_currency": loan_amounts.total_interest_amount,
|
||||
"account": data.interest_income_account,
|
||||
"credit_in_account_currency": data.interest_amount,
|
||||
"cost_center": self.cost_center,
|
||||
"project": self.project
|
||||
})
|
||||
payable_amount -= flt(loan_amounts.total_loan_repayment, precision)
|
||||
payable_amount -= flt(data.total_payment, precision)
|
||||
|
||||
# Payable amount
|
||||
accounts.append({
|
||||
@ -327,11 +331,11 @@ class ProcessPayroll(Document):
|
||||
|
||||
def make_payment_entry(self):
|
||||
self.check_permission('write')
|
||||
total_salary_amount = self.get_total_salary_and_loan_amounts()
|
||||
total_salary_amount = self.get_total_salary_amount()
|
||||
default_payroll_payable_account = self.get_default_payroll_payable_account()
|
||||
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
|
||||
|
||||
if total_salary_amount.rounded_total:
|
||||
if total_salary_amount and total_salary_amount.rounded_total:
|
||||
journal_entry = frappe.new_doc('Journal Entry')
|
||||
journal_entry.voucher_type = 'Bank Entry'
|
||||
journal_entry.user_remark = _('Payment of salary from {0} to {1}')\
|
||||
|
@ -6,9 +6,9 @@ import unittest
|
||||
|
||||
import erpnext
|
||||
import frappe
|
||||
from frappe.utils import nowdate
|
||||
from erpnext.hr.doctype.process_payroll.process_payroll import get_end_date
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from erpnext.accounts.utils import get_fiscal_year, getdate, nowdate
|
||||
from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates, get_end_date
|
||||
|
||||
class TestProcessPayroll(unittest.TestCase):
|
||||
def test_process_payroll(self):
|
||||
@ -19,22 +19,9 @@ class TestProcessPayroll(unittest.TestCase):
|
||||
if not frappe.db.get_value('Salary Component Account',
|
||||
{'parent': data.name, 'company': erpnext.get_default_company()}, 'name'):
|
||||
get_salary_component_account(data.name)
|
||||
|
||||
payment_account = frappe.get_value('Account',
|
||||
{'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
|
||||
|
||||
if not frappe.db.get_value("Salary Slip", {"start_date": "2016-11-01", "end_date": "2016-11-30"}):
|
||||
process_payroll = frappe.get_doc("Process Payroll", "Process Payroll")
|
||||
process_payroll.company = erpnext.get_default_company()
|
||||
process_payroll.start_date = "2016-11-01"
|
||||
process_payroll.end_date = "2016-11-30"
|
||||
process_payroll.payment_account = payment_account
|
||||
process_payroll.posting_date = nowdate()
|
||||
process_payroll.payroll_frequency = "Monthly"
|
||||
process_payroll.create_salary_slips()
|
||||
process_payroll.submit_salary_slips()
|
||||
if process_payroll.get_sal_slip_list(ss_status = 1):
|
||||
r = process_payroll.make_payment_entry()
|
||||
make_process_payroll()
|
||||
|
||||
def test_get_end_date(self):
|
||||
self.assertEqual(get_end_date('2017-01-01', 'monthly'), {'end_date': '2017-01-31'})
|
||||
@ -45,7 +32,99 @@ class TestProcessPayroll(unittest.TestCase):
|
||||
self.assertEqual(get_end_date('2020-02-15', 'bimonthly'), {'end_date': ''})
|
||||
self.assertEqual(get_end_date('2017-02-15', 'monthly'), {'end_date': '2017-03-14'})
|
||||
self.assertEqual(get_end_date('2017-02-15', 'daily'), {'end_date': '2017-02-15'})
|
||||
|
||||
|
||||
def test_employee_loan(self):
|
||||
from erpnext.hr.doctype.salary_structure.test_salary_structure import (make_employee,
|
||||
make_salary_structure)
|
||||
from erpnext.hr.doctype.employee_loan.test_employee_loan import create_employee_loan
|
||||
|
||||
branch = "Test Employee Branch"
|
||||
employee = make_employee("test_employee@loan.com")
|
||||
company = erpnext.get_default_company()
|
||||
holiday_list = make_holiday("test holiday for loan")
|
||||
|
||||
if not frappe.db.exists('Salary Component', 'Basic Salary'):
|
||||
frappe.get_doc({
|
||||
'doctype': 'Salary Component',
|
||||
'salary_component': 'Basic Salary',
|
||||
'salary_component_abbr': 'BS',
|
||||
'type': 'Earning',
|
||||
'accounts': [{
|
||||
'company': company,
|
||||
'default_account': frappe.db.get_value('Account',
|
||||
{'company': company, 'root_type': 'Expense', 'account_type': ''}, 'name')
|
||||
}]
|
||||
}).insert()
|
||||
|
||||
if not frappe.db.get_value('Salary Component Account',
|
||||
{'parent': 'Basic Salary', 'company': company}):
|
||||
salary_component = frappe.get_doc('Salary Component', 'Basic Salary')
|
||||
salary_component.append('accounts', {
|
||||
'company': company,
|
||||
'default_account': 'Salary - WP'
|
||||
})
|
||||
|
||||
company_doc = frappe.get_doc('Company', company)
|
||||
if not company_doc.default_payroll_payable_account:
|
||||
company_doc.default_payroll_payable_account = frappe.db.get_value('Account',
|
||||
{'company': company, 'root_type': 'Liability', 'account_type': ''}, 'name')
|
||||
company_doc.save()
|
||||
|
||||
if not frappe.db.exists('Branch', branch):
|
||||
frappe.get_doc({
|
||||
'doctype': 'Branch',
|
||||
'branch': branch
|
||||
}).insert()
|
||||
|
||||
employee_doc = frappe.get_doc('Employee', employee)
|
||||
employee_doc.branch = branch
|
||||
employee_doc.holiday_list = holiday_list
|
||||
employee_doc.save()
|
||||
|
||||
employee_loan = create_employee_loan(employee,
|
||||
"Personal Loan", 280000, "Repay Over Number of Periods", 20)
|
||||
employee_loan.repay_from_salary = 1
|
||||
employee_loan.submit()
|
||||
|
||||
salary_strcture = "Test Salary Structure for Loan"
|
||||
if not frappe.db.exists('Salary Structure', salary_strcture):
|
||||
salary_strcture = make_salary_structure(salary_strcture, [{
|
||||
'employee': employee,
|
||||
'from_date': '2017-01-01',
|
||||
'base': 30000
|
||||
}])
|
||||
|
||||
salary_strcture = frappe.get_doc('Salary Structure', salary_strcture)
|
||||
salary_strcture.set('earnings', [{
|
||||
'salary_component': 'Basic Salary',
|
||||
'abbr': 'BS',
|
||||
'amount_based_on_formula':1,
|
||||
'formula': 'base*.5'
|
||||
}])
|
||||
salary_strcture.save()
|
||||
|
||||
dates = get_start_end_dates('Monthly', nowdate())
|
||||
make_process_payroll(start_date=dates.start_date,
|
||||
end_date=dates.end_date, branch=branch)
|
||||
|
||||
name = frappe.db.get_value('Salary Slip',
|
||||
{'posting_date': nowdate(), 'employee': employee}, 'name')
|
||||
|
||||
salary_slip = frappe.get_doc('Salary Slip', name)
|
||||
for row in salary_slip.loans:
|
||||
if row.employee_loan == employee_loan.name:
|
||||
interest_amount = (280000 * 8.4)/(12*100)
|
||||
principal_amount = employee_loan.monthly_repayment_amount - interest_amount
|
||||
self.assertEqual(row.interest_amount, interest_amount)
|
||||
self.assertEqual(row.principal_amount, principal_amount)
|
||||
self.assertEqual(row.total_payment,
|
||||
interest_amount + principal_amount)
|
||||
|
||||
if salary_slip.docstatus == 0:
|
||||
frappe.delete_doc('Salary Slip', name)
|
||||
|
||||
employee_loan.cancel()
|
||||
frappe.delete_doc('Employee Loan', employee_loan.name)
|
||||
|
||||
def get_salary_component_account(sal_comp):
|
||||
company = erpnext.get_default_company()
|
||||
@ -63,4 +142,54 @@ def create_account(company):
|
||||
"parent_account": "Indirect Expenses - " + frappe.db.get_value('Company', company, 'abbr'),
|
||||
"company": company
|
||||
}).insert()
|
||||
return salary_account
|
||||
return salary_account
|
||||
|
||||
def make_process_payroll(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
process_payroll = frappe.get_doc("Process Payroll", "Process Payroll")
|
||||
process_payroll.company = erpnext.get_default_company()
|
||||
process_payroll.start_date = args.start_date or "2016-11-01"
|
||||
process_payroll.end_date = args.end_date or "2016-11-30"
|
||||
process_payroll.payment_account = get_payment_account()
|
||||
process_payroll.posting_date = nowdate()
|
||||
process_payroll.payroll_frequency = "Monthly"
|
||||
process_payroll.branch = args.branch or None
|
||||
process_payroll.create_salary_slips()
|
||||
process_payroll.submit_salary_slips()
|
||||
if process_payroll.get_sal_slip_list(ss_status = 1):
|
||||
r = process_payroll.make_payment_entry()
|
||||
|
||||
return process_payroll
|
||||
|
||||
def get_payment_account():
|
||||
return frappe.get_value('Account',
|
||||
{'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
|
||||
|
||||
def make_holiday(holiday_list_name):
|
||||
if not frappe.db.exists('Holiday List', holiday_list_name):
|
||||
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)
|
||||
dt = getdate(nowdate())
|
||||
|
||||
new_year = dt + relativedelta(month=01, day=01, year=dt.year)
|
||||
republic_day = dt + relativedelta(month=01, day=26, year=dt.year)
|
||||
test_holiday = dt + relativedelta(month=02, day=02, year=dt.year)
|
||||
|
||||
frappe.get_doc({
|
||||
'doctype': 'Holiday List',
|
||||
'from_date': current_fiscal_year.year_start_date,
|
||||
'to_date': current_fiscal_year.year_end_date,
|
||||
'holiday_list_name': holiday_list_name,
|
||||
'holidays': [{
|
||||
'holiday_date': new_year,
|
||||
'description': 'New Year'
|
||||
}, {
|
||||
'holiday_date': republic_day,
|
||||
'description': 'Republic Day'
|
||||
}, {
|
||||
'holiday_date': test_holiday,
|
||||
'description': 'Test Holiday'
|
||||
}]
|
||||
}).insert()
|
||||
|
||||
return holiday_list_name
|
||||
|
@ -1293,7 +1293,68 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "principal_amount",
|
||||
"fieldname": "loans",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Employee Loan",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Salary Slip Loan",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_43",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "total_principal_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@ -1302,7 +1363,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Principal Amount",
|
||||
"label": "Total Principal Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
@ -1324,7 +1385,8 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "interest_amount",
|
||||
"default": "0",
|
||||
"fieldname": "total_interest_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@ -1333,7 +1395,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Interest Amount",
|
||||
"label": "Total Interest Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
@ -1355,7 +1417,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_48",
|
||||
"fieldname": "column_break_45",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@ -1384,6 +1446,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "total_loan_repayment",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -1604,7 +1667,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-11-10 18:40:33.817074",
|
||||
"modified": "2017-11-13 23:55:37.504856",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Slip",
|
||||
|
@ -375,15 +375,34 @@ class SalarySlip(TransactionBase):
|
||||
self.precision("net_pay") if disable_rounded_total else 0)
|
||||
|
||||
def set_loan_repayment(self):
|
||||
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
||||
sum(total_payment) as total_loan_repayment from `tabRepayment Schedule`
|
||||
where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
|
||||
where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
|
||||
(self.start_date, self.end_date, self.employee), as_dict=True)
|
||||
if employee_loan:
|
||||
self.principal_amount = employee_loan[0].principal_amount
|
||||
self.interest_amount = employee_loan[0].interest_amount
|
||||
self.total_loan_repayment = employee_loan[0].total_loan_repayment
|
||||
self.set('loans', [])
|
||||
self.total_loan_repayment = 0
|
||||
self.total_interest_amount = 0
|
||||
self.total_principal_amount = 0
|
||||
|
||||
for loan in self.get_employee_loan_details():
|
||||
self.append('loans', {
|
||||
'employee_loan': loan.name,
|
||||
'total_payment': loan.total_payment,
|
||||
'interest_amount': loan.interest_amount,
|
||||
'principal_amount': loan.principal_amount,
|
||||
'employee_loan_account': loan.employee_loan_account,
|
||||
'interest_income_account': loan.interest_income_account
|
||||
})
|
||||
|
||||
self.total_loan_repayment += loan.total_payment
|
||||
self.total_interest_amount += loan.interest_amount
|
||||
self.total_principal_amount += loan.principal_amount
|
||||
|
||||
def get_employee_loan_details(self):
|
||||
return frappe.db.sql("""select rps.principal_amount, rps.interest_amount, el.name,
|
||||
rps.total_payment, el.employee_loan_account, el.interest_income_account
|
||||
from
|
||||
`tabRepayment Schedule` as rps, `tabEmployee Loan` as el
|
||||
where
|
||||
el.name = rps.parent and rps.payment_date between %s and %s and
|
||||
el.repay_from_salary = 1 and el.docstatus = 1 and el.employee = %s""",
|
||||
(self.start_date, self.end_date, self.employee), as_dict=True) or []
|
||||
|
||||
def on_submit(self):
|
||||
if self.net_pay < 0:
|
||||
|
0
erpnext/hr/doctype/salary_slip_loan/__init__.py
Normal file
0
erpnext/hr/doctype/salary_slip_loan/__init__.py
Normal file
256
erpnext/hr/doctype/salary_slip_loan/salary_slip_loan.json
Normal file
256
erpnext/hr/doctype/salary_slip_loan/salary_slip_loan.json
Normal file
@ -0,0 +1,256 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2017-11-08 12:51:12.834479",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "employee_loan",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Employee Loan",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee Loan",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "employee_loan_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Employee Loan Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "interest_income_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Interest Income Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "principal_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Principal Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "interest_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Interest Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_payment",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Payment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-11-13 23:59:47.237689",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Slip Loan",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
10
erpnext/hr/doctype/salary_slip_loan/salary_slip_loan.py
Normal file
10
erpnext/hr/doctype/salary_slip_loan/salary_slip_loan.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SalarySlipLoan(Document):
|
||||
pass
|
@ -17,11 +17,9 @@ class TestSalaryStructure(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.make_holiday_list()
|
||||
frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Structure Test Holiday List")
|
||||
make_earning_salary_component(["Basic Salary", "Special Allowance", "HRA"])
|
||||
make_deduction_salary_component(["Professional Tax", "TDS"])
|
||||
make_employee("test_employee@salary.com")
|
||||
make_employee("test_employee_2@salary.com")
|
||||
|
||||
|
||||
def make_holiday_list(self):
|
||||
if not frappe.db.get_value("Holiday List", "Salary Structure Test Holiday List"):
|
||||
holiday_list = frappe.get_doc({
|
||||
@ -33,7 +31,7 @@ class TestSalaryStructure(unittest.TestCase):
|
||||
}).insert()
|
||||
holiday_list.get_weekly_off_dates()
|
||||
holiday_list.save()
|
||||
|
||||
|
||||
def test_amount_totals(self):
|
||||
sal_slip = frappe.get_value("Salary Slip", {"employee_name":"test_employee@salary.com"})
|
||||
if not sal_slip:
|
||||
@ -64,7 +62,7 @@ class TestSalaryStructure(unittest.TestCase):
|
||||
|
||||
for row in salary_structure.deductions:
|
||||
self.assertFalse(("\n" in row.formula) or ("\n" in row.condition))
|
||||
|
||||
|
||||
def make_employee(user):
|
||||
if not frappe.db.get_value("User", user):
|
||||
frappe.get_doc({
|
||||
@ -74,7 +72,6 @@ def make_employee(user):
|
||||
"new_password": "password",
|
||||
"roles": [{"doctype": "Has Role", "role": "Employee"}]
|
||||
}).insert()
|
||||
|
||||
|
||||
if not frappe.db.get_value("Employee", {"user_id": user}):
|
||||
emp = frappe.get_doc({
|
||||
@ -95,7 +92,7 @@ def make_employee(user):
|
||||
return emp.name
|
||||
else:
|
||||
return frappe.get_value("Employee", {"employee_name":user}, "name")
|
||||
|
||||
|
||||
def make_salary_slip_from_salary_structure(employee):
|
||||
sal_struct = make_salary_structure('Salary Structure Sample')
|
||||
sal_slip = make_salary_slip(sal_struct, employee = employee)
|
||||
@ -106,22 +103,21 @@ def make_salary_slip_from_salary_structure(employee):
|
||||
sal_slip.insert()
|
||||
sal_slip.submit()
|
||||
return sal_slip
|
||||
|
||||
def make_salary_structure(sal_struct):
|
||||
|
||||
def make_salary_structure(sal_struct, employees=None):
|
||||
if not frappe.db.exists('Salary Structure', sal_struct):
|
||||
frappe.get_doc({
|
||||
"doctype": "Salary Structure",
|
||||
"name": sal_struct,
|
||||
"company": erpnext.get_default_company(),
|
||||
"employees": get_employee_details(),
|
||||
"employees": employees or get_employee_details(),
|
||||
"earnings": get_earnings_component(),
|
||||
"deductions": get_deductions_component(),
|
||||
"payroll_frequency": "Monthly",
|
||||
"payment_account": frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
|
||||
}).insert()
|
||||
return sal_struct
|
||||
|
||||
|
||||
return sal_struct
|
||||
|
||||
def get_employee_details():
|
||||
return [{"employee": frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"),
|
||||
"base": 25000,
|
||||
@ -136,8 +132,11 @@ def get_employee_details():
|
||||
"idx": 2
|
||||
}
|
||||
]
|
||||
|
||||
def get_earnings_component():
|
||||
|
||||
def get_earnings_component():
|
||||
make_earning_salary_component(["Basic Salary", "Special Allowance", "HRA"])
|
||||
make_deduction_salary_component(["Professional Tax", "TDS"])
|
||||
|
||||
return [
|
||||
{
|
||||
"salary_component": 'Basic Salary',
|
||||
@ -167,7 +166,7 @@ def get_earnings_component():
|
||||
"idx": 4
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_deductions_component():
|
||||
return [
|
||||
{
|
||||
@ -191,5 +190,4 @@ def get_deductions_component():
|
||||
"formula": 'base*.1',
|
||||
"idx": 3
|
||||
}
|
||||
]
|
||||
|
||||
]
|
||||
|
@ -458,4 +458,5 @@ erpnext.patches.v9_0.copy_old_fees_field_data
|
||||
erpnext.patches.v9_0.set_pos_profile_name
|
||||
erpnext.patches.v9_0.remove_non_existing_warehouse_from_stock_settings
|
||||
execute:frappe.delete_doc_if_exists("DocType", "Program Fee")
|
||||
erpnext.patches.v9_2.delete_healthcare_domain_default_items
|
||||
erpnext.patches.v9_0.update_employee_loan_details
|
||||
erpnext.patches.v9_2.delete_healthcare_domain_default_items
|
||||
|
24
erpnext/patches/v9_0/update_employee_loan_details.py
Normal file
24
erpnext/patches/v9_0/update_employee_loan_details.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('hr', 'doctype', 'salary_slip_loan')
|
||||
frappe.reload_doc('hr', 'doctype', 'salary_slip')
|
||||
|
||||
for data in frappe.db.sql(""" select name,
|
||||
start_date, end_date, total_loan_repayment
|
||||
from
|
||||
`tabSalary Slip`
|
||||
where
|
||||
docstatus < 2 and ifnull(total_loan_repayment, 0) > 0""", as_dict=1):
|
||||
salary_slip = frappe.get_doc('Salary Slip', data.name)
|
||||
salary_slip.set_loan_repayment()
|
||||
|
||||
if salary_slip.total_loan_repayment == data.total_loan_repayment:
|
||||
for row in salary_slip.loans:
|
||||
row.db_update()
|
||||
|
||||
salary_slip.db_update()
|
@ -157,7 +157,7 @@ class Item(WebsiteGenerator):
|
||||
def make_route(self):
|
||||
if not self.route:
|
||||
return cstr(frappe.db.get_value('Item Group', self.item_group,
|
||||
'route')) + '/' + self.scrub(self.item_name + '-' + random_string(5))
|
||||
'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5))
|
||||
|
||||
def validate_website_image(self):
|
||||
"""Validate if the website image is a public file"""
|
||||
|
Loading…
Reference in New Issue
Block a user