Skip to content

Commit

Permalink
Merge branch 'develop' into attendance-request-future-date
Browse files Browse the repository at this point in the history
  • Loading branch information
iamejaaz authored Oct 15, 2024
2 parents 8dbd5d5 + b59f609 commit 377c441
Show file tree
Hide file tree
Showing 132 changed files with 762 additions and 342 deletions.
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ body:
Welcome to Frappe HR issue tracker! Before submitting a request, please consider the following:
1. This tracker should only be used to report bugs and request features / enhancements to Frappe HR
- For questions and general support, checkout the [documentation](https://frappehr.com/docs) or use the [forum](https://discuss.frappe.io) to get inputs from the open source community.
- For questions and general support, checkout the [documentation](https://docs.frappe.io/hr) or use the [forum](https://discuss.frappe.io) to get inputs from the open source community.
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
the original discussion.
3. When making a feature request, make sure to be as verbose as possible. The better you convey your message, the greater the drive to make it happen.
Expand Down Expand Up @@ -47,4 +47,4 @@ body:
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
...
...
2 changes: 1 addition & 1 deletion .github/helper/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def docs_link_exists(body):
parts = parsed_url.path.split("/")
if len(parts) == 5 and parts[1] == "frappe" and parts[2] == "hrms":
return True
elif parsed_url.netloc == "frappehr.com":
elif parsed_url.netloc == "docs.frappe.io":
return True


Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Frappe HR has everything you need to drive excellence within the company. It's a

## Learning and Community

1. [Documentation](https://frappehr.com/docs) - Extensive documentation for Frappe HR.
1. [Documentation](https://docs.frappe.io/hr) - Extensive documentation for Frappe HR.
2. [User Forum](https://discuss.erpnext.com/) - Engage with the community of ERPNext users and service providers.
3. [Telegram Group](https://t.me/frappehr) - Get instant help from the community of users.

Expand Down
2 changes: 1 addition & 1 deletion frappe-ui
Submodule frappe-ui updated 53 files
+2 −3 package.json
+2 −4 src/components/Autocomplete.vue
+2 −11 src/components/Avatar.vue
+0 −1 src/components/Breadcrumbs.vue
+0 −247 src/components/Calendar.story.md
+0 −138 src/components/Calendar.story.vue
+0 −432 src/components/Calendar/Calendar.vue
+0 −113 src/components/Calendar/CalendarDaily.vue
+0 −512 src/components/Calendar/CalendarEvent.vue
+0 −143 src/components/Calendar/CalendarMonthly.vue
+0 −49 src/components/Calendar/CalendarTimeMarker.vue
+0 −252 src/components/Calendar/CalendarWeekly.vue
+0 −63 src/components/Calendar/EventModalContent.vue
+0 −46 src/components/Calendar/FloatingPopover.vue
+0 −210 src/components/Calendar/NewEventModal.vue
+0 −37 src/components/Calendar/ShowMoreCalendarEvent.vue
+0 −277 src/components/Calendar/calendarUtils.js
+0 −54 src/components/Calendar/composables/useCalendarData.js
+0 −41 src/components/Calendar/composables/useEventModal.js
+4 −7 src/components/Checkbox.vue
+0 −36 src/components/DatePicker.story.vue
+72 −108 src/components/DatePicker.vue
+0 −333 src/components/DateRangePicker.vue
+0 −405 src/components/DateTimePicker.vue
+3 −11 src/components/Dialog.vue
+3 −3 src/components/FeatherIcon.vue
+6 −6 src/components/FileUploader.vue
+4 −4 src/components/ListFilter/ListFilter.vue
+2 −2 src/components/ListFilter/SearchComplete.vue
+1 −1 src/components/ListView/ListHeader.vue
+7 −19 src/components/ListView/ListRow.vue
+2 −2 src/components/ListView/ListView.vue
+10 −19 src/components/Popover.vue
+4 −4 src/components/Switch.vue
+3 −17 src/components/TabButtons.vue
+2 −2 src/components/TextEditor/InsertVideo.vue
+1 −1 src/components/TextEditor/TextEditor.vue
+1 −1 src/components/TextEditor/image-extension.js
+1 −1 src/components/TextEditor/mention.js
+1 −1 src/components/Tooltip/Tooltip.vue
+2 −2 src/components/toast.js
+2 −4 src/fonts/Inter/inter.css
+0 −4 src/index.js
+6 −6 src/resources/documentResource.js
+8 −8 src/resources/listResource.js
+1 −1 src/resources/plugin.js
+1 −1 src/utils/call.js
+1 −1 src/utils/confirmDialog.js
+1 −1 src/utils/debounce.ts
+1 −1 src/utils/frappeRequest.js
+1 −1 src/utils/markdown.js
+1 −1 src/utils/pageMeta.js
+0 −4 src/utils/tailwind.config.js
8 changes: 6 additions & 2 deletions hrms/api/roster.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,18 @@ def insert_shift(

def get_holidays(month_start: str, month_end: str, employee_filters: dict[str, str]) -> dict[str, list[dict]]:
holidays = {}
holiday_lists = {}

for employee in frappe.get_list("Employee", filters=employee_filters, pluck="name"):
if holiday_list := get_holiday_list_for_employee(employee, raise_exception=False):
holidays[employee] = frappe.get_all(
if not (holiday_list := get_holiday_list_for_employee(employee, raise_exception=False)):
continue
if holiday_list not in holiday_lists:
holiday_lists[holiday_list] = frappe.get_all(
"Holiday",
filters={"parent": holiday_list, "holiday_date": ["between", [month_start, month_end]]},
fields=["name as holiday", "holiday_date", "description", "weekly_off"],
)
holidays[employee] = holiday_lists[holiday_list].copy()

return holidays

Expand Down
4 changes: 2 additions & 2 deletions hrms/controllers/tests/test_employee_reminders.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from datetime import timedelta

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase
from frappe.utils import add_months, getdate

from erpnext.setup.doctype.employee.test_employee import make_employee
Expand All @@ -14,7 +14,7 @@
from hrms.hr.utils import get_holidays_for_employee


class TestEmployeeReminders(FrappeTestCase):
class TestEmployeeReminders(IntegrationTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/appointment_letter/test_appointment_letter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# See license.txt

# import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase


class TestAppointmentLetter(FrappeTestCase):
class TestAppointmentLetter(IntegrationTestCase):
pass
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# See license.txt

# import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase


class TestAppointmentLetterTemplate(FrappeTestCase):
class TestAppointmentLetterTemplate(IntegrationTestCase):
pass
4 changes: 2 additions & 2 deletions hrms/hr/doctype/appraisal/test_appraisal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase

from erpnext.setup.doctype.designation.test_designation import create_designation
from erpnext.setup.doctype.employee.test_employee import make_employee
Expand All @@ -17,7 +17,7 @@
from hrms.tests.test_utils import create_company


class TestAppraisal(FrappeTestCase):
class TestAppraisal(IntegrationTestCase):
def setUp(self):
frappe.db.delete("Goal")
frappe.db.delete("Appraisal")
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase

from erpnext.setup.doctype.designation.test_designation import create_designation
from erpnext.setup.doctype.employee.test_employee import make_employee
Expand All @@ -11,7 +11,7 @@
from hrms.tests.test_utils import create_company


class TestAppraisalCycle(FrappeTestCase):
class TestAppraisalCycle(IntegrationTestCase):
def setUp(self):
company = create_company("_Test Appraisal").name
self.template = create_appraisal_template()
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/appraisal_template/test_appraisal_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase


class TestAppraisalTemplate(FrappeTestCase):
class TestAppraisalTemplate(IntegrationTestCase):
def test_incorrect_weightage_allocation(self):
template = create_appraisal_template()
template.goals[1].per_weightage = 69.99
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/attendance/test_attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase
from frappe.utils import (
add_days,
add_months,
Expand All @@ -27,7 +27,7 @@
test_records = frappe.get_test_records("Attendance")


class TestAttendance(FrappeTestCase):
class TestAttendance(IntegrationTestCase):
def setUp(self):
from hrms.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list

Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/attendance_request/test_attendance_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, add_months, get_year_ending, get_year_start, getdate

from hrms.hr.doctype.attendance.attendance import mark_attendance
Expand All @@ -17,7 +17,7 @@
test_dependencies = ["Employee"]


class TestAttendanceRequest(FrappeTestCase):
class TestAttendanceRequest(IntegrationTestCase):
def setUp(self):
for doctype in ["Attendance Request", "Attendance"]:
frappe.db.delete(doctype)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, add_months, today

from hrms.hr.doctype.attendance_request.test_attendance_request import get_employee
Expand All @@ -13,7 +13,7 @@
test_dependencies = ["Employee"]


class TestCompensatoryLeaveRequest(FrappeTestCase):
class TestCompensatoryLeaveRequest(IntegrationTestCase):
def setUp(self):
frappe.db.delete("Compensatory Leave Request")
frappe.db.delete("Leave Ledger Entry")
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/daily_work_summary/test_daily_work_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import frappe
import frappe.utils
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase

# test_records = frappe.get_test_records('Daily Work Summary')


class TestDailyWorkSummary(FrappeTestCase):
class TestDailyWorkSummary(IntegrationTestCase):
def test_email_trigger(self):
self.setup_and_prepare_test()
for d in self.users:
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/employee_advance/test_employee_advance.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase
from frappe.utils import flt, nowdate

import erpnext
Expand All @@ -23,7 +23,7 @@
from hrms.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure


class TestEmployeeAdvance(FrappeTestCase):
class TestEmployeeAdvance(IntegrationTestCase):
def setUp(self):
frappe.db.delete("Employee Advance")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See license.txt

import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests import IntegrationTestCase
from frappe.utils import getdate

from erpnext.setup.doctype.employee.test_employee import make_employee
Expand All @@ -15,7 +15,7 @@
from hrms.hr.doctype.shift_type.test_shift_type import setup_shift_type


class TestEmployeeAttendanceTool(FrappeTestCase):
class TestEmployeeAttendanceTool(IntegrationTestCase):
def setUp(self):
frappe.db.delete("Attendance")

Expand Down
42 changes: 4 additions & 38 deletions hrms/hr/doctype/employee_checkin/employee_checkin.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ frappe.ui.form.on("Employee Checkin", {
}
},

fetch_geolocation: (frm) => {
hrms.fetch_geolocation(frm);
},

add_fetch_shift_button(frm) {
if (frm.doc.attendace) return;
frm.add_custom_button(__("Fetch Shift"), function () {
Expand All @@ -39,42 +43,4 @@ frappe.ui.form.on("Employee Checkin", {
});
});
},

fetch_geolocation: async (frm) => {
if (!navigator.geolocation) {
frappe.msgprint({
message: __("Geolocation is not supported by your current browser"),
title: __("Geolocation Error"),
indicator: "red",
});
hide_field(["geolocation"]);
return;
}

frappe.dom.freeze(__("Fetching your geolocation") + "...");

navigator.geolocation.getCurrentPosition(
async (position) => {
frm.set_value("latitude", position.coords.latitude);
frm.set_value("longitude", position.coords.longitude);

await frm.call("set_geolocation_from_coordinates");
frm.dirty();
frappe.dom.unfreeze();
},
(error) => {
frappe.dom.unfreeze();

let msg = __("Unable to retrieve your location") + "<br><br>";
if (error) {
msg += __("ERROR({0}): {1}", [error.code, error.message]);
}
frappe.msgprint({
message: msg,
title: __("Geolocation Error"),
indicator: "red",
});
},
);
},
});
58 changes: 39 additions & 19 deletions hrms/hr/doctype/employee_checkin/employee_checkin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,25 @@
from frappe.model.document import Document
from frappe.utils import cint, get_datetime

from hrms.hr.doctype.shift_assignment.shift_assignment import (
get_actual_start_end_datetime_of_shift,
from hrms.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift
from hrms.hr.utils import (
get_distance_between_coordinates,
set_geolocation_from_coordinates,
validate_active_employee,
)
from hrms.hr.utils import validate_active_employee


class CheckinRadiusExceededError(frappe.ValidationError):
pass


class EmployeeCheckin(Document):
def validate(self):
validate_active_employee(self.employee)
self.validate_duplicate_log()
self.fetch_shift()
self.set_geolocation_from_coordinates()
set_geolocation_from_coordinates(self)
self.validate_distance_from_shift_location()

def validate_duplicate_log(self):
doc = frappe.db.exists(
Expand Down Expand Up @@ -64,27 +71,40 @@ def fetch_shift(self):
self.shift_start = shift_actual_timings.start_datetime
self.shift_end = shift_actual_timings.end_datetime

@frappe.whitelist()
def set_geolocation_from_coordinates(self):
def validate_distance_from_shift_location(self):
if not frappe.db.get_single_value("HR Settings", "allow_geolocation_tracking"):
return

if not (self.latitude and self.longitude):
if not (self.latitude or self.longitude):
frappe.throw(_("Latitude and longitude values are required for checking in."))

assignment_locations = frappe.get_all(
"Shift Assignment",
filters={
"employee": self.employee,
"shift_type": self.shift,
"start_date": ["<=", self.time],
"shift_location": ["is", "set"],
"docstatus": 1,
},
or_filters=[["end_date", ">=", self.time], ["end_date", "is", "not set"]],
pluck="shift_location",
)
if not assignment_locations:
return

self.geolocation = frappe.json.dumps(
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
# geojson needs coordinates in reverse order: long, lat instead of lat, long
"geometry": {"type": "Point", "coordinates": [self.longitude, self.latitude]},
}
],
}
checkin_radius, latitude, longitude = frappe.db.get_value(
"Shift Location", assignment_locations[0], ["checkin_radius", "latitude", "longitude"]
)
if checkin_radius <= 0:
return

distance = get_distance_between_coordinates(latitude, longitude, self.latitude, self.longitude)
if distance > checkin_radius:
frappe.throw(
_("You must be within {0} meters of your shift location to check in.").format(checkin_radius),
exc=CheckinRadiusExceededError,
)


@frappe.whitelist()
Expand Down
Loading

0 comments on commit 377c441

Please sign in to comment.