brynq-sdk-bob 2.6.2.dev10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ import pandera as pa
2
+ from pandera.typing import Series, String, Float
3
+ from typing import Optional
4
+ import pandas as pd
5
+ from brynq_sdk_functions import BrynQPanderaDataFrameModel
6
+
7
+ class TimeOffSchema(BrynQPanderaDataFrameModel):
8
+ change_type: Series[String] = pa.Field(coerce=True, description="Change Type", alias="changeType")
9
+ employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
10
+ employee_display_name: Series[String] = pa.Field(coerce=True, description="Employee Display Name", alias="employeeDisplayName")
11
+ employee_email: Series[String] = pa.Field(coerce=True, description="Employee Email", alias="employeeEmail")
12
+ request_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Request ID", alias="requestId")
13
+ policy_type_display_name: Series[String] = pa.Field(coerce=True, description="Policy Type Display Name", alias="policyTypeDisplayName")
14
+ type: Series[String] = pa.Field(coerce=True, description="Type", alias="type")
15
+ start_date: Series[String] = pa.Field(coerce=True, nullable=True, description="Start Date", alias="startDate")
16
+ start_portion: Series[String] = pa.Field(coerce=True, nullable=True, description="Start Portion", alias="startPortion")
17
+ end_date: Series[String] = pa.Field(coerce=True, nullable=True, description="End Date", alias="endDate")
18
+ end_portion: Series[String] = pa.Field(coerce=True, nullable=True, description="End Portion", alias="endPortion")
19
+ day_portion: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Day Portion", alias="dayPortion")
20
+ date: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Date", alias="date")
21
+ hours_on_date: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Hours on Date", alias="hoursOnDate")
22
+ daily_hours: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Daily Hours", alias="dailyHours")
23
+ duration_unit: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Duration Unit", alias="durationUnit")
24
+ total_duration: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Total Duration", alias="totalDuration")
25
+ total_cost: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Total Cost", alias="totalCost")
26
+ change_reason: Optional[Series[String]] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="changeReason")
27
+ visibility: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Visibility", alias="visibility")
28
+
29
+ class Config:
30
+ coerce = True
31
+
32
+
33
+ class TimeOffBalanceSchema(BrynQPanderaDataFrameModel):
34
+ employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
35
+ policy_type_name: Series[String] = pa.Field(coerce=True, description="Policy Type Name", alias="policyTypeName")
36
+ policy_type_display_name: Series[String] = pa.Field(coerce=True, description="Policy Type Display Name", alias="policyTypeDisplayName")
37
+ balance: Series[Float] = pa.Field(coerce=True, description="Current Balance", alias="balance")
38
+ used: Series[Float] = pa.Field(coerce=True, description="Used Balance", alias="used")
39
+ available: Series[Float] = pa.Field(coerce=True, description="Available Balance", alias="available")
40
+ approved_requests: Series[Float] = pa.Field(coerce=True, description="Approved Requests", alias="approvedRequests")
41
+ pending_requests: Series[Float] = pa.Field(coerce=True, description="Pending Requests", alias="pendingRequests")
42
+ as_of_date: Series[String] = pa.Field(coerce=True, description="As of Date", alias="asOfDate")
43
+ accrual_start_date: Series[String] = pa.Field(nullable=True, coerce=True, description="Accrual Start Date", alias="accrualStartDate")
44
+ expiry_date: Series[String] = pa.Field(nullable=True, coerce=True, description="Expiry Date", alias="expiryDate")
45
+ duration_unit: Series[String] = pa.Field(coerce=True, description="Duration Unit", alias="durationUnit")
46
+
47
+ class Config:
48
+ coerce = True
@@ -0,0 +1,32 @@
1
+ import pandera as pa
2
+ from pandera.typing import Series
3
+ import pandas as pd
4
+ from datetime import datetime
5
+ from brynq_sdk_functions import BrynQPanderaDataFrameModel
6
+
7
+ class WorkSchema(BrynQPanderaDataFrameModel):
8
+ can_be_deleted: Series[pa.Bool] = pa.Field(coerce=True, description="Can Be Deleted", alias="canBeDeleted")
9
+ work_change_type: Series[str] = pa.Field(coerce=True, description="Work Change Type", alias="workChangeType")
10
+ creation_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
11
+ title: Series[str] = pa.Field(coerce=True, nullable=True, description="Title", alias="title")
12
+ is_current: Series[pa.Bool] = pa.Field(coerce=True, description="Is Current", alias="isCurrent")
13
+ modification_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Modification Date", alias="modificationDate")
14
+ site: Series[str] = pa.Field(coerce=True, nullable=True, description="Site", alias="site")
15
+ site_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Site ID", alias="siteId")
16
+ id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="ID", alias="id")
17
+ end_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="End Effective Date", alias="endEffectiveDate")
18
+ active_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Active Effective Date", alias="activeEffectiveDate")
19
+ department: Series[str] = pa.Field(coerce=True, nullable=True, description="Department", alias="department")
20
+ effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Effective Date", alias="effectiveDate")
21
+ change_reason: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Reason", alias="change.reason")
22
+ change_changed_by: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Changed By", alias="change.changedBy")
23
+ change_changed_by_id: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Changed By ID", alias="change.changedById")
24
+ reports_to_id: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To ID", alias="reportsTo.id")
25
+ reports_to_first_name: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To First Name", alias="reportsTo.firstName")
26
+ reports_to_surname: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Surname", alias="reportsTo.surname")
27
+ reports_to_email: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Email", alias="reportsTo.email")
28
+ reports_to_display_name: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Display Name", alias="reportsTo.displayName")
29
+ employee_id: Series[str] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
30
+
31
+ class Config:
32
+ coerce = True
@@ -0,0 +1,79 @@
1
+ from datetime import datetime, timezone, timedelta
2
+ import pandas as pd
3
+ from brynq_sdk_functions import Functions
4
+ from .schemas.timeoff import TimeOffSchema, TimeOffBalanceSchema
5
+ import warnings
6
+
7
+
8
+ class TimeOff:
9
+ def __init__(self, bob):
10
+ self.bob = bob
11
+ self.schema = TimeOffSchema
12
+ self.balance_schema = TimeOffBalanceSchema
13
+
14
+ def get(self, since: datetime = None, include_pending: bool = False) -> tuple[pd.DataFrame, pd.DataFrame]:
15
+ """
16
+ Get time off requests
17
+
18
+ Args:
19
+ since (datetime, optional): The start date of the time off requests max 6 months ago. Defaults to 6 months ago if not provided.
20
+
21
+ Returns:
22
+ tuple[pd.DataFrame, pd.DataFrame]: A tuple of (valid_timeoff, invalid_timeoff) as pandas DataFrames
23
+ """
24
+ max_lookback = timedelta(days=int((365 / 2) - 1))
25
+ now_utc = datetime.now(timezone.utc)
26
+ six_months_ago = now_utc - max_lookback
27
+ #if since is provided, use it and cap to 6 months max
28
+ if since is not None:
29
+ if since.tzinfo is None:
30
+ since = since.replace(tzinfo=timezone.utc)
31
+ if since < six_months_ago:
32
+ warnings.warn("The 'since' date is more than 6 months ago. Limiting to 6 months ago due to API restrictions.")
33
+ since = six_months_ago
34
+ #if no since is provided, use 6 months ago
35
+ else:
36
+ since = six_months_ago
37
+
38
+ since = since.replace(tzinfo=timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
39
+ resp = self.bob.session.get(url=f"{self.bob.base_url}timeoff/requests/changes",
40
+ params={'since': since, 'includePending': 'true' if include_pending else 'false'},
41
+ timeout=self.bob.timeout)
42
+ resp.raise_for_status()
43
+ data = resp.json()['changes']
44
+ # data = self.bob.get_paginated_result(request)
45
+ df = pd.DataFrame(data)
46
+ valid_timeoff, invalid_timeoff = Functions.validate_data(df=df, schema=self.schema, debug=True)
47
+
48
+ return valid_timeoff, invalid_timeoff
49
+
50
+ def get_balance(self, employee_id: str, policy_type: str = None, as_of_date: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
51
+ """
52
+ Get time off balance for a specific employee
53
+
54
+ Args:
55
+ employee_id (str): The ID of the employee
56
+ policy_type (str, optional): The policy type to filter by. Defaults to None.
57
+ as_of_date (str, optional): The date to get balance as of (YYYY-MM-DD format). Defaults to None.
58
+
59
+ Returns:
60
+ tuple[pd.DataFrame, pd.DataFrame]: A tuple of (valid_balance, invalid_balance) as pandas DataFrames
61
+ """
62
+ params = {}
63
+ if policy_type:
64
+ params['policyType'] = policy_type
65
+ if as_of_date:
66
+ params['asOfDate'] = as_of_date
67
+
68
+ resp = self.bob.session.get(
69
+ url=f"{self.bob.base_url}timeoff/employees/{employee_id}/balance",
70
+ params=params,
71
+ timeout=self.bob.timeout
72
+ )
73
+ resp.raise_for_status()
74
+ data = resp.json()
75
+ df = pd.DataFrame(data)
76
+
77
+ valid_balance, invalid_balance = Functions.validate_data(df=df, schema=self.balance_schema, debug=True)
78
+
79
+ return valid_balance, invalid_balance
brynq_sdk_bob/work.py ADDED
@@ -0,0 +1,31 @@
1
+ import pandas as pd
2
+ import requests
3
+ from typing import Optional, List
4
+ from brynq_sdk_functions import Functions
5
+ from .schemas.work import WorkSchema
6
+
7
+
8
+ class Work:
9
+ def __init__(self, bob):
10
+ self.bob = bob
11
+ self.schema = WorkSchema
12
+
13
+ def get(self, employee_ids: Optional[List[str]] = None) ->(pd.DataFrame, pd.DataFrame):
14
+ params = {"limit": 100}
15
+
16
+ # Add employeeIds filter if provided
17
+ if employee_ids is not None:
18
+ params["employeeIds"] = ",".join(employee_ids)
19
+
20
+ request = requests.Request(method='GET',
21
+ url=f"{self.bob.base_url}bulk/people/work",
22
+ params=params)
23
+ data = self.bob.get_paginated_result(request)
24
+ df = pd.json_normalize(
25
+ data,
26
+ record_path='values',
27
+ meta=['employeeId']
28
+ )
29
+ valid_work, invalid_work = Functions.validate_data(df=df, schema=self.schema, debug=True)
30
+
31
+ return valid_work, invalid_work
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: brynq_sdk_bob
3
+ Version: 2.6.2.dev10
4
+ Summary: Bob wrapper from BrynQ
5
+ Author: BrynQ
6
+ Author-email: support@brynq.com
7
+ License: BrynQ License
8
+ Requires-Dist: brynq-sdk-brynq<5,>=4
9
+ Requires-Dist: pandas<3.0.0,>=2.2.0
10
+ Requires-Dist: tenacity==8.2.3
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: description
14
+ Dynamic: license
15
+ Dynamic: requires-dist
16
+ Dynamic: summary
17
+
18
+ Bob wrapper from BrynQ
@@ -0,0 +1,28 @@
1
+ brynq_sdk_bob/__init__.py,sha256=bw2Www_wgVxqZczJpz9K_94k7OdgqwWKF0aQaKG5TQE,3052
2
+ brynq_sdk_bob/bank.py,sha256=5ncWsmeAvNoiLnVvIvPgFDRQ5DB5_VY2ipMC439GVHU,1460
3
+ brynq_sdk_bob/company.py,sha256=rjOpkm0CZ1EeJ-jddBl36GrGKUQviC1ca1aUL2tl1_M,848
4
+ brynq_sdk_bob/custom_tables.py,sha256=MvnR2mIcyK0rpwd0P7xV3BPIvCYQVEClBvo901GttPs,2642
5
+ brynq_sdk_bob/documents.py,sha256=ww101owiBGARCxOANdDtmWrNedSBe9V-BEed6QspQPg,1756
6
+ brynq_sdk_bob/employment.py,sha256=kBEKfUmKEw-A_FjC9fOuJqcsT7NxUKwXJs_V_-x9LbI,765
7
+ brynq_sdk_bob/named_lists.py,sha256=ksLXV2ysBFegq4gZiiaC56gjkgdnPzL7WajZTGvjYIM,1069
8
+ brynq_sdk_bob/payments.py,sha256=e1TnJcXlbotOfULukVUiaYZ1N-bDGynAtmPgpux7It0,5670
9
+ brynq_sdk_bob/payroll_history.py,sha256=wHo6da7kLDe1ViL4egyMdyJBMZnWVhwjNjmh4cTCTeY,3972
10
+ brynq_sdk_bob/people.py,sha256=6b7uCucl_xqtAq_4YJZU457fUY0qssMwfCCStzbNG0M,5036
11
+ brynq_sdk_bob/salaries.py,sha256=8xq9XDTK473Az2MpuAPofz9CvZstjufSoWtF0bi1wC4,1766
12
+ brynq_sdk_bob/timeoff.py,sha256=NbBZ39qy9D7jbS_z9bpmB-BKNuUGmNrkYTbEw034tZ0,3339
13
+ brynq_sdk_bob/work.py,sha256=IADipEuI_ofhhLZZV9oI8PV10VN07yluPPkLZT19Ze8,1013
14
+ brynq_sdk_bob/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ brynq_sdk_bob/schemas/bank.py,sha256=Yfq-ouzcAyaqcZj5_lWLcaQgtLikI9zlcsHhsuPUQzY,1935
16
+ brynq_sdk_bob/schemas/custom_tables.py,sha256=638NH2n50vHzw1LFlbKVCBKBhfSsfGqtEGuor0Z-QS4,1567
17
+ brynq_sdk_bob/schemas/employment.py,sha256=uErbSyl8xYaYo5Hu0FZ7_tl1WCOaytcU9pjkIWJbmOo,3226
18
+ brynq_sdk_bob/schemas/named_lists.py,sha256=HJBRKrAI2vhrkq-5MVXqQcmpGNzFtoOnaZI2Ii_6_vs,725
19
+ brynq_sdk_bob/schemas/payments.py,sha256=N4Ylommed-hsw0aX7rjuZuVZQc4XU0iDBdSIxz8eAxc,4292
20
+ brynq_sdk_bob/schemas/payroll_history.py,sha256=JdAq0XaArHHEw8EsXo3GD0EhSAyBhPtYQMmdvjCiY8g,806
21
+ brynq_sdk_bob/schemas/people.py,sha256=cy0mLKRdUhjOv52WB53AWd1XHn6mwrACGZAvK2ufsz4,38780
22
+ brynq_sdk_bob/schemas/salary.py,sha256=TSaM1g92y3oiDcUrfJW7ushgKZenI9xB6XW3kKuU0dE,4540
23
+ brynq_sdk_bob/schemas/timeoff.py,sha256=BHImTTT4n8j7bF7T5Ue_B0WHmmj1_QTPV9TKAlHeBZM,4124
24
+ brynq_sdk_bob/schemas/work.py,sha256=klzJtQf-avwhOkRHuPTM-jMhTIsroDPE56da1H5xaYs,2926
25
+ brynq_sdk_bob-2.6.2.dev10.dist-info/METADATA,sha256=hlLk5XIWFqHhiKBwQb8E-EPiyr34wWndRQvBxcSP5_M,408
26
+ brynq_sdk_bob-2.6.2.dev10.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
27
+ brynq_sdk_bob-2.6.2.dev10.dist-info/top_level.txt,sha256=oGiWqOuAAiVoLIzGe6F-Lo4IJBYz5ftOwBft7HtPuoY,14
28
+ brynq_sdk_bob-2.6.2.dev10.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ brynq_sdk_bob