brynq-sdk-bob 2.5.2.dev0__tar.gz → 2.6.2.dev0__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.
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/PKG-INFO +1 -1
- brynq_sdk_bob-2.6.2.dev0/brynq_sdk_bob/__init__.py +77 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/bank.py +6 -1
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/payments.py +46 -1
- brynq_sdk_bob-2.6.2.dev0/brynq_sdk_bob/people.py +100 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/salaries.py +9 -2
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/bank.py +8 -7
- brynq_sdk_bob-2.6.2.dev0/brynq_sdk_bob/schemas/people.py +284 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/salary.py +1 -1
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob.egg-info/PKG-INFO +1 -1
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/setup.py +1 -1
- brynq_sdk_bob-2.5.2.dev0/brynq_sdk_bob/__init__.py +0 -349
- brynq_sdk_bob-2.5.2.dev0/brynq_sdk_bob/people.py +0 -343
- brynq_sdk_bob-2.5.2.dev0/brynq_sdk_bob/schemas/people.py +0 -100
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/company.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/custom_tables.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/documents.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/employment.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/named_lists.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/payroll_history.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/__init__.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/custom_tables.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/employment.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/named_lists.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/payments.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/payroll_history.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/timeoff.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/schemas/work.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/timeoff.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob/work.py +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob.egg-info/SOURCES.txt +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob.egg-info/dependency_links.txt +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob.egg-info/not-zip-safe +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob.egg-info/requires.txt +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/brynq_sdk_bob.egg-info/top_level.txt +0 -0
- {brynq_sdk_bob-2.5.2.dev0 → brynq_sdk_bob-2.6.2.dev0}/setup.cfg +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import re
|
|
3
|
+
from typing import Union, List, Optional, Literal
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import requests
|
|
6
|
+
import os
|
|
7
|
+
from brynq_sdk_brynq import BrynQ
|
|
8
|
+
from brynq_sdk_functions import Functions
|
|
9
|
+
from .bank import Bank
|
|
10
|
+
from .company import Company
|
|
11
|
+
from .documents import CustomDocuments
|
|
12
|
+
from .employment import Employment
|
|
13
|
+
from .named_lists import NamedLists
|
|
14
|
+
from .payments import Payments
|
|
15
|
+
from .people import People
|
|
16
|
+
from .salaries import Salaries
|
|
17
|
+
from .timeoff import TimeOff
|
|
18
|
+
from .work import Work
|
|
19
|
+
from .custom_tables import CustomTables
|
|
20
|
+
|
|
21
|
+
class Bob(BrynQ):
|
|
22
|
+
def __init__(self, system_type: Optional[Literal['source', 'target']] = None, test_environment: bool = True, debug: bool = False, target_system: str = None):
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.timeout = 3600
|
|
25
|
+
self.headers = self._get_request_headers(system_type)
|
|
26
|
+
if test_environment:
|
|
27
|
+
self.base_url = "https://api.sandbox.hibob.com/v1/"
|
|
28
|
+
else:
|
|
29
|
+
self.base_url = "https://api.hibob.com/v1/"
|
|
30
|
+
self.session = requests.Session()
|
|
31
|
+
self.session.headers.update(self.headers)
|
|
32
|
+
self.people = People(self)
|
|
33
|
+
self.salaries = Salaries(self)
|
|
34
|
+
self.work = Work(self)
|
|
35
|
+
self.bank = Bank(self)
|
|
36
|
+
self.employment = Employment(self)
|
|
37
|
+
self.payments = Payments(self)
|
|
38
|
+
self.time_off = TimeOff(self)
|
|
39
|
+
self.documents = CustomDocuments(self)
|
|
40
|
+
self.companies = Company(self)
|
|
41
|
+
self.named_lists = NamedLists(self)
|
|
42
|
+
self.custom_tables = CustomTables(self)
|
|
43
|
+
self.data_interface_id = os.getenv("DATA_INTERFACE_ID")
|
|
44
|
+
self.debug = debug
|
|
45
|
+
|
|
46
|
+
def _get_request_headers(self, system_type):
|
|
47
|
+
credentials = self.interfaces.credentials.get(system='bob', system_type=system_type)
|
|
48
|
+
if type(credentials) is list:
|
|
49
|
+
credentials = credentials[0]
|
|
50
|
+
|
|
51
|
+
print(credentials)
|
|
52
|
+
auth_token = base64.b64encode(f"{credentials.get('data').get('User ID')}:{credentials.get('data').get('API Token')}".encode()).decode('utf-8')
|
|
53
|
+
headers = {
|
|
54
|
+
"accept": "application/json",
|
|
55
|
+
"Authorization": f"Basic {auth_token}",
|
|
56
|
+
"Partner-Token": "001Vg00000A6FY6IAN"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return headers
|
|
60
|
+
|
|
61
|
+
def get_paginated_result(self, request: requests.Request) -> List:
|
|
62
|
+
has_next_page = True
|
|
63
|
+
result_data = []
|
|
64
|
+
while has_next_page:
|
|
65
|
+
prepped = request.prepare()
|
|
66
|
+
prepped.headers.update(self.session.headers)
|
|
67
|
+
resp = self.session.send(prepped, timeout=self.timeout)
|
|
68
|
+
resp.raise_for_status()
|
|
69
|
+
response_data = resp.json()
|
|
70
|
+
result_data += response_data['results']
|
|
71
|
+
next_cursor = response_data.get('response_metadata').get('next_cursor')
|
|
72
|
+
# If there is no next page, set has_next_page to False, we could use the falsy value of None but this is more readable
|
|
73
|
+
has_next_page = next_cursor is not None
|
|
74
|
+
if has_next_page:
|
|
75
|
+
request.params.update({"cursor": next_cursor})
|
|
76
|
+
|
|
77
|
+
return result_data
|
|
@@ -2,6 +2,8 @@ import pandas as pd
|
|
|
2
2
|
from brynq_sdk_functions import Functions
|
|
3
3
|
from .schemas.bank import BankSchema
|
|
4
4
|
|
|
5
|
+
import time
|
|
6
|
+
from tqdm import tqdm
|
|
5
7
|
|
|
6
8
|
class Bank:
|
|
7
9
|
def __init__(self, bob):
|
|
@@ -10,7 +12,7 @@ class Bank:
|
|
|
10
12
|
|
|
11
13
|
def get(self, person_ids: pd.Series, field_selection: list[str] = []) -> (pd.DataFrame, pd.DataFrame):
|
|
12
14
|
data = []
|
|
13
|
-
for person_id in person_ids:
|
|
15
|
+
for person_id in tqdm(person_ids, desc="Fetching bank accounts"):
|
|
14
16
|
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/bank-accounts", timeout=self.bob.timeout)
|
|
15
17
|
resp.raise_for_status()
|
|
16
18
|
temp_data = resp.json()['values']
|
|
@@ -19,6 +21,9 @@ class Bank:
|
|
|
19
21
|
account['employee_id'] = person_id
|
|
20
22
|
data += temp_data
|
|
21
23
|
|
|
24
|
+
# rate limit is 50 per minute
|
|
25
|
+
time.sleep(1.3)
|
|
26
|
+
|
|
22
27
|
df = pd.DataFrame(data)
|
|
23
28
|
|
|
24
29
|
valid_banks, invalid_banks = Functions.validate_data(df=df, schema=BankSchema, debug=True)
|
|
@@ -3,15 +3,49 @@ from typing import Optional, List
|
|
|
3
3
|
from brynq_sdk_functions import Functions
|
|
4
4
|
from .schemas.payments import VariablePaymentSchema, ActualPaymentsSchema
|
|
5
5
|
|
|
6
|
+
import time
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
class Payments:
|
|
8
11
|
def __init__(self, bob):
|
|
9
12
|
self.bob = bob
|
|
10
13
|
self.schema = VariablePaymentSchema
|
|
11
14
|
|
|
15
|
+
def _apply_named_list_mappings(self, df: pd.DataFrame) -> pd.DataFrame:
|
|
16
|
+
"""Apply named list ID-to-value mappings to dataframe columns."""
|
|
17
|
+
if df.empty:
|
|
18
|
+
return df
|
|
19
|
+
|
|
20
|
+
# Fetch named lists from Bob API
|
|
21
|
+
resp_named_lists = self.bob.session.get(
|
|
22
|
+
url=f"{self.bob.base_url}company/named-lists",
|
|
23
|
+
timeout=self.bob.timeout,
|
|
24
|
+
headers=self.bob.headers
|
|
25
|
+
)
|
|
26
|
+
named_lists = resp_named_lists.json()
|
|
27
|
+
|
|
28
|
+
# Transform named_lists to create id-to-value mappings for each field
|
|
29
|
+
named_lists = {
|
|
30
|
+
key.split('.')[-1]: {item['id']: item['value'] for item in value['values']}
|
|
31
|
+
for key, value in named_lists.items()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for field in df.columns:
|
|
35
|
+
# Fields in the response and in the named-list have different building blocks
|
|
36
|
+
# but they both end with the same last block
|
|
37
|
+
field_df = field.split('.')[-1].split('work_')[-1]
|
|
38
|
+
if field_df in named_lists.keys() and field_df not in ['site']:
|
|
39
|
+
mapping = named_lists[field_df]
|
|
40
|
+
df[field] = df[field].apply(
|
|
41
|
+
lambda v: [mapping.get(x, x) for x in v] if isinstance(v, list) else mapping.get(v, v)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return df
|
|
45
|
+
|
|
12
46
|
def get(self, person_ids: List[str]) -> (pd.DataFrame, pd.DataFrame):
|
|
13
47
|
df = pd.DataFrame()
|
|
14
|
-
for person_id in person_ids:
|
|
48
|
+
for person_id in tqdm(person_ids, desc="Fetching variable payments"):
|
|
15
49
|
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
|
|
16
50
|
resp.raise_for_status()
|
|
17
51
|
data = resp.json()
|
|
@@ -20,7 +54,15 @@ class Payments:
|
|
|
20
54
|
record_path='values'
|
|
21
55
|
)])
|
|
22
56
|
df['employee_id'] = person_id
|
|
57
|
+
|
|
58
|
+
# Rate limit is 50 per minute
|
|
59
|
+
time.sleep(1.3)
|
|
60
|
+
|
|
23
61
|
df = df.reset_index(drop=True)
|
|
62
|
+
|
|
63
|
+
# Apply named list mappings
|
|
64
|
+
df = self._apply_named_list_mappings(df)
|
|
65
|
+
|
|
24
66
|
valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
25
67
|
return valid_payments, invalid_payments
|
|
26
68
|
|
|
@@ -107,6 +149,9 @@ class Payments:
|
|
|
107
149
|
|
|
108
150
|
df = pd.json_normalize(all_results)
|
|
109
151
|
|
|
152
|
+
# Apply named list mappings
|
|
153
|
+
df = self._apply_named_list_mappings(df)
|
|
154
|
+
|
|
110
155
|
valid_payments, invalid_payments = Functions.validate_data(
|
|
111
156
|
df=df,
|
|
112
157
|
schema=ActualPaymentsSchema,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
from brynq_sdk_functions import Functions
|
|
4
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
|
+
from .bank import Bank
|
|
6
|
+
from .employment import Employment
|
|
7
|
+
from .salaries import Salaries
|
|
8
|
+
from .schemas.people import PeopleSchema
|
|
9
|
+
from .work import Work
|
|
10
|
+
from .custom_tables import CustomTables
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class People:
|
|
14
|
+
def __init__(self, bob):
|
|
15
|
+
self.bob = bob
|
|
16
|
+
self.salaries = Salaries(bob)
|
|
17
|
+
self.employment = Employment(bob)
|
|
18
|
+
self.bank = Bank(bob)
|
|
19
|
+
self.work = Work(bob)
|
|
20
|
+
self.custom_tables = CustomTables(bob)
|
|
21
|
+
self.schema = PeopleSchema
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Build API fields using column metadata if present (api_field), otherwise use the column (alias) name
|
|
25
|
+
def __build_api_fields(self, schema_model: BrynQPanderaDataFrameModel) -> list[str]:
|
|
26
|
+
schema = schema_model.to_schema()
|
|
27
|
+
return [
|
|
28
|
+
((getattr(col, "metadata", None) or {}).get("api_field")) or col_name
|
|
29
|
+
for col_name, col in schema.columns.items()
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
def get(self, schema_custom_fields: Optional[BrynQPanderaDataFrameModel] = None, employee_ids: Optional[List[str]] = None) -> pd.DataFrame:
|
|
33
|
+
core_fields = self.__build_api_fields(PeopleSchema)
|
|
34
|
+
custom_fields = self.__build_api_fields(schema_custom_fields) if schema_custom_fields is not None else []
|
|
35
|
+
fields = core_fields + custom_fields
|
|
36
|
+
|
|
37
|
+
# Build filters based on employee_ids if provided
|
|
38
|
+
filters = []
|
|
39
|
+
if employee_ids is not None:
|
|
40
|
+
filters = [
|
|
41
|
+
{
|
|
42
|
+
"fieldPath": "root.id",
|
|
43
|
+
"operator": "equals",
|
|
44
|
+
"values": employee_ids
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
resp = self.bob.session.post(url=f"{self.bob.base_url}people/search",
|
|
49
|
+
json={
|
|
50
|
+
"fields": fields,
|
|
51
|
+
"filters": filters
|
|
52
|
+
#"humanReadable": "REPLACE"
|
|
53
|
+
},
|
|
54
|
+
timeout=self.bob.timeout)
|
|
55
|
+
resp.raise_for_status()
|
|
56
|
+
df = pd.json_normalize(resp.json()['employees'])
|
|
57
|
+
df = df.loc[:, ~df.columns.str.contains('value')]
|
|
58
|
+
|
|
59
|
+
# Normalize separators in incoming data: convert '/' to '.' to match schema aliases
|
|
60
|
+
df.columns = df.columns.str.replace('/', '.', regex=False)
|
|
61
|
+
|
|
62
|
+
# A lot of fields from Bob are returned with only ID's. Those fields should be mapped to names. Therefore, we need to get the mapping from the named-lists endpoint.
|
|
63
|
+
resp_named_lists = self.bob.session.get(url=f"{self.bob.base_url}company/named-lists", timeout=self.bob.timeout, headers=self.bob.headers)
|
|
64
|
+
named_lists = resp_named_lists.json()
|
|
65
|
+
# save json to file
|
|
66
|
+
# import json
|
|
67
|
+
# with open('named_lists.json', 'w') as f:
|
|
68
|
+
# json.dump(named_lists, f, indent=4)
|
|
69
|
+
|
|
70
|
+
# Transform named_lists to create id-to-value mappings for each field
|
|
71
|
+
named_lists = {key.split('.')[-1]: {item['id']: item['value'] for item in value['values']} for key, value in named_lists.items()}
|
|
72
|
+
|
|
73
|
+
deviating_named_list_cols_mapping = {
|
|
74
|
+
'payroll.employment.type': 'payrollEmploymentType',
|
|
75
|
+
'home.familyStatus': 'familystatus',
|
|
76
|
+
'personal.nationality': 'nationalities',
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for field in df.columns:
|
|
80
|
+
# Fields in the response and in the named-list does have different building blocks (e.g. people.payroll.entitlement. or people.entitlement.). But they both end with the same last block
|
|
81
|
+
field_df = field.split('.')[-1].split('work_')[-1]
|
|
82
|
+
|
|
83
|
+
# Check if this field has a deviating mapping
|
|
84
|
+
named_list_key = deviating_named_list_cols_mapping.get(field, field_df)
|
|
85
|
+
|
|
86
|
+
if named_list_key in named_lists.keys() and named_list_key not in ['site']:
|
|
87
|
+
mapping = named_lists[named_list_key]
|
|
88
|
+
df[field] = df[field].apply(
|
|
89
|
+
lambda v: [mapping.get(x, x) for x in v] if isinstance(v, list) else mapping.get(v, v)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if schema_custom_fields is not None:
|
|
93
|
+
valid_people, invalid_people_custom = Functions.validate_data(df=df, schema=schema_custom_fields, debug=True)
|
|
94
|
+
else:
|
|
95
|
+
valid_people = df
|
|
96
|
+
invalid_people_custom = pd.DataFrame()
|
|
97
|
+
|
|
98
|
+
valid_people, invalid_people = Functions.validate_data(df=valid_people, schema=PeopleSchema, debug=True)
|
|
99
|
+
|
|
100
|
+
return valid_people, pd.concat([invalid_people, invalid_people_custom])
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import requests
|
|
3
|
+
from typing import Optional, List
|
|
3
4
|
from brynq_sdk_functions import Functions
|
|
4
5
|
from .schemas.salary import SalarySchema, SalaryCreateSchema
|
|
5
6
|
|
|
@@ -9,10 +10,16 @@ class Salaries:
|
|
|
9
10
|
self.bob = bob
|
|
10
11
|
self.schema = SalarySchema
|
|
11
12
|
|
|
12
|
-
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
13
|
+
def get(self, employee_ids: Optional[List[str]] = None) -> tuple[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
|
+
|
|
13
20
|
request = requests.Request(method='GET',
|
|
14
21
|
url=f"{self.bob.base_url}bulk/people/salaries",
|
|
15
|
-
params=
|
|
22
|
+
params=params)
|
|
16
23
|
data = self.bob.get_paginated_result(request)
|
|
17
24
|
df = pd.json_normalize(
|
|
18
25
|
data,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pandera as pa
|
|
2
|
+
from typing import Optional
|
|
2
3
|
from pandera.typing import Series, String
|
|
3
4
|
import pandas as pd
|
|
4
5
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
@@ -6,19 +7,19 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
|
6
7
|
|
|
7
8
|
class BankSchema(BrynQPanderaDataFrameModel):
|
|
8
9
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Bank ID", alias="id")
|
|
9
|
-
employee_id: Series[
|
|
10
|
-
amount: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Amount", alias="amount")
|
|
11
|
-
allocation: Series[String] = pa.Field(coerce=True, nullable=True, description="Allocation", alias="allocation")
|
|
12
|
-
branch_address: Series[String] = pa.Field(coerce=True, nullable=True, description="Branch Address", alias="branchAddress")
|
|
10
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employee_id")
|
|
11
|
+
amount: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, description="Amount", alias="amount")
|
|
12
|
+
allocation: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Allocation", alias="allocation")
|
|
13
|
+
branch_address: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Branch Address", alias="branchAddress")
|
|
13
14
|
bank_name: Series[String] = pa.Field(coerce=True, nullable=True, description="Bank Name", alias="bankName")
|
|
14
15
|
account_number: Series[String] = pa.Field(coerce=True, nullable=True, description="Account Number", alias="accountNumber")
|
|
15
|
-
routing_number: Series[String] = pa.Field(coerce=True, nullable=True, description="Routing Number", alias="routingNumber")
|
|
16
|
+
routing_number: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Routing Number", alias="routingNumber")
|
|
16
17
|
bank_account_type: Series[String] = pa.Field(coerce=True, nullable=True, description="Bank Account Type", alias="bankAccountType")
|
|
17
|
-
bic_or_swift: Series[String] = pa.Field(coerce=True, nullable=True, description="BIC or SWIFT", alias="bicOrSwift")
|
|
18
|
+
bic_or_swift: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="BIC or SWIFT", alias="bicOrSwift")
|
|
18
19
|
changed_by: Series[String] = pa.Field(coerce=True, nullable=True, description="Changed By", alias="changedBy")
|
|
19
20
|
iban: Series[String] = pa.Field(coerce=True, description="IBAN", alias="iban")
|
|
20
21
|
account_nickname: Series[String] = pa.Field(coerce=True, nullable=True, description="Account Nickname", alias="accountNickname")
|
|
21
|
-
use_for_bonus: Series[pd.BooleanDtype] = pa.Field(coerce=True, nullable=True, description="Use for Bonus", alias="useForBonus")
|
|
22
|
+
use_for_bonus: Optional[Series[pd.BooleanDtype]] = pa.Field(coerce=True, nullable=True, description="Use for Bonus", alias="useForBonus")
|
|
22
23
|
|
|
23
24
|
class Config:
|
|
24
25
|
coerce = True
|