Skip to content

Commit

Permalink
Merge pull request #686 from frappe/version-14-hotfix
Browse files Browse the repository at this point in the history
  • Loading branch information
ruchamahabal committed Jul 13, 2023
2 parents eb901b1 + 68eee2a commit 1f75555
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 30 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/release_notes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This action:
#
# 1. Generates release notes using github API.
# 2. Strips unnecessary info like chore/style etc from notes.
# 3. Updates release info.

# This action needs to be maintained on all branches that do releases.

name: 'Release Notes'

on:
workflow_dispatch:
inputs:
tag_name:
description: 'Tag of release like v13.0.0'
required: true
type: string
release:
types: [released]

permissions:
contents: read

jobs:
regen-notes:
name: 'Regenerate release notes'
runs-on: ubuntu-latest

steps:
- name: Update notes
run: |
NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/generate-notes -f tag_name=$RELEASE_TAG | jq -r '.body' | sed -E '/^\* (chore|ci|test|docs|style)/d' )
RELEASE_ID=$(gh api -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/tags/$RELEASE_TAG | jq -r '.id')
gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/$RELEASE_ID -f body="$NEW_NOTES"
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
RELEASE_TAG: ${{ github.event.inputs.tag_name || github.event.release.tag_name }}
2 changes: 1 addition & 1 deletion hrms/hr/doctype/job_applicant/job_applicant.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ frappe.ui.form.on("Job Applicant", {
}, __("Create"));
}

if (!frm.doc.__islocal) {
if (!frm.doc.__islocal && frm.doc.status == "Accepted") {
if (frm.doc.__onload && frm.doc.__onload.job_offer) {
$('[data-doctype="Employee Onboarding"]').find("button").show();
$('[data-doctype="Job Offer"]').find("button").hide();
Expand Down
11 changes: 7 additions & 4 deletions hrms/hr/doctype/shift_type/shift_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def process_auto_attendance(self):
self.name,
)

for employee in self.get_assigned_employee(self.process_attendance_after, True):
for employee in self.get_assigned_employees(self.process_attendance_after, True):
self.mark_absent_for_dates_with_no_attendance(employee)

def get_employee_checkins(self) -> list[dict]:
Expand Down Expand Up @@ -225,7 +225,7 @@ def get_marked_attendance_dates_between(
)
).run(pluck=True)

def get_assigned_employee(self, from_date=None, consider_default_shift=False):
def get_assigned_employees(self, from_date=None, consider_default_shift=False):
filters = {"shift_type": self.name, "docstatus": "1", "status": "Active"}
if from_date:
filters["start_date"] = (">=", from_date)
Expand All @@ -234,9 +234,12 @@ def get_assigned_employee(self, from_date=None, consider_default_shift=False):

if consider_default_shift:
default_shift_employees = self.get_employees_with_default_shift(filters)
assigned_employees = set(assigned_employees + default_shift_employees)

return list(set(assigned_employees + default_shift_employees))
return assigned_employees
# exclude inactive employees
inactive_employees = frappe.db.get_all("Employee", {"status": "Inactive"}, pluck="name")

return set(assigned_employees) - set(inactive_employees)

def get_employees_with_default_shift(self, filters: dict) -> list:
default_shift_employees = frappe.get_all(
Expand Down
17 changes: 16 additions & 1 deletion hrms/hr/doctype/shift_type/test_shift_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def test_skip_marking_absent_on_a_holiday(self):
)
self.assertIsNone(attendance)

def test_skip_marking_absent_for_a_fallback_default_shift(self):
def test_skip_absent_marking_for_a_fallback_default_shift(self):
"""
Tests if an employee is not marked absent for default shift
when they have a valid shift assignment of another type.
Expand Down Expand Up @@ -366,6 +366,21 @@ def test_skip_marking_absent_for_a_fallback_default_shift(self):
)
self.assertEqual(attendance, "Present")

def test_skip_absent_marking_for_inactive_employee(self):
from hrms.hr.doctype.employee_checkin.test_employee_checkin import make_checkin

shift = setup_shift_type()
employee = make_employee("[email protected]", company="_Test Company")
date = getdate()
make_shift_assignment(shift.name, employee, date)

# mark employee as Inactive
frappe.db.set_value("Employee", employee, "status", "Inactive")

shift.process_auto_attendance()
attendance = frappe.db.get_value("Attendance", {"employee": employee}, "status")
self.assertIsNone(attendance)

def test_get_start_and_end_dates(self):
date = getdate()

Expand Down
5 changes: 3 additions & 2 deletions hrms/payroll/doctype/salary_component/salary_component.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"depends_on": "eval:doc.type == \"Deduction\"",
"fieldname": "variable_based_on_taxable_salary",
"fieldtype": "Check",
"label": "Variable Based On Taxable Salary"
"label": "Variable Based On Taxable Salary",
"search_index": 1
},
{
"depends_on": "eval:doc.statistical_component != 1",
Expand Down Expand Up @@ -263,7 +264,7 @@
"icon": "fa fa-flag",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-03-01 16:57:46.413627",
"modified": "2023-06-21 15:11:53.582800",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Component",
Expand Down
8 changes: 7 additions & 1 deletion hrms/payroll/doctype/salary_component/salary_component.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt


import frappe
from frappe.model.document import Document
from frappe.model.naming import append_number_if_name_exists

Expand All @@ -10,6 +10,9 @@ class SalaryComponent(Document):
def validate(self):
self.validate_abbr()

def on_update(self):
self.invalidate_cache()

def validate_abbr(self):
if not self.salary_component_abbr:
self.salary_component_abbr = "".join([c[0] for c in self.salary_component.split()]).upper()
Expand All @@ -22,3 +25,6 @@ def validate_abbr(self):
separator="_",
filters={"name": ["!=", self.name]},
)

def invalidate_cache(self):
frappe.cache().delete_value("tax_components")
96 changes: 76 additions & 20 deletions hrms/payroll/doctype/salary_slip/salary_slip.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
get_payroll_period,
get_period_factor,
)
from hrms.payroll.utils import sanitize_expression


class SalarySlip(TransactionBase):
Expand Down Expand Up @@ -1042,37 +1043,42 @@ def get_data_for_eval(self):

return data, default_data

def eval_condition_and_formula(self, d, data):
def eval_condition_and_formula(self, struct_row, data):
try:
condition = d.condition.strip().replace("\n", " ") if d.condition else None
condition = sanitize_expression(struct_row.condition)
if condition:
if not frappe.safe_eval(condition, self.whitelisted_globals, data):
return None
amount = d.amount
if d.amount_based_on_formula:
formula = d.formula.strip().replace("\n", " ") if d.formula else None
amount = struct_row.amount
if struct_row.amount_based_on_formula:
formula = sanitize_expression(struct_row.formula)
if formula:
amount = flt(frappe.safe_eval(formula, self.whitelisted_globals, data), d.precision("amount"))
amount = flt(
frappe.safe_eval(formula, self.whitelisted_globals, data), struct_row.precision("amount")
)
if amount:
data[d.abbr] = amount
data[struct_row.abbr] = amount

return amount

except NameError as err:
except NameError as ne:
throw_error_message(
d,
err,
struct_row,
ne,
title=_("Name error"),
description=_("This error can be due to missing or deleted field."),
)
except SyntaxError as err:
except SyntaxError as se:
throw_error_message(
d, err, title=_("Syntax error"), description=_("This error can be due to invalid syntax.")
struct_row,
se,
title=_("Syntax error"),
description=_("This error can be due to invalid syntax."),
)
except Exception as err:
except Exception as exc:
throw_error_message(
d,
err,
struct_row,
exc,
title=_("Error in formula or condition"),
description=_("This error can be due to invalid formula or condition."),
)
Expand Down Expand Up @@ -1143,11 +1149,14 @@ def add_tax_components(self):
self.other_deduction_components.append(d.salary_component)

if not tax_components:
tax_components = [
d.name
for d in frappe.get_all("Salary Component", filters={"variable_based_on_taxable_salary": 1})
if d.name not in self.other_deduction_components
]
tax_components = self.get_tax_components()
frappe.msgprint(
_(
"Added tax components from the Salary Component master as the salary structure didn't have any tax component."
),
indicator="blue",
alert=True,
)

if tax_components and self.payroll_period and self.salary_structure:
self.tax_slab = self.get_income_tax_slabs()
Expand All @@ -1160,6 +1169,53 @@ def add_tax_components(self):
tax_row = get_salary_component_data(d)
self.update_component_row(tax_row, tax_amount, "deductions")

def get_tax_components(self) -> list:
"""
Returns:
list: A list of tax components specific to the company.
If no tax components are defined for the company,
it returns the default tax components.
"""

tax_components = frappe.cache().get_value(
"tax_components", self._fetch_company_wise_tax_components
)

default_tax_components = tax_components.get("default", [])

return tax_components.get(self.company, default_tax_components)

def _fetch_company_wise_tax_components(self) -> dict:
"""
Returns:
dict: A dictionary containing tax components grouped by company.
Raises:
None
"""

tax_components = {}
sc = frappe.qb.DocType("Salary Component")
sca = frappe.qb.DocType("Salary Component Account")

components = (
frappe.qb.from_(sc)
.left_join(sca)
.on(sca.parent == sc.name)
.select(
sc.name,
sca.company,
)
.where(sc.variable_based_on_taxable_salary == 1)
).run(as_dict=True)

for component in components:
key = component.company or "default"
tax_components.setdefault(key, [])
tax_components[key].append(component.name)

return tax_components

def update_component_row(
self,
component_data,
Expand Down
Loading

0 comments on commit 1f75555

Please sign in to comment.