Skip to content

Commit

Permalink
Merge pull request #1018 from frappe/version-14-hotfix
Browse files Browse the repository at this point in the history
chore: release v14
  • Loading branch information
ruchamahabal authored Nov 1, 2023
2 parents a1db09f + 6a5d41c commit 20b26b2
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 15 deletions.
30 changes: 23 additions & 7 deletions hrms/controllers/employee_reminders.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ def send_holidays_reminder_in_advance(employee, holidays):
employee_doc = frappe.get_doc("Employee", employee)
employee_email = get_employee_email(employee_doc)
frequency = frappe.db.get_single_value("HR Settings", "frequency")

sender_email = get_sender_email()
email_header = _("Holidays this Month.") if frequency == "Monthly" else _("Holidays this Week.")
frappe.sendmail(
sender=sender_email,
recipients=[employee_email],
subject=_("Upcoming Holidays Reminder"),
template="holiday_reminder",
Expand All @@ -85,10 +86,12 @@ def send_holidays_reminder_in_advance(employee, holidays):
# ------------------
def send_birthday_reminders():
"""Send Employee birthday reminders if no 'Stop Birthday Reminders' is not set."""

to_send = int(frappe.db.get_single_value("HR Settings", "send_birthday_reminders"))
if not to_send:
return

sender = get_sender_email()
employees_born_today = get_employees_who_are_born_today()

for company, birthday_persons in employees_born_today.items():
Expand All @@ -97,15 +100,15 @@ def send_birthday_reminders():
recipients = list(set(employee_emails) - set(birthday_person_emails))

reminder_text, message = get_birthday_reminder_text_and_message(birthday_persons)
send_birthday_reminder(recipients, reminder_text, birthday_persons, message)
send_birthday_reminder(recipients, reminder_text, birthday_persons, message, sender)

if len(birthday_persons) > 1:
# special email for people sharing birthdays
for person in birthday_persons:
person_email = person["user_id"] or person["personal_email"] or person["company_email"]
others = [d for d in birthday_persons if d != person]
reminder_text, message = get_birthday_reminder_text_and_message(others)
send_birthday_reminder(person_email, reminder_text, others, message)
send_birthday_reminder(person_email, reminder_text, others, message, sender)


def get_birthday_reminder_text_and_message(birthday_persons):
Expand All @@ -124,8 +127,9 @@ def get_birthday_reminder_text_and_message(birthday_persons):
return reminder_text, message


def send_birthday_reminder(recipients, reminder_text, birthday_persons, message):
def send_birthday_reminder(recipients, reminder_text, birthday_persons, message, sender=None):
frappe.sendmail(
sender=sender,
recipients=recipients,
subject=_("Birthday Reminder"),
template="birthday_reminder",
Expand Down Expand Up @@ -206,6 +210,7 @@ def send_work_anniversary_reminders():
if not to_send:
return

sender = get_sender_email()
employees_joined_today = get_employees_having_an_event_today("work_anniversary")

message = _("A friendly reminder of an important date for our team.")
Expand All @@ -218,15 +223,15 @@ def send_work_anniversary_reminders():
recipients = list(set(employee_emails) - set(anniversary_person_emails))

reminder_text = get_work_anniversary_reminder_text(anniversary_persons)
send_work_anniversary_reminder(recipients, reminder_text, anniversary_persons, message)
send_work_anniversary_reminder(recipients, reminder_text, anniversary_persons, message, sender)

if len(anniversary_persons) > 1:
# email for people sharing work anniversaries
for person in anniversary_persons:
person_email = person["user_id"] or person["personal_email"] or person["company_email"]
others = [d for d in anniversary_persons if d != person]
reminder_text = get_work_anniversary_reminder_text(others)
send_work_anniversary_reminder(person_email, reminder_text, others, message)
send_work_anniversary_reminder(person_email, reminder_text, others, message, sender)


def get_work_anniversary_reminder_text(anniversary_persons: list) -> str:
Expand Down Expand Up @@ -261,8 +266,15 @@ def get_pluralized_years(years):
return f"{years} years"


def send_work_anniversary_reminder(recipients, reminder_text, anniversary_persons, message):
def send_work_anniversary_reminder(
recipients,
reminder_text,
anniversary_persons,
message,
sender=None,
):
frappe.sendmail(
sender=sender,
recipients=recipients,
subject=_("Work Anniversary Reminder"),
template="anniversary_reminder",
Expand All @@ -273,3 +285,7 @@ def send_work_anniversary_reminder(recipients, reminder_text, anniversary_person
),
header=_("Work Anniversary Reminder"),
)


def get_sender_email() -> str | None:
return frappe.db.get_single_value("HR Settings", "sender_email")
1 change: 1 addition & 0 deletions hrms/hr/doctype/attendance/attendance_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ frappe.listview_settings["Attendance"] = {
fieldtype: "MultiCheck",
options: [],
columns: 2,
select_all: true,
},
],
primary_action(data) {
Expand Down
9 changes: 9 additions & 0 deletions hrms/hr/doctype/hr_settings/hr_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
// For license information, please see license.txt

frappe.ui.form.on('HR Settings', {
refresh: function (frm) {
frm.set_query("sender", () => {
return {
filters: {
enable_outgoing: 1,
},
};
});
}
});

frappe.tour['HR Settings'] = [
Expand Down
31 changes: 24 additions & 7 deletions hrms/hr/doctype/hr_settings/hr_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
"column_break_9",
"retirement_age",
"reminders_section",
"send_birthday_reminders",
"column_break_11",
"send_work_anniversary_reminders",
"column_break_18",
"send_birthday_reminders",
"send_holiday_reminders",
"frequency",
"column_break_hyec",
"sender",
"sender_email",
"leave_and_expense_claim_settings",
"send_leave_notification",
"leave_approval_notification_template",
Expand Down Expand Up @@ -71,10 +73,6 @@
"fieldtype": "Check",
"label": "Expense Approver Mandatory In Expense Claim"
},
{
"fieldname": "column_break_18",
"fieldtype": "Column Break"
},
{
"default": "1",
"fieldname": "leave_approver_mandatory_in_leave_application",
Expand Down Expand Up @@ -251,13 +249,31 @@
{
"fieldname": "column_break_34",
"fieldtype": "Column Break"
},
{
"fieldname": "sender",
"fieldtype": "Link",
"label": "Sender",
"options": "Email Account"
},
{
"depends_on": "eval:doc.sender",
"fetch_from": "sender.email_id",
"fieldname": "sender_email",
"fieldtype": "Data",
"label": "Sender Email",
"read_only": 1
},
{
"fieldname": "column_break_hyec",
"fieldtype": "Column Break"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2022-10-04 17:29:45.926918",
"modified": "2023-11-01 11:06:31.329718",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
Expand All @@ -275,5 +291,6 @@
],
"sort_field": "modified",
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
10 changes: 10 additions & 0 deletions hrms/payroll/doctype/payroll_settings/payroll_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
// For license information, please see license.txt

frappe.ui.form.on('Payroll Settings', {
refresh: function (frm) {
frm.set_query("sender", () => {
return {
filters: {
enable_outgoing: 1,
},
};
});
},

encrypt_salary_slips_in_emails: function(frm) {
let encrypt_state = frm.doc.encrypt_salary_slips_in_emails;
frm.set_df_property('password_policy', 'reqd', encrypt_state);
Expand Down
19 changes: 18 additions & 1 deletion hrms/payroll/doctype/payroll_settings/payroll_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"show_leave_balances_in_salary_slip",
"email_section",
"email_salary_slip_to_employee",
"sender",
"sender_email",
"column_break_iewr",
"encrypt_salary_slips_in_emails",
"password_policy",
Expand Down Expand Up @@ -155,13 +157,28 @@
"fieldname": "consider_marked_attendance_on_holidays",
"fieldtype": "Check",
"label": "Consider Marked Attendance on Holidays"
},
{
"depends_on": "eval:doc.email_salary_slip_to_employee",
"fieldname": "sender",
"fieldtype": "Link",
"label": "Sender",
"options": "Email Account"
},
{
"depends_on": "eval:doc.sender",
"fetch_from": "sender.email_id",
"fieldname": "sender_email",
"fieldtype": "Data",
"label": "Sender Email",
"read_only": 1
}
],
"icon": "fa fa-cog",
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-09-25 14:03:59.215240",
"modified": "2023-11-01 13:51:04.225492",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll Settings",
Expand Down
2 changes: 2 additions & 0 deletions hrms/payroll/doctype/salary_slip/salary_slip.py
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,7 @@ def get_loan_details(self):
"docstatus": 1,
"repay_from_salary": 1,
"company": self.company,
"status": ("!=", "Closed"),
},
)

Expand Down Expand Up @@ -1860,6 +1861,7 @@ def email_salary_slip(self):

if receiver:
email_args = {
"sender": payroll_settings.sender_email,
"recipients": [receiver],
"message": _(message),
"subject": "Salary Slip - from {0} to {1}".format(self.start_date, self.end_date),
Expand Down
89 changes: 89 additions & 0 deletions hrms/payroll/doctype/salary_slip/test_salary_slip.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ def test_loan_repayment_salary_slip(self):
"Test Loan Repayment Salary Structure",
"Monthly",
employee=applicant,
company="_Test Company",
currency="INR",
payroll_period=payroll_period,
)
Expand Down Expand Up @@ -689,6 +690,94 @@ def test_payroll_frequency(self):
elif payroll_frequency == "Daily":
self.assertEqual(ss.end_date, nowdate())

def test_loan_write_off_salary_slip(self):
from erpnext.loan_management.doctype.loan.loan import make_loan_write_off
from erpnext.loan_management.doctype.loan.test_loan import (
create_loan,
create_loan_accounts,
create_loan_type,
create_repayment_entry,
make_loan_disbursement_entry,
)
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
process_loan_interest_accrual_for_term_loans,
)

from hrms.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure

applicant = make_employee("test_loan_repayment_salary_slip@salary.com", company="_Test Company")

create_loan_accounts()

create_loan_type(
"Personal Loan",
12000,
0,
is_term_loan=1,
mode_of_payment="Cash",
disbursement_account="Disbursement Account - _TC",
payment_account="Payment Account - _TC",
loan_account="Loan Account - _TC",
interest_income_account="Interest Income Account - _TC",
penalty_income_account="Penalty Income Account - _TC",
repayment_schedule_type="Monthly as per repayment start date",
)

payroll_period = create_payroll_period(name="_Test Payroll Period", company="_Test Company")

make_salary_structure(
"Test Loan Repayment Salary Structure",
"Monthly",
employee=applicant,
company="_Test Company",
currency="INR",
payroll_period=payroll_period,
)

frappe.db.sql(
"delete from tabLoan where applicant = 'test_loan_repayment_salary_slip@salary.com'"
)
loan = create_loan(
applicant,
"Personal Loan",
12000,
"Repay Over Number of Periods",
12,
posting_date=payroll_period.start_date,
)
loan.repay_from_salary = 1
loan.submit()

make_loan_disbursement_entry(
loan.name, loan.loan_amount, disbursement_date=payroll_period.start_date
)

process_loan_interest_accrual_for_term_loans(
posting_date=add_months(payroll_period.start_date, 12)
)

repayment_entry = create_repayment_entry(
loan.name, applicant, add_months(payroll_period.start_date, 7), 7000
)
repayment_entry.submit()

we = make_loan_write_off(
loan.name, posting_date=add_months(payroll_period.start_date, 8), amount=5000
)
we.submit()

self.assertEqual(frappe.db.get_value("Loan", loan.name, "status"), "Closed")

ss = make_employee_salary_slip(
applicant,
"Monthly",
"Test Loan Repayment Salary Structure",
posting_date=add_months(payroll_period.start_date, 8),
)
ss.submit()

self.assertEqual(ss.total_loan_repayment, 0)

def test_multi_currency_salary_slip(self):
from hrms.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure

Expand Down

0 comments on commit 20b26b2

Please sign in to comment.