brynq-sdk-vplan 1.0.0__tar.gz → 1.2.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.
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/PKG-INFO +1 -1
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/__init__.py +44 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/activity.py +132 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/get_data.py +86 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/item.py +141 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/leave.py +110 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/order.py +166 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/project.py +129 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/resource.py +142 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/time_tracking.py +144 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan/user.py +141 -0
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/brynq_sdk_vplan.egg-info/PKG-INFO +1 -1
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan.egg-info/SOURCES.txt +17 -0
- brynq_sdk_vplan-1.2.0/brynq_sdk_vplan.egg-info/top_level.txt +1 -0
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/setup.py +1 -1
- brynq_sdk_vplan-1.0.0/brynq_sdk_vplan.egg-info/SOURCES.txt +0 -7
- brynq_sdk_vplan-1.0.0/brynq_sdk_vplan.egg-info/top_level.txt +0 -1
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/brynq_sdk_vplan.egg-info/dependency_links.txt +0 -0
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/brynq_sdk_vplan.egg-info/not-zip-safe +0 -0
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/brynq_sdk_vplan.egg-info/requires.txt +0 -0
- {brynq_sdk_vplan-1.0.0 → brynq_sdk_vplan-1.2.0}/setup.cfg +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from brynq_sdk_brynq import BrynQ
|
|
2
|
+
from typing import List, Union
|
|
3
|
+
from .get_data import GetData
|
|
4
|
+
from .activity import Activity
|
|
5
|
+
from .item import Item
|
|
6
|
+
from .order import Order
|
|
7
|
+
from .project import Project
|
|
8
|
+
from .resource import Resource
|
|
9
|
+
from .time_tracking import TimeTracking
|
|
10
|
+
from .user import User
|
|
11
|
+
from .leave import Leave
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class VPlan(BrynQ):
|
|
15
|
+
def __init__(self, label: Union[str, List], debug: bool = False):
|
|
16
|
+
"""
|
|
17
|
+
A class to fetch data from the vPlan API. See https://developer.vplan.com/documentation/#tag/General/ for more information
|
|
18
|
+
"""
|
|
19
|
+
super().__init__()
|
|
20
|
+
self.headers = self._get_credentials(label)
|
|
21
|
+
self.post_headers = {**self.headers, 'Content-Type': 'application/json'}
|
|
22
|
+
self.base_url = 'https://api.vplan.com/v1/'
|
|
23
|
+
self.get = GetData(self)
|
|
24
|
+
self.activity = Activity(self)
|
|
25
|
+
self.item = Item(self)
|
|
26
|
+
self.order = Order(self)
|
|
27
|
+
self.project = Project(self)
|
|
28
|
+
self.resource = Resource(self)
|
|
29
|
+
self.time_tracking = TimeTracking(self)
|
|
30
|
+
self.user = User(self)
|
|
31
|
+
self.leave = Leave(self)
|
|
32
|
+
|
|
33
|
+
def _get_credentials(self, label) -> dict:
|
|
34
|
+
"""
|
|
35
|
+
Retrieve API key and env from the system credentials.
|
|
36
|
+
Args: label (Union[str, List]): The label or list of labels to get the credentials.
|
|
37
|
+
Returns: str: The authorization headers
|
|
38
|
+
"""
|
|
39
|
+
credentials = self.get_system_credential(system='vplan', label=label)
|
|
40
|
+
headers = {
|
|
41
|
+
'X-Api-Key': credentials['X-Api-Key'],
|
|
42
|
+
'X-Api-Env': credentials['X-Api-Env']
|
|
43
|
+
}
|
|
44
|
+
return headers
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Union, List
|
|
3
|
+
import warnings
|
|
4
|
+
import json
|
|
5
|
+
from .get_data import GetData
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Activity:
|
|
9
|
+
def __init__(self, vplan):
|
|
10
|
+
"""
|
|
11
|
+
Initialize the GetData class.
|
|
12
|
+
Args: vplan: contains the vplan object with the headers and base_url
|
|
13
|
+
"""
|
|
14
|
+
self.vplan = vplan
|
|
15
|
+
self.get_data = GetData(vplan)
|
|
16
|
+
|
|
17
|
+
def get_activity_list(self, filter: str = None, show: str = None, hide: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Get all the activitys from vPlan: https://developer.vplan.com/documentation/#tag/activity/paths/~1activity/get
|
|
20
|
+
Args: filter (str, optional): On the list endpoints it is possible to filter the result set given. To apply a filter use the filter query parameter with the format: field:operator:value
|
|
21
|
+
Example: ?filter=created_at:gt:2020-09-26,and,(id:not:starts_with:0000,or,id:contains:FFFF)
|
|
22
|
+
|
|
23
|
+
Colon : is the separator between the field, operator(s) and value.
|
|
24
|
+
Comma , can be used to combine filter statements by using ,and, or ,or,.
|
|
25
|
+
Braces (...) can be used to group filter statements.
|
|
26
|
+
|
|
27
|
+
The following operators are supported
|
|
28
|
+
|
|
29
|
+
operator description
|
|
30
|
+
eq equal to the given value
|
|
31
|
+
gt greater than the given value
|
|
32
|
+
gte greater than or equal to the given value
|
|
33
|
+
lt lesser than the given value
|
|
34
|
+
lte lesser than or equal to the given value
|
|
35
|
+
not negation of the operator that follows it
|
|
36
|
+
contains has occurrence of the given value
|
|
37
|
+
starts_with starts with the given value
|
|
38
|
+
end_with ends with the given value
|
|
39
|
+
|
|
40
|
+
warning: Currently the comma , and colon : are not supported within the filter value
|
|
41
|
+
|
|
42
|
+
show (str, optional): On the list endpoints it is possible to select the fields that should be returned. To apply a show use the show query parameter with the format: field1,field2,field3
|
|
43
|
+
hide (str, optional): On the list endpoints it is possible to hide the fields that should not be returned. To apply a hide use the hide query parameter with the format: field1,field2,field3
|
|
44
|
+
|
|
45
|
+
Returns: pd.DataFrame: The fetched data as a pandas DataFrame.
|
|
46
|
+
"""
|
|
47
|
+
df = self.get_data.get_data(endpoint='activity', filter=filter, show=show, hide=hide)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def post_activity(self, data: dict) -> requests.Response:
|
|
51
|
+
"""
|
|
52
|
+
Create a new activity in vPlan: https://developer.vplan.com/documentation/#tag/activity/paths/~1activity/post
|
|
53
|
+
|
|
54
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
55
|
+
to the vPlan API with the provided data.
|
|
56
|
+
|
|
57
|
+
Args: endpoint (str): The name of the endpoint to create a new activity in.
|
|
58
|
+
data (dict): The data to create the new activity with.
|
|
59
|
+
|
|
60
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
61
|
+
"""
|
|
62
|
+
required_fields = ['code', 'description']
|
|
63
|
+
allowed_fields = ['resource_type', 'default_duration', 'external_ref', 'archive']
|
|
64
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
65
|
+
|
|
66
|
+
url = f"{self.vplan.base_url}activity"
|
|
67
|
+
|
|
68
|
+
base_body = {
|
|
69
|
+
"code": data['code'],
|
|
70
|
+
"description": data['description']
|
|
71
|
+
}
|
|
72
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
73
|
+
base_body.update({"resource_type": data['resource_type']}) if 'resource_type' in data else base_body
|
|
74
|
+
base_body.update({"default_duration": data['default_duration']}) if 'default_duration' in data else base_body
|
|
75
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
76
|
+
base_body.update({"archive": data['archive']}) if 'archive' in data else base_body
|
|
77
|
+
|
|
78
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=base_body)
|
|
79
|
+
return response
|
|
80
|
+
|
|
81
|
+
def update_activity(self, activity_id: str, data: dict) -> requests.Response:
|
|
82
|
+
"""
|
|
83
|
+
Update an existing activity in vPlan: https://developer.vplan.com/documentation/#tag/activity/paths/~1activity~1%7Bactivity_id%7D/put
|
|
84
|
+
|
|
85
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
86
|
+
to the vPlan API with the provided data.
|
|
87
|
+
|
|
88
|
+
Args: endpoint (str): The name of the endpoint to create a new activity in.
|
|
89
|
+
data (dict): The data to create the new activity with.
|
|
90
|
+
|
|
91
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
92
|
+
"""
|
|
93
|
+
required_fields = ['code', 'description']
|
|
94
|
+
allowed_fields = ['resource_type', 'default_duration', 'external_ref', 'archive']
|
|
95
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
96
|
+
|
|
97
|
+
url = f"{self.vplan.base_url}activity/{activity_id}"
|
|
98
|
+
|
|
99
|
+
base_body = {
|
|
100
|
+
"code": data['code'],
|
|
101
|
+
"description": data['description']
|
|
102
|
+
}
|
|
103
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
104
|
+
base_body.update({"resource_type": data['resource_type']}) if 'resource_type' in data else base_body
|
|
105
|
+
base_body.update({"default_duration": data['default_duration']}) if 'default_duration' in data else base_body
|
|
106
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
107
|
+
base_body.update({"archive": data['archive']}) if 'archive' in data else base_body
|
|
108
|
+
|
|
109
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, json=base_body)
|
|
110
|
+
return response
|
|
111
|
+
|
|
112
|
+
def delete_activity(self, activity_id):
|
|
113
|
+
"""
|
|
114
|
+
Delete an existing activity in vPlan: https://developer.vplan.com/documentation/#tag/activity/paths/~1activity~1%7Bactivity_id%7D/delete
|
|
115
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
116
|
+
"""
|
|
117
|
+
url = f"{self.vplan.base_url}activity/{activity_id}"
|
|
118
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers)
|
|
119
|
+
return response
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
123
|
+
if isinstance(data, dict):
|
|
124
|
+
data = data.keys()
|
|
125
|
+
|
|
126
|
+
for field in data:
|
|
127
|
+
if field not in allowed_fields and field not in required_fields:
|
|
128
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
129
|
+
|
|
130
|
+
for field in required_fields:
|
|
131
|
+
if field not in data:
|
|
132
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from typing import List, Any
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GetData:
|
|
7
|
+
def __init__(self, vplan):
|
|
8
|
+
"""
|
|
9
|
+
Initialize the GetData class.
|
|
10
|
+
Args: vplan: contains the vplan object with the headers and base_url
|
|
11
|
+
"""
|
|
12
|
+
self.vplan = vplan
|
|
13
|
+
|
|
14
|
+
def get_data(self, endpoint: str, limit: int = 1000, filter: str = None, with_array: str = None, show: str = None, hide: str = None, archived: bool = False) -> pd.DataFrame:
|
|
15
|
+
"""
|
|
16
|
+
Fetch data from a specified table from vPlan
|
|
17
|
+
|
|
18
|
+
This method constructs a request URL based on the table name and optional filter,
|
|
19
|
+
sends a request to the vPlan API, parses the JSON response, and converts it
|
|
20
|
+
to a pandas DataFrame. The DataFrame columns are cleaned to remove unnecessary
|
|
21
|
+
characters and duplicate columns are handled.
|
|
22
|
+
|
|
23
|
+
Args: endpoint (str): The name of the endpoint to fetch data from.
|
|
24
|
+
filter (str, optional): On the list endpoints it is possible to filter the result set given. To apply a filter use the filter query parameter with the format: field:operator:value
|
|
25
|
+
Example: ?filter=created_at:gt:2020-09-26,and,(id:not:starts_with:0000,or,id:contains:FFFF)
|
|
26
|
+
|
|
27
|
+
Colon : is the separator between the field, operator(s) and value.
|
|
28
|
+
Comma , can be used to combine filter statements by using ,and, or ,or,.
|
|
29
|
+
Braces (...) can be used to group filter statements.
|
|
30
|
+
|
|
31
|
+
The following operators are supported
|
|
32
|
+
|
|
33
|
+
operator description
|
|
34
|
+
eq equal to the given value
|
|
35
|
+
gt greater than the given value
|
|
36
|
+
gte greater than or equal to the given value
|
|
37
|
+
lt lesser than the given value
|
|
38
|
+
lte lesser than or equal to the given value
|
|
39
|
+
not negation of the operator that follows it
|
|
40
|
+
contains has occurrence of the given value
|
|
41
|
+
starts_with starts with the given value
|
|
42
|
+
end_with ends with the given value
|
|
43
|
+
|
|
44
|
+
warning: Currently the comma , and colon : are not supported within the filter value
|
|
45
|
+
|
|
46
|
+
show (str, optional): On the list endpoints it is possible to select the fields that should be returned. To apply a show use the show query parameter with the format: field1,field2,field3
|
|
47
|
+
hide (str, optional): On the list endpoints it is possible to hide the fields that should not be returned. To apply a hide use the hide query parameter with the format: field1,field2,field3
|
|
48
|
+
|
|
49
|
+
Returns: pd.DataFrame: The fetched data as a pandas DataFrame.
|
|
50
|
+
"""
|
|
51
|
+
# Initial URL with subscription-key
|
|
52
|
+
url = f"{self.vplan.base_url}{endpoint}?"
|
|
53
|
+
if limit:
|
|
54
|
+
url += f'limit={limit}&'
|
|
55
|
+
if filter:
|
|
56
|
+
url += f'filter={filter}&'
|
|
57
|
+
if with_array:
|
|
58
|
+
url += f'with={with_array}&'
|
|
59
|
+
if show:
|
|
60
|
+
url += f'show={show}&'
|
|
61
|
+
if hide:
|
|
62
|
+
url += f'hide={hide}&'
|
|
63
|
+
if archived:
|
|
64
|
+
url += f'archived={archived}&'
|
|
65
|
+
|
|
66
|
+
all_data = []
|
|
67
|
+
offset = 0
|
|
68
|
+
received = 0
|
|
69
|
+
while True:
|
|
70
|
+
final_url = f'{url}offset={offset}'
|
|
71
|
+
response = requests.get(url=final_url, headers=self.vplan.headers)
|
|
72
|
+
response.raise_for_status()
|
|
73
|
+
result = response.json()
|
|
74
|
+
data = result.get('data', result)
|
|
75
|
+
all_data.extend(data)
|
|
76
|
+
|
|
77
|
+
# Determine if we need to continue fetching data
|
|
78
|
+
count = result.get('count', 0)
|
|
79
|
+
received += len(data)
|
|
80
|
+
offset += limit
|
|
81
|
+
if received >= count:
|
|
82
|
+
break
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
df = pd.DataFrame(all_data)
|
|
86
|
+
return df
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Union, List
|
|
3
|
+
import warnings
|
|
4
|
+
import json
|
|
5
|
+
from .get_data import GetData
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Item:
|
|
9
|
+
def __init__(self, vplan):
|
|
10
|
+
"""
|
|
11
|
+
Initialize the GetData class.
|
|
12
|
+
Args: vplan: contains the vplan object with the headers and base_url
|
|
13
|
+
"""
|
|
14
|
+
self.vplan = vplan
|
|
15
|
+
self.get_data = GetData(vplan)
|
|
16
|
+
|
|
17
|
+
def get_item_list(self, filter: str = None, show: str = None, hide: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Get all the items from vPlan: https://developer.vplan.com/documentation/#tag/item/paths/~1item/get
|
|
20
|
+
Args: filter (str, optional): On the list endpoints it is possible to filter the result set given. To apply a filter use the filter query parameter with the format: field:operator:value
|
|
21
|
+
Example: ?filter=created_at:gt:2020-09-26,and,(id:not:starts_with:0000,or,id:contains:FFFF)
|
|
22
|
+
|
|
23
|
+
Colon : is the separator between the field, operator(s) and value.
|
|
24
|
+
Comma , can be used to combine filter statements by using ,and, or ,or,.
|
|
25
|
+
Braces (...) can be used to group filter statements.
|
|
26
|
+
|
|
27
|
+
The following operators are supported
|
|
28
|
+
|
|
29
|
+
operator description
|
|
30
|
+
eq equal to the given value
|
|
31
|
+
gt greater than the given value
|
|
32
|
+
gte greater than or equal to the given value
|
|
33
|
+
lt lesser than the given value
|
|
34
|
+
lte lesser than or equal to the given value
|
|
35
|
+
not negation of the operator that follows it
|
|
36
|
+
contains has occurrence of the given value
|
|
37
|
+
starts_with starts with the given value
|
|
38
|
+
end_with ends with the given value
|
|
39
|
+
|
|
40
|
+
warning: Currently the comma , and colon : are not supported within the filter value
|
|
41
|
+
|
|
42
|
+
show (str, optional): On the list endpoints it is possible to select the fields that should be returned. To apply a show use the show query parameter with the format: field1,field2,field3
|
|
43
|
+
hide (str, optional): On the list endpoints it is possible to hide the fields that should not be returned. To apply a hide use the hide query parameter with the format: field1,field2,field3
|
|
44
|
+
|
|
45
|
+
Returns: pd.DataFrame: The fetched data as a pandas DataFrame.
|
|
46
|
+
"""
|
|
47
|
+
df = self.get_data.get_data(endpoint='item', filter=filter, show=show, hide=hide)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def post_item(self, data: dict) -> requests.Response:
|
|
51
|
+
"""
|
|
52
|
+
Create a new item in vPlan: https://developer.vplan.com/documentation/#tag/item/paths/~1item/post
|
|
53
|
+
|
|
54
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
55
|
+
to the vPlan API with the provided data.
|
|
56
|
+
|
|
57
|
+
Args: endpoint (str): The name of the endpoint to create a new item in.
|
|
58
|
+
data (dict): The data to create the new item with.
|
|
59
|
+
|
|
60
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
61
|
+
"""
|
|
62
|
+
required_fields = ['code', 'description']
|
|
63
|
+
allowed_fields = ['stock_management', 'unit', 'type', 'location', 'note', 'external_ref']
|
|
64
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
65
|
+
|
|
66
|
+
url = f"{self.vplan.base_url}item"
|
|
67
|
+
|
|
68
|
+
base_body = {
|
|
69
|
+
"code": data['code'],
|
|
70
|
+
"description": data['description']
|
|
71
|
+
}
|
|
72
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
73
|
+
base_body.update({"code": data['code']}) if 'code' in data else base_body
|
|
74
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
75
|
+
base_body.update({"stock_management": data['stock_management']}) if 'stock_management' in data else base_body
|
|
76
|
+
base_body.update({"unit": data['unit']}) if 'unit' in data else base_body
|
|
77
|
+
base_body.update({"type": data['type']}) if 'type' in data else base_body
|
|
78
|
+
base_body.update({"location": data['location']}) if 'location' in data else base_body
|
|
79
|
+
base_body.update({"note": data['note']}) if 'note' in data else base_body
|
|
80
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
81
|
+
|
|
82
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=base_body)
|
|
83
|
+
return response
|
|
84
|
+
|
|
85
|
+
def update_item(self, item_id: str, data: dict) -> requests.Response:
|
|
86
|
+
"""
|
|
87
|
+
Update an existing item in vPlan: https://developer.vplan.com/documentation/#tag/item/paths/~1item~1%7Bitem_id%7D/put
|
|
88
|
+
|
|
89
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
90
|
+
to the vPlan API with the provided data.
|
|
91
|
+
|
|
92
|
+
Args: endpoint (str): The name of the endpoint to create a new item in.
|
|
93
|
+
data (dict): The data to create the new item with.
|
|
94
|
+
|
|
95
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
96
|
+
"""
|
|
97
|
+
required_fields = ['code', 'description']
|
|
98
|
+
allowed_fields = ['stock_management', 'unit', 'type', 'location', 'note', 'external_ref']
|
|
99
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
100
|
+
|
|
101
|
+
url = f"{self.vplan.base_url}item/{item_id}"
|
|
102
|
+
|
|
103
|
+
base_body = {
|
|
104
|
+
"code": data['code'],
|
|
105
|
+
"description": data['description']
|
|
106
|
+
}
|
|
107
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
108
|
+
base_body.update({"code": data['code']}) if 'code' in data else base_body
|
|
109
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
110
|
+
base_body.update({"stock_management": data['stock_management']}) if 'stock_management' in data else base_body
|
|
111
|
+
base_body.update({"unit": data['unit']}) if 'unit' in data else base_body
|
|
112
|
+
base_body.update({"type": data['type']}) if 'type' in data else base_body
|
|
113
|
+
base_body.update({"location": data['location']}) if 'location' in data else base_body
|
|
114
|
+
base_body.update({"note": data['note']}) if 'note' in data else base_body
|
|
115
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
116
|
+
|
|
117
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, json=base_body)
|
|
118
|
+
return response
|
|
119
|
+
|
|
120
|
+
def delete_item(self, item_id):
|
|
121
|
+
"""
|
|
122
|
+
Delete an existing item in vPlan: https://developer.vplan.com/documentation/#tag/Item/paths/~1item~1%7Bitem_id%7D/delete
|
|
123
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
124
|
+
"""
|
|
125
|
+
url = f"{self.vplan.base_url}item/{item_id}"
|
|
126
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers)
|
|
127
|
+
return response
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
132
|
+
if isinstance(data, dict):
|
|
133
|
+
data = data.keys()
|
|
134
|
+
|
|
135
|
+
for field in data:
|
|
136
|
+
if field not in allowed_fields and field not in required_fields:
|
|
137
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
138
|
+
|
|
139
|
+
for field in required_fields:
|
|
140
|
+
if field not in data:
|
|
141
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Union, List, Any
|
|
3
|
+
import warnings
|
|
4
|
+
import json
|
|
5
|
+
from .get_data import GetData
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Leave:
|
|
9
|
+
def __init__(self, vplan):
|
|
10
|
+
"""
|
|
11
|
+
Initialize the GetData class.
|
|
12
|
+
Args: vplan: contains the vplan object with the headers and base_url
|
|
13
|
+
"""
|
|
14
|
+
self.vplan = vplan
|
|
15
|
+
self.get_data = GetData(vplan)
|
|
16
|
+
|
|
17
|
+
def get_leave(self, resource_id: str) -> requests.Response:
|
|
18
|
+
"""
|
|
19
|
+
There is no documentation for this method available
|
|
20
|
+
|
|
21
|
+
This method constructs a request URL based on the endpoint and sends a GET request
|
|
22
|
+
to the vPlan API.
|
|
23
|
+
|
|
24
|
+
Args: resource_id (str): The id of the resource to get the leave from
|
|
25
|
+
|
|
26
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
27
|
+
"""
|
|
28
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation"
|
|
29
|
+
response = requests.request('GET', url, headers=self.vplan.headers)
|
|
30
|
+
return response
|
|
31
|
+
|
|
32
|
+
def post_leave(self, resource_id: str, data: dict) -> requests.Response:
|
|
33
|
+
"""
|
|
34
|
+
There is no documentation for this method available
|
|
35
|
+
|
|
36
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
37
|
+
to the vPlan API with the provided data.
|
|
38
|
+
|
|
39
|
+
Args: resource_id (str): The resource id of the employee to add the leave to
|
|
40
|
+
data (dict): The data to create the new order with.
|
|
41
|
+
|
|
42
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
43
|
+
"""
|
|
44
|
+
required_fields = ['type', 'time', 'description', 'start_date', 'end_date']
|
|
45
|
+
allowed_fields = []
|
|
46
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
47
|
+
|
|
48
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation"
|
|
49
|
+
base_body = json.dumps({
|
|
50
|
+
"type": data['type'],
|
|
51
|
+
"time": data['time'],
|
|
52
|
+
"description": data['description'],
|
|
53
|
+
"start_date": data['start_date'],
|
|
54
|
+
"end_date": data['end_date']
|
|
55
|
+
})
|
|
56
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=base_body)
|
|
57
|
+
return response
|
|
58
|
+
|
|
59
|
+
def update_leave(self, resource_id: str, leave_id: str, data: dict) -> requests.Response:
|
|
60
|
+
"""
|
|
61
|
+
There is no documentation for this method available
|
|
62
|
+
|
|
63
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
64
|
+
to the vPlan API with the provided data.
|
|
65
|
+
|
|
66
|
+
Args: resource_id (str): The resource id of the employee to add the leave to
|
|
67
|
+
leave_id (str): The id of the leave to update
|
|
68
|
+
data (dict): The data to create the new order with.
|
|
69
|
+
|
|
70
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
71
|
+
"""
|
|
72
|
+
required_fields = ['type', 'time', 'description', 'start_date', 'end_date']
|
|
73
|
+
allowed_fields = []
|
|
74
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
75
|
+
|
|
76
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation/{leave_id}"
|
|
77
|
+
base_body = json.dumps({
|
|
78
|
+
"type": data['type'],
|
|
79
|
+
"time": data['time'],
|
|
80
|
+
"description": data['description'],
|
|
81
|
+
"start_date": data['start_date'],
|
|
82
|
+
"end_date": data['end_date']
|
|
83
|
+
})
|
|
84
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, json=base_body)
|
|
85
|
+
return response
|
|
86
|
+
|
|
87
|
+
def delete_leave(self, resource_id: str, leave_id: str):
|
|
88
|
+
"""
|
|
89
|
+
There is no documentation for this method available
|
|
90
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
91
|
+
:param resource_id: The resource id of the employee to delete the the leave to
|
|
92
|
+
:param leave_id: The id of the leave to delete
|
|
93
|
+
"""
|
|
94
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation/{leave_id}"
|
|
95
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers)
|
|
96
|
+
return response
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
101
|
+
if isinstance(data, dict):
|
|
102
|
+
data = data.keys()
|
|
103
|
+
|
|
104
|
+
for field in data:
|
|
105
|
+
if field not in allowed_fields and field not in required_fields:
|
|
106
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
107
|
+
|
|
108
|
+
for field in required_fields:
|
|
109
|
+
if field not in data:
|
|
110
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|