brynq-sdk-bob 2.3.0__tar.gz → 2.4.0__tar.gz

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.
Files changed (32) hide show
  1. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/PKG-INFO +1 -1
  2. brynq_sdk_bob-2.4.0/brynq_sdk_bob/payments.py +114 -0
  3. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/payments.py +15 -1
  4. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/people.py +2 -2
  5. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/salary.py +1 -1
  6. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/PKG-INFO +1 -1
  7. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/setup.py +1 -1
  8. brynq_sdk_bob-2.3.0/brynq_sdk_bob/payments.py +0 -23
  9. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/__init__.py +0 -0
  10. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/bank.py +0 -0
  11. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/company.py +0 -0
  12. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/custom_tables.py +0 -0
  13. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/documents.py +0 -0
  14. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/employment.py +0 -0
  15. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/named_lists.py +0 -0
  16. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/people.py +0 -0
  17. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/salaries.py +0 -0
  18. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/__init__.py +0 -0
  19. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/bank.py +0 -0
  20. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/custom_tables.py +0 -0
  21. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/employment.py +0 -0
  22. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/named_lists.py +0 -0
  23. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/timeoff.py +0 -0
  24. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/work.py +0 -0
  25. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/timeoff.py +0 -0
  26. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/work.py +0 -0
  27. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/SOURCES.txt +0 -0
  28. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/dependency_links.txt +0 -0
  29. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/not-zip-safe +0 -0
  30. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/requires.txt +0 -0
  31. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/top_level.txt +0 -0
  32. {brynq_sdk_bob-2.3.0 → brynq_sdk_bob-2.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq_sdk_bob
3
- Version: 2.3.0
3
+ Version: 2.4.0
4
4
  Summary: Bob wrapper from BrynQ
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -0,0 +1,114 @@
1
+ import pandas as pd
2
+ from typing import Optional, List
3
+ from brynq_sdk_functions import Functions
4
+ from .schemas.payments import VariablePaymentSchema, ActualPaymentsSchema
5
+
6
+
7
+ class Payments:
8
+ def __init__(self, bob):
9
+ self.bob = bob
10
+ self.schema = VariablePaymentSchema
11
+
12
+ def get(self, person_id: str) -> (pd.DataFrame, pd.DataFrame):
13
+ resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
14
+ resp.raise_for_status()
15
+ data = resp.json()
16
+ df = pd.json_normalize(
17
+ data,
18
+ record_path='values'
19
+ )
20
+ df['employee_id'] = person_id
21
+ valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
22
+
23
+ return valid_payments, invalid_payments
24
+
25
+ def get_actual_payments(
26
+ self,
27
+ limit: int = 200,
28
+ employee_ids: Optional[List[str]] = None,
29
+ pay_date_from: Optional[str] = None,
30
+ pay_date_to: Optional[str] = None
31
+ ) -> (pd.DataFrame, pd.DataFrame):
32
+ """
33
+ Search for actual payments with optional employee and pay date filters.
34
+ This method auto-paginates until all results are fetched.
35
+
36
+ See Bob API: https://apidocs.hibob.com/reference/post_people-actual-payments-search
37
+ See Pagination: https://apidocs.hibob.com/docs/pagination
38
+
39
+ Args:
40
+ limit (int): Number of records per page (default: 50, max: 200).
41
+ employee_ids (Optional[List[str]]): Filter by employee IDs.
42
+ pay_date_from (Optional[str]): Inclusive start date filter (YYYY-MM-DD).
43
+ pay_date_to (Optional[str]): Inclusive end date filter (YYYY-MM-DD).
44
+
45
+ Returns:
46
+ tuple: (valid_payments DataFrame, invalid_payments DataFrame)
47
+ """
48
+ base_payload = {
49
+ "pagination": {
50
+ "limit": limit
51
+ }
52
+ }
53
+
54
+ filters = []
55
+ if employee_ids:
56
+ filters.append({
57
+ "fieldPath": "employeeId",
58
+ "operator": "equals",
59
+ "values": employee_ids
60
+ })
61
+ if pay_date_from:
62
+ filters.append({
63
+ "fieldPath": "payDate",
64
+ "operator": "greaterThanOrEquals",
65
+ "value": pay_date_from
66
+ })
67
+ if pay_date_to:
68
+ filters.append({
69
+ "fieldPath": "payDate",
70
+ "operator": "lessThanOrEquals",
71
+ "value": pay_date_to
72
+ })
73
+
74
+ if filters:
75
+ base_payload["filters"] = filters
76
+
77
+ all_results = []
78
+ next_cursor = None
79
+
80
+ while True:
81
+ payload = dict(base_payload)
82
+ payload["pagination"] = dict(base_payload["pagination"])
83
+ if next_cursor:
84
+ payload["pagination"]["cursor"] = next_cursor
85
+
86
+ resp = self.bob.session.post(
87
+ url=f"{self.bob.base_url}people/actual-payments/search",
88
+ json=payload,
89
+ timeout=self.bob.timeout
90
+ )
91
+ resp.raise_for_status()
92
+ data = resp.json()
93
+
94
+ page_results = data.get('results') or []
95
+ if page_results:
96
+ all_results.extend(page_results)
97
+
98
+ next_cursor = (data.get('response_metadata') or {}).get('next_cursor')
99
+ if not next_cursor:
100
+ break
101
+
102
+ if not all_results:
103
+ empty_df = pd.DataFrame()
104
+ return empty_df, empty_df
105
+
106
+ df = pd.json_normalize(all_results)
107
+
108
+ valid_payments, invalid_payments = Functions.validate_data(
109
+ df=df,
110
+ schema=ActualPaymentsSchema,
111
+ debug=True
112
+ )
113
+
114
+ return valid_payments, invalid_payments
@@ -26,6 +26,20 @@ class VariablePaymentSchema(BrynQPanderaDataFrameModel):
26
26
  change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="change.reason")
27
27
  change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By", alias="change.changedBy")
28
28
  change_changed_by_id: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True, description="Change Changed By ID", alias="change.changedById")
29
- employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employeeId") #set manually
29
+ employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employee_id") #set manually
30
+ class Config:
31
+ coerce = True
32
+
33
+ class ActualPaymentsSchema(BrynQPanderaDataFrameModel):
34
+ employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
35
+ id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Payment ID", alias="id")
36
+ pay_date: Series[DateTime] = pa.Field(coerce=True, description="Pay Date", alias="payDate")
37
+ pay_type: Series[String] = pa.Field(coerce=True, description="Pay Type", alias="payType")
38
+ amount_value: Series[Float] = pa.Field(coerce=True, description="Amount Value", alias="amount.value")
39
+ amount_currency: Series[String] = pa.Field(coerce=True, description="Amount Currency", alias="amount.currency")
40
+ change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="change.reason")
41
+ change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By", alias="change.changedBy")
42
+ change_changed_by_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By ID", alias="change.changedById")
43
+
30
44
  class Config:
31
45
  coerce = True
@@ -16,7 +16,7 @@ def check_list(x):
16
16
 
17
17
 
18
18
  class PeopleSchema(BrynQPanderaDataFrameModel):
19
- id: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, description="Person ID", alias="id")
19
+ id: Optional[Series[String]] = pa.Field(coerce=True, description="Person ID", alias="id")
20
20
  display_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Display Name", alias="displayName")
21
21
  company_id: Optional[Series[String]] = pa.Field(coerce=True, description="Company ID", alias="companyId")
22
22
  email: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Email", alias="email")
@@ -63,7 +63,7 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
63
63
  work_active_effective_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Work Active Effective Date", alias="work.activeEffectiveDate")
64
64
  work_direct_reports: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Direct Reports", alias="work.directReports")
65
65
  # work_work_change_type: Series[String] = pa.Field(coerce=True, nullable=True)
66
- work_second_level_manager: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Second Level Manager", alias="work.secondLevelManager")
66
+ work_second_level_manager: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Second Level Manager", alias="work.secondLevelManager")
67
67
  work_days_of_previous_service: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Days of Previous Service", alias="work.daysOfPreviousService")
68
68
  work_years_of_service: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Work Years of Service", alias="work.yearsOfService")
69
69
  payroll_employment_contract: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Contract Type", alias="payroll.employment.contract")
@@ -7,7 +7,7 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
7
7
 
8
8
 
9
9
  class SalarySchema(BrynQPanderaDataFrameModel):
10
- id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Salary ID", alias="id")
10
+ id: Series[String] = pa.Field(coerce=True, description="Salary ID", alias="id")
11
11
  employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
12
12
  pay_frequency: Series[String] = pa.Field(coerce=True, nullable=True, description="Pay Frequency", alias="payFrequency") # has a list of possible values , isin=['Monthly']
13
13
  creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq-sdk-bob
3
- Version: 2.3.0
3
+ Version: 2.4.0
4
4
  Summary: Bob wrapper from BrynQ
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -2,7 +2,7 @@ from setuptools import setup, find_namespace_packages
2
2
 
3
3
  setup(
4
4
  name='brynq_sdk_bob',
5
- version='2.3.0',
5
+ version='2.4.0',
6
6
  description='Bob wrapper from BrynQ',
7
7
  long_description='Bob wrapper from BrynQ',
8
8
  author='BrynQ',
@@ -1,23 +0,0 @@
1
- from datetime import datetime
2
- import pandas as pd
3
- from brynq_sdk_functions import Functions
4
- from .schemas.payments import VariablePaymentSchema
5
-
6
-
7
- class Payments:
8
- def __init__(self, bob):
9
- self.bob = bob
10
- self.schema = VariablePaymentSchema
11
-
12
- def get(self, person_id: str) -> (pd.DataFrame, pd.DataFrame):
13
- resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
14
- resp.raise_for_status()
15
- data = resp.json()
16
- df = pd.json_normalize(
17
- data,
18
- record_path='values'
19
- )
20
- df['employee_id'] = person_id
21
- valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
22
-
23
- return valid_payments, invalid_payments
File without changes